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