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