1  /*
2   *  Copyright 2018 Google, Inc
3   *
4   *  Licensed under the Apache License, Version 2.0 (the "License");
5   *  you may not use this file except in compliance with the License.
6   *  You may obtain a copy of the License at
7   *
8   *      http://www.apache.org/licenses/LICENSE-2.0
9   *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  #ifndef _LIBDM_DM_H_
18  #define _LIBDM_DM_H_
19  
20  #include <dirent.h>
21  #include <fcntl.h>
22  #include <linux/dm-ioctl.h>
23  #include <linux/kdev_t.h>
24  #include <linux/types.h>
25  #include <stdint.h>
26  #include <sys/sysmacros.h>
27  #include <sys/types.h>
28  #include <unistd.h>
29  
30  #include <chrono>
31  #include <map>
32  #include <memory>
33  #include <optional>
34  #include <string>
35  #include <utility>
36  #include <vector>
37  
38  #include "dm_table.h"
39  
40  // The minimum expected device mapper major.minor version
41  #define DM_VERSION0 (4)
42  #define DM_VERSION1 (0)
43  #define DM_VERSION2 (0)
44  
45  #define DM_ALIGN_MASK (7)
46  #define DM_ALIGN(x) (((x) + DM_ALIGN_MASK) & ~DM_ALIGN_MASK)
47  
48  namespace android {
49  namespace dm {
50  
51  enum class DmDeviceState { INVALID, SUSPENDED, ACTIVE };
52  
53  static constexpr uint64_t kSectorSize = 512;
54  
55  // Returns `path` without /dev/block prefix if and only if `path` starts with
56  // that prefix.
57  std::optional<std::string> ExtractBlockDeviceName(const std::string& path);
58  
59  // This interface is for testing purposes. See DeviceMapper proper for what these methods do.
60  class IDeviceMapper {
61    public:
~IDeviceMapper()62      virtual ~IDeviceMapper() {}
63  
64      struct TargetInfo {
65          struct dm_target_spec spec;
66          std::string data;
TargetInfoTargetInfo67          TargetInfo() {}
TargetInfoTargetInfo68          TargetInfo(const struct dm_target_spec& spec, const std::string& data)
69              : spec(spec), data(data) {}
70  
71          bool IsOverflowSnapshot() const;
72      };
73  
74      virtual bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
75                                const std::chrono::milliseconds& timeout_ms) = 0;
76      virtual DmDeviceState GetState(const std::string& name) const = 0;
77      virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) = 0;
78      virtual bool LoadTable(const std::string& name, const DmTable& table) = 0;
79      virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) = 0;
80      virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) = 0;
81      virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) = 0;
82      virtual bool GetDeviceString(const std::string& name, std::string* dev) = 0;
83      virtual bool DeleteDeviceIfExists(const std::string& name) = 0;
84  };
85  
86  class DeviceMapper final : public IDeviceMapper {
87    public:
88      class DmBlockDevice final {
89        public:
90          // only allow creating this with dm_name_list
91          DmBlockDevice() = delete;
92  
DmBlockDevice(struct dm_name_list * d)93          explicit DmBlockDevice(struct dm_name_list* d) : name_(d->name), dev_(d->dev){};
94  
95          // Returs device mapper name associated with the block device
name()96          const std::string& name() const { return name_; }
97  
98          // Return major number for the block device
Major()99          uint32_t Major() const { return major(dev_); }
100  
101          // Return minor number for the block device
Minor()102          uint32_t Minor() const { return minor(dev_); }
103          ~DmBlockDevice() = default;
104  
105        private:
106          std::string name_;
107          uint64_t dev_;
108      };
109  
110      class Info {
111          uint32_t flags_;
112  
113        public:
Info(uint32_t flags)114          explicit Info(uint32_t flags) : flags_(flags) {}
115  
IsActiveTablePresent()116          bool IsActiveTablePresent() const { return flags_ & DM_ACTIVE_PRESENT_FLAG; }
IsBufferFull()117          bool IsBufferFull() const { return flags_ & DM_BUFFER_FULL_FLAG; }
IsInactiveTablePresent()118          bool IsInactiveTablePresent() const { return flags_ & DM_INACTIVE_PRESENT_FLAG; }
IsReadOnly()119          bool IsReadOnly() const { return flags_ & DM_READONLY_FLAG; }
IsSuspended()120          bool IsSuspended() const { return !IsActiveTablePresent() || (flags_ & DM_SUSPEND_FLAG); }
121      };
122  
123      // Removes a device mapper device with the given name.
124      // Returns 'true' on success, false otherwise.
125      bool DeleteDevice(const std::string& name);
126      bool DeleteDeviceIfExists(const std::string& name) override;
127      // Removes a device mapper device with the given name and waits for |timeout_ms| milliseconds
128      // for the corresponding block device to be deleted.
129      bool DeleteDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
130      bool DeleteDeviceIfExists(const std::string& name, const std::chrono::milliseconds& timeout_ms);
131  
132      // Enqueues a deletion of device mapper device with the given name once last reference is
133      // closed.
134      // Returns 'true' on success, false otherwise.
135      bool DeleteDeviceDeferred(const std::string& name);
136      bool DeleteDeviceIfExistsDeferred(const std::string& name);
137  
138      // Fetches and returns the complete state of the underlying device mapper
139      // device with given name.
140      std::optional<Info> GetDetailedInfo(const std::string& name) const;
141  
142      // Returns the current state of the underlying device mapper device
143      // with given name.
144      // One of INVALID, SUSPENDED or ACTIVE.
145      DmDeviceState GetState(const std::string& name) const override;
146  
147      // Puts the given device to the specified status, which must be either:
148      // - SUSPENDED: suspend the device, or
149      // - ACTIVE: resumes the device.
150      bool ChangeState(const std::string& name, DmDeviceState state);
151  
152      // Creates empty device.
153      // This supports a use case when a caller doesn't need a device straight away, but instead
154      // asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd
155      // to create user space paths.
156      // Callers are expected to then activate their device by calling LoadTableAndActivate function.
157      // To avoid race conditions, callers must still synchronize with ueventd by calling
158      // WaitForDevice function.
159      bool CreateEmptyDevice(const std::string& name);
160  
161      // Waits for device paths to be created in the user space.
162      bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
163                         std::string* path);
164  
165      // Creates a device, loads the given table, and activates it. If the device
166      // is not able to be activated, it is destroyed, and false is returned.
167      // After creation, |path| contains the result of calling
168      // GetDmDevicePathByName, and the path is guaranteed to exist. If after
169      // |timeout_ms| the path is not available, the device will be deleted and
170      // this function will return false.
171      //
172      // This variant must be used when depending on the device path. The
173      // following manual sequence should not be used:
174      //
175      //   1. CreateDevice(name, table)
176      //   2. GetDmDevicePathByName(name, &path)
177      //   3. fs_mgr::WaitForFile(path, <timeout>)
178      //
179      // This sequence has a race condition where, if another process deletes a
180      // device, CreateDevice may acquire the same path. When this happens, the
181      // WaitForFile() may early-return since ueventd has not yet processed all
182      // of the outstanding udev events. The caller may unexpectedly get an
183      // ENOENT on a system call using the affected path.
184      //
185      // If |timeout_ms| is 0ms, then this function will return true whether or
186      // not |path| is available. It is the caller's responsibility to ensure
187      // there are no races.
188      bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
189                        const std::chrono::milliseconds& timeout_ms) override;
190  
191      // Create a device and activate the given table, without waiting to acquire
192      // a valid path. If the caller will use GetDmDevicePathByName(), it should
193      // use the timeout variant above.
194      bool CreateDevice(const std::string& name, const DmTable& table);
195  
196      // Loads the device mapper table from parameter into the underlying device
197      // mapper device with given name and activate / resumes the device in the
198      // process. A device with the given name must already exist.
199      //
200      // Returns 'true' on success, false otherwise.
201      bool LoadTableAndActivate(const std::string& name, const DmTable& table) override;
202  
203      // Same as LoadTableAndActivate, but there is no resume step. This puts the
204      // new table in the inactive slot.
205      //
206      // Returns 'true' on success, false otherwise.
207      bool LoadTable(const std::string& name, const DmTable& table) override;
208  
209      // Returns true if a list of available device mapper targets registered in the kernel was
210      // successfully read and stored in 'targets'. Returns 'false' otherwise.
211      bool GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets);
212  
213      // Finds a target by name and returns its information if found. |info| may
214      // be null to check for the existence of a target.
215      bool GetTargetByName(const std::string& name, DmTargetTypeInfo* info);
216  
217      // Return 'true' if it can successfully read the list of device mapper block devices
218      // currently created. 'devices' will be empty if the kernel interactions
219      // were successful and there are no block devices at the moment. Returns
220      // 'false' in case of any failure along the way.
221      bool GetAvailableDevices(std::vector<DmBlockDevice>* devices);
222  
223      // Returns the path to the device mapper device node in '/dev' corresponding to
224      // 'name'. If the device does not exist, false is returned, and the path
225      // parameter is not set.
226      //
227      // This returns a path in the format "/dev/block/dm-N" that can be easily
228      // re-used with sysfs.
229      //
230      // WaitForFile() should not be used in conjunction with this call, since it
231      // could race with ueventd.
232      bool GetDmDevicePathByName(const std::string& name, std::string* path);
233  
234      // Returns the device mapper UUID for a given name.  If the device does not
235      // exist, false is returned, and the path parameter is not set.
236      //
237      // WaitForFile() should not be used in conjunction with this call, since it
238      // could race with ueventd.
239      bool GetDmDeviceUuidByName(const std::string& name, std::string* path);
240  
241      // Returns a device's unique path as generated by ueventd. This will return
242      // true as long as the device has been created, even if ueventd has not
243      // processed it yet.
244      //
245      // The formatting of this path is /dev/block/mapper/by-uuid/<uuid>.
246      bool GetDeviceUniquePath(const std::string& name, std::string* path);
247  
248      // Returns the dev_t for the named device-mapper node.
249      bool GetDeviceNumber(const std::string& name, dev_t* dev);
250  
251      // Returns a major:minor string for the named device-mapper node, that can
252      // be used as inputs to DmTargets that take a block device.
253      bool GetDeviceString(const std::string& name, std::string* dev) override;
254  
255      // The only way to create a DeviceMapper object.
256      static DeviceMapper& Instance();
257  
~DeviceMapper()258      ~DeviceMapper() {
259          if (fd_ != -1) {
260              ::close(fd_);
261          }
262      }
263  
264      // Query the status of a table, given a device name. The output vector will
265      // contain one TargetInfo for each target in the table. If the device does
266      // not exist, or there were too many targets, the call will fail and return
267      // false.
268      bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) override;
269  
270      // Identical to GetTableStatus, except also retrives the active table for the device
271      // mapper device from the kernel.
272      bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) override;
273  
274      static std::string GetTargetType(const struct dm_target_spec& spec);
275  
276      // Returns true if given path is a path to a dm block device.
277      bool IsDmBlockDevice(const std::string& path);
278  
279      // Returns name of a dm-device with the given path, or std::nulloptr if given path is not a
280      // dm-device.
281      std::optional<std::string> GetDmDeviceNameByPath(const std::string& path);
282  
283      // Returns a parent block device of a dm device with the given path, or std::nullopt if:
284      //  * Given path doesn't correspond to a dm device.
285      //  * A dm device is based on top of more than one block devices.
286      //  * A failure occurred.
287      std::optional<std::string> GetParentBlockDeviceByPath(const std::string& path);
288  
289      // Iterate the content over "/sys/block/dm-x/dm/name" and find
290      // all the dm-wrapped block devices.
291      //
292      // Returns mapping <partition-name, /dev/block/dm-x>
293      std::map<std::string, std::string> FindDmPartitions();
294  
295      // Create a placeholder device. This is useful for ensuring that a uevent is in the pipeline,
296      // to reduce the amount of time a future WaitForDevice will block. On kernels < 5.15, this
297      // simply calls CreateEmptyDevice. On 5.15 and higher, it also loads (but does not activate)
298      // a placeholder table containing dm-error.
299      bool CreatePlaceholderDevice(const std::string& name);
300  
301      bool GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid);
302  
303    private:
304      // Maximum possible device mapper targets registered in the kernel.
305      // This is only used to read the list of targets from kernel so we allocate
306      // a finite amount of memory. This limit is in no way enforced by the kernel.
307      static constexpr uint32_t kMaxPossibleDmTargets = 256;
308  
309      // Maximum possible device mapper created block devices. Note that this is restricted by
310      // the minor numbers (that used to be 8 bits) that can be range from 0 to 2^20-1 in newer
311      // kernels. In Android systems however, we never expect these to grow beyond the artificial
312      // limit we are imposing here of 256.
313      static constexpr uint32_t kMaxPossibleDmDevices = 256;
314  
315      bool CreateDevice(const std::string& name, const std::string& uuid = {});
316      bool GetTable(const std::string& name, uint32_t flags, std::vector<TargetInfo>* table);
317      void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const;
318  
319      DeviceMapper();
320  
321      int fd_;
322      // Non-copyable & Non-movable
323      DeviceMapper(const DeviceMapper&) = delete;
324      DeviceMapper& operator=(const DeviceMapper&) = delete;
325      DeviceMapper& operator=(DeviceMapper&&) = delete;
326      DeviceMapper(DeviceMapper&&) = delete;
327  };
328  
329  }  // namespace dm
330  }  // namespace android
331  
332  #endif /* _LIBDM_DM_H_ */
333