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