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