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