• 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 <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 `path` starts with that prefix.
56 // Or, if `path` is a symlink, do the same with its real path.
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 GetTableStatusIma(const std::string& name, std::vector<TargetInfo>* table) = 0;
82     virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) = 0;
83     virtual bool GetDeviceString(const std::string& name, std::string* dev) = 0;
84     virtual bool DeleteDeviceIfExists(const std::string& name) = 0;
85 };
86 
87 class DeviceMapper final : public IDeviceMapper {
88   public:
89     class DmBlockDevice final {
90       public:
91         // only allow creating this with dm_name_list
92         DmBlockDevice() = delete;
93 
DmBlockDevice(struct dm_name_list * d)94         explicit DmBlockDevice(struct dm_name_list* d) : name_(d->name), dev_(d->dev){};
95 
96         // Returs device mapper name associated with the block device
name()97         const std::string& name() const { return name_; }
98 
99         // Return major number for the block device
Major()100         uint32_t Major() const { return major(dev_); }
101 
102         // Return minor number for the block device
Minor()103         uint32_t Minor() const { return minor(dev_); }
104         ~DmBlockDevice() = default;
105 
106       private:
107         std::string name_;
108         uint64_t dev_;
109     };
110 
111     class Info {
112         uint32_t flags_;
113 
114       public:
Info(uint32_t flags)115         explicit Info(uint32_t flags) : flags_(flags) {}
116 
IsActiveTablePresent()117         bool IsActiveTablePresent() const { return flags_ & DM_ACTIVE_PRESENT_FLAG; }
IsBufferFull()118         bool IsBufferFull() const { return flags_ & DM_BUFFER_FULL_FLAG; }
IsInactiveTablePresent()119         bool IsInactiveTablePresent() const { return flags_ & DM_INACTIVE_PRESENT_FLAG; }
IsReadOnly()120         bool IsReadOnly() const { return flags_ & DM_READONLY_FLAG; }
IsSuspended()121         bool IsSuspended() const { return !IsActiveTablePresent() || (flags_ & DM_SUSPEND_FLAG); }
122     };
123 
124     // Removes a device mapper device with the given name.
125     // Returns 'true' on success, false otherwise.
126     bool DeleteDevice(const std::string& name);
127     bool DeleteDeviceIfExists(const std::string& name) override;
128     // Removes a device mapper device with the given name and waits for |timeout_ms| milliseconds
129     // for the corresponding block device to be deleted.
130     bool DeleteDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
131     bool DeleteDeviceIfExists(const std::string& name, const std::chrono::milliseconds& timeout_ms);
132 
133     // Enqueues a deletion of device mapper device with the given name once last reference is
134     // closed.
135     // Returns 'true' on success, false otherwise.
136     bool DeleteDeviceDeferred(const std::string& name);
137     bool DeleteDeviceIfExistsDeferred(const std::string& name);
138 
139     // Fetches and returns the complete state of the underlying device mapper
140     // device with given name.
141     std::optional<Info> GetDetailedInfo(const std::string& name) const;
142 
143     // Returns the current state of the underlying device mapper device
144     // with given name.
145     // One of INVALID, SUSPENDED or ACTIVE.
146     DmDeviceState GetState(const std::string& name) const override;
147 
148     // Puts the given device to the specified status, which must be either:
149     // - SUSPENDED: suspend the device, or
150     // - ACTIVE: resumes the device.
151     bool ChangeState(const std::string& name, DmDeviceState state);
152 
153     // Creates empty device.
154     // This supports a use case when a caller doesn't need a device straight away, but instead
155     // asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd
156     // to create user space paths.
157     // Callers are expected to then activate their device by calling LoadTableAndActivate function.
158     // To avoid race conditions, callers must still synchronize with ueventd by calling
159     // WaitForDevice function.
160     bool CreateEmptyDevice(const std::string& name);
161 
162     // Waits for device paths to be created in the user space.
163     bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
164                        std::string* path);
165 
166     // Creates a device, loads the given table, and activates it. If the device
167     // is not able to be activated, it is destroyed, and false is returned.
168     // After creation, |path| contains the result of calling
169     // GetDmDevicePathByName, and the path is guaranteed to exist. If after
170     // |timeout_ms| the path is not available, the device will be deleted and
171     // this function will return false.
172     //
173     // This variant must be used when depending on the device path. The
174     // following manual sequence should not be used:
175     //
176     //   1. CreateDevice(name, table)
177     //   2. GetDmDevicePathByName(name, &path)
178     //   3. fs_mgr::WaitForFile(path, <timeout>)
179     //
180     // This sequence has a race condition where, if another process deletes a
181     // device, CreateDevice may acquire the same path. When this happens, the
182     // WaitForFile() may early-return since ueventd has not yet processed all
183     // of the outstanding udev events. The caller may unexpectedly get an
184     // ENOENT on a system call using the affected path.
185     //
186     // If |timeout_ms| is 0ms, then this function will return true whether or
187     // not |path| is available. It is the caller's responsibility to ensure
188     // there are no races.
189     bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
190                       const std::chrono::milliseconds& timeout_ms) override;
191 
192     // Create a device and activate the given table, without waiting to acquire
193     // a valid path. If the caller will use GetDmDevicePathByName(), it should
194     // use the timeout variant above.
195     bool CreateDevice(const std::string& name, const DmTable& table);
196 
197     // Loads the device mapper table from parameter into the underlying device
198     // mapper device with given name and activate / resumes the device in the
199     // process. A device with the given name must already exist.
200     //
201     // Returns 'true' on success, false otherwise.
202     bool LoadTableAndActivate(const std::string& name, const DmTable& table) override;
203 
204     // Same as LoadTableAndActivate, but there is no resume step. This puts the
205     // new table in the inactive slot.
206     //
207     // Returns 'true' on success, false otherwise.
208     bool LoadTable(const std::string& name, const DmTable& table) override;
209 
210     // Returns true if a list of available device mapper targets registered in the kernel was
211     // successfully read and stored in 'targets'. Returns 'false' otherwise.
212     bool GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets);
213 
214     // Finds a target by name and returns its information if found. |info| may
215     // be null to check for the existence of a target.
216     bool GetTargetByName(const std::string& name, DmTargetTypeInfo* info);
217 
218     // Return 'true' if it can successfully read the list of device mapper block devices
219     // currently created. 'devices' will be empty if the kernel interactions
220     // were successful and there are no block devices at the moment. Returns
221     // 'false' in case of any failure along the way.
222     bool GetAvailableDevices(std::vector<DmBlockDevice>* devices);
223 
224     // Returns the path to the device mapper device node in '/dev' corresponding to
225     // 'name'. If the device does not exist, false is returned, and the path
226     // parameter is not set.
227     //
228     // This returns a path in the format "/dev/block/dm-N" that can be easily
229     // re-used with sysfs.
230     //
231     // WaitForFile() should not be used in conjunction with this call, since it
232     // could race with ueventd.
233     bool GetDmDevicePathByName(const std::string& name, std::string* path);
234 
235     // Returns the device mapper UUID for a given name.  If the device does not
236     // exist, false is returned, and the path parameter is not set.
237     //
238     // WaitForFile() should not be used in conjunction with this call, since it
239     // could race with ueventd.
240     bool GetDmDeviceUuidByName(const std::string& name, std::string* path);
241 
242     // Returns a device's unique path as generated by ueventd. This will return
243     // true as long as the device has been created, even if ueventd has not
244     // processed it yet.
245     //
246     // The formatting of this path is /dev/block/mapper/by-uuid/<uuid>.
247     bool GetDeviceUniquePath(const std::string& name, std::string* path);
248 
249     // Returns the dev_t for the named device-mapper node.
250     bool GetDeviceNumber(const std::string& name, dev_t* dev);
251 
252     // Returns a major:minor string for the named device-mapper node, that can
253     // be used as inputs to DmTargets that take a block device.
254     bool GetDeviceString(const std::string& name, std::string* dev) override;
255 
256     // The only way to create a DeviceMapper object.
257     static DeviceMapper& Instance();
258 
~DeviceMapper()259     ~DeviceMapper() {
260         if (fd_ != -1) {
261             ::close(fd_);
262         }
263     }
264 
265     // Query the status of a table, given a device name. The output vector will
266     // contain one TargetInfo for each target in the table. If the device does
267     // not exist, or there were too many targets, the call will fail and return
268     // false.
269     bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) override;
270 
271     // Query the status of a table, given a device name. The output vector will
272     // contain IMA TargetInfo for each target in the table. If the device does
273     // not exist, or there were too many targets, the call will fail and return
274     // false.
275     bool GetTableStatusIma(const std::string& name, std::vector<TargetInfo>* table) override;
276 
277     // Identical to GetTableStatus, except also retrives the active table for the device
278     // mapper device from the kernel.
279     bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) override;
280 
281     static std::string GetTargetType(const struct dm_target_spec& spec);
282 
283     // Returns true if given path is a path to a dm block device.
284     bool IsDmBlockDevice(const std::string& path);
285 
286     // Returns name of a dm-device with the given path, or std::nulloptr if given path is not a
287     // dm-device.
288     std::optional<std::string> GetDmDeviceNameByPath(const std::string& path);
289 
290     // Returns a parent block device of a dm device with the given path, or std::nullopt if:
291     //  * Given path doesn't correspond to a dm device.
292     //  * A dm device is based on top of more than one block devices.
293     //  * A failure occurred.
294     std::optional<std::string> GetParentBlockDeviceByPath(const std::string& path);
295 
296     // Iterate the content over "/sys/block/dm-x/dm/name" and find
297     // all the dm-wrapped block devices.
298     //
299     // Returns mapping <partition-name, /dev/block/dm-x>
300     std::map<std::string, std::string> FindDmPartitions();
301 
302     // Create a placeholder device. This is useful for ensuring that a uevent is in the pipeline,
303     // to reduce the amount of time a future WaitForDevice will block. On kernels < 5.15, this
304     // simply calls CreateEmptyDevice. On 5.15 and higher, it also loads (but does not activate)
305     // a placeholder table containing dm-error.
306     bool CreatePlaceholderDevice(const std::string& name);
307 
308     bool GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid);
309 
310     // Send |message| to target, pointed by |name| and |sector|. Use 0 if |sector| is not needed.
311     bool SendMessage(const std::string& name, uint64_t sector, const std::string& message);
312 
313   private:
314     // Maximum possible device mapper targets registered in the kernel.
315     // This is only used to read the list of targets from kernel so we allocate
316     // a finite amount of memory. This limit is in no way enforced by the kernel.
317     static constexpr uint32_t kMaxPossibleDmTargets = 256;
318 
319     // Maximum possible device mapper created block devices. Note that this is restricted by
320     // the minor numbers (that used to be 8 bits) that can be range from 0 to 2^20-1 in newer
321     // kernels. In Android systems however, we never expect these to grow beyond the artificial
322     // limit we are imposing here of 256.
323     static constexpr uint32_t kMaxPossibleDmDevices = 256;
324 
325     bool CreateDevice(const std::string& name, const std::string& uuid = {});
326     bool GetTable(const std::string& name, uint32_t flags, std::vector<TargetInfo>* table);
327     void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const;
328 
329     DeviceMapper();
330 
331     int fd_;
332     // Non-copyable & Non-movable
333     DeviceMapper(const DeviceMapper&) = delete;
334     DeviceMapper& operator=(const DeviceMapper&) = delete;
335     DeviceMapper& operator=(DeviceMapper&&) = delete;
336     DeviceMapper(DeviceMapper&&) = delete;
337 };
338 
339 }  // namespace dm
340 }  // namespace android
341 
342 #endif /* _LIBDM_DM_H_ */
343