1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #include "fs_mgr_dm_linear.h" 26 27 #include <inttypes.h> 28 #include <linux/dm-ioctl.h> 29 #include <string.h> 30 #include <sys/ioctl.h> 31 #include <sys/stat.h> 32 #include <unistd.h> 33 34 #include <sstream> 35 36 #include <android-base/file.h> 37 #include <android-base/logging.h> 38 #include <android-base/stringprintf.h> 39 #include <android-base/strings.h> 40 #include <android-base/unique_fd.h> 41 #include <fs_mgr/file_wait.h> 42 #include <liblp/reader.h> 43 44 #include "fs_mgr_priv.h" 45 46 namespace android { 47 namespace fs_mgr { 48 49 using DeviceMapper = android::dm::DeviceMapper; 50 using DmTable = android::dm::DmTable; 51 using DmTarget = android::dm::DmTarget; 52 using DmTargetZero = android::dm::DmTargetZero; 53 using DmTargetLinear = android::dm::DmTargetLinear; 54 GetPhysicalPartitionDevicePath(const CreateLogicalPartitionParams & params,const LpMetadataBlockDevice & block_device,const std::string & super_device,std::string * result)55 static bool GetPhysicalPartitionDevicePath(const CreateLogicalPartitionParams& params, 56 const LpMetadataBlockDevice& block_device, 57 const std::string& super_device, std::string* result) { 58 // If the super device is the source of this block device's metadata, 59 // make sure we use the correct super device (and not just "super", 60 // which might not exist.) 61 std::string name = GetBlockDevicePartitionName(block_device); 62 if (android::base::StartsWith(name, "dm-")) { 63 // Device-mapper nodes are not normally allowed in LpMetadata, since 64 // they are not consistent across reboots. However for the purposes of 65 // testing it's useful to handle them. For example when running DSUs, 66 // userdata is a device-mapper device, and some stacking will result 67 // when using libfiemap. 68 *result = "/dev/block/" + name; 69 return true; 70 } 71 72 auto opener = params.partition_opener; 73 std::string dev_string = opener->GetDeviceString(name); 74 if (GetMetadataSuperBlockDevice(*params.metadata) == &block_device) { 75 dev_string = opener->GetDeviceString(super_device); 76 } 77 78 // Note: device-mapper will not accept symlinks, so we must use realpath 79 // here. If the device string is a major:minor sequence, we don't need to 80 // to call Realpath (it would not work anyway). 81 if (android::base::StartsWith(dev_string, "/")) { 82 if (!android::base::Realpath(dev_string, result)) { 83 PERROR << "realpath: " << dev_string; 84 return false; 85 } 86 } else { 87 *result = dev_string; 88 } 89 return true; 90 } 91 CreateDmTableInternal(const CreateLogicalPartitionParams & params,DmTable * table)92 bool CreateDmTableInternal(const CreateLogicalPartitionParams& params, DmTable* table) { 93 const auto& super_device = params.block_device; 94 95 uint64_t sector = 0; 96 for (size_t i = 0; i < params.partition->num_extents; i++) { 97 const auto& extent = params.metadata->extents[params.partition->first_extent_index + i]; 98 std::unique_ptr<DmTarget> target; 99 switch (extent.target_type) { 100 case LP_TARGET_TYPE_ZERO: 101 target = std::make_unique<DmTargetZero>(sector, extent.num_sectors); 102 break; 103 case LP_TARGET_TYPE_LINEAR: { 104 const auto& block_device = params.metadata->block_devices[extent.target_source]; 105 std::string dev_string; 106 if (!GetPhysicalPartitionDevicePath(params, block_device, super_device, 107 &dev_string)) { 108 LOG(ERROR) << "Unable to complete device-mapper table, unknown block device"; 109 return false; 110 } 111 target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, dev_string, 112 extent.target_data); 113 break; 114 } 115 default: 116 LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type; 117 return false; 118 } 119 if (!table->AddTarget(std::move(target))) { 120 return false; 121 } 122 sector += extent.num_sectors; 123 } 124 if (params.partition->attributes & LP_PARTITION_ATTR_READONLY) { 125 table->set_readonly(true); 126 } 127 if (params.force_writable) { 128 table->set_readonly(false); 129 } 130 return true; 131 } 132 CreateDmTable(CreateLogicalPartitionParams params,DmTable * table)133 bool CreateDmTable(CreateLogicalPartitionParams params, DmTable* table) { 134 CreateLogicalPartitionParams::OwnedData owned_data; 135 if (!params.InitDefaults(&owned_data)) return false; 136 return CreateDmTableInternal(params, table); 137 } 138 CreateLogicalPartitions(const std::string & block_device)139 bool CreateLogicalPartitions(const std::string& block_device) { 140 uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); 141 auto metadata = ReadMetadata(block_device.c_str(), slot); 142 if (!metadata) { 143 LOG(ERROR) << "Could not read partition table."; 144 return true; 145 } 146 return CreateLogicalPartitions(*metadata.get(), block_device); 147 } 148 ReadCurrentMetadata(const std::string & block_device)149 std::unique_ptr<LpMetadata> ReadCurrentMetadata(const std::string& block_device) { 150 uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); 151 return ReadMetadata(block_device.c_str(), slot); 152 } 153 CreateLogicalPartitions(const LpMetadata & metadata,const std::string & super_device)154 bool CreateLogicalPartitions(const LpMetadata& metadata, const std::string& super_device) { 155 CreateLogicalPartitionParams params = { 156 .block_device = super_device, 157 .metadata = &metadata, 158 }; 159 for (const auto& partition : metadata.partitions) { 160 if (!partition.num_extents) { 161 LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition); 162 continue; 163 } 164 if (partition.attributes & LP_PARTITION_ATTR_DISABLED) { 165 LINFO << "Skipping disabled partition: " << GetPartitionName(partition); 166 continue; 167 } 168 169 params.partition = &partition; 170 171 std::string ignore_path; 172 if (!CreateLogicalPartition(params, &ignore_path)) { 173 LERROR << "Could not create logical partition: " << GetPartitionName(partition); 174 return false; 175 } 176 } 177 return true; 178 } 179 InitDefaults(CreateLogicalPartitionParams::OwnedData * owned)180 bool CreateLogicalPartitionParams::InitDefaults(CreateLogicalPartitionParams::OwnedData* owned) { 181 if (block_device.empty()) { 182 LOG(ERROR) << "block_device is required for CreateLogicalPartition"; 183 return false; 184 } 185 186 if (!partition_opener) { 187 owned->partition_opener = std::make_unique<PartitionOpener>(); 188 partition_opener = owned->partition_opener.get(); 189 } 190 191 // Read metadata if needed. 192 if (!metadata) { 193 if (!metadata_slot) { 194 LOG(ERROR) << "Either metadata or a metadata slot must be specified."; 195 return false; 196 } 197 auto slot = *metadata_slot; 198 if (owned->metadata = ReadMetadata(*partition_opener, block_device, slot); 199 !owned->metadata) { 200 LOG(ERROR) << "Could not read partition table for: " << block_device; 201 return false; 202 } 203 metadata = owned->metadata.get(); 204 } 205 206 // Find the partition by name if needed. 207 if (!partition) { 208 for (const auto& metadata_partition : metadata->partitions) { 209 if (android::fs_mgr::GetPartitionName(metadata_partition) == partition_name) { 210 partition = &metadata_partition; 211 break; 212 } 213 } 214 } 215 if (!partition) { 216 LERROR << "Could not find any partition with name: " << partition_name; 217 return false; 218 } 219 if (partition_name.empty()) { 220 partition_name = android::fs_mgr::GetPartitionName(*partition); 221 } else if (partition_name != android::fs_mgr::GetPartitionName(*partition)) { 222 LERROR << "Inconsistent partition_name " << partition_name << " with partition " 223 << android::fs_mgr::GetPartitionName(*partition); 224 return false; 225 } 226 227 if (device_name.empty()) { 228 device_name = partition_name; 229 } 230 231 return true; 232 } 233 CreateLogicalPartition(CreateLogicalPartitionParams params,std::string * path)234 bool CreateLogicalPartition(CreateLogicalPartitionParams params, std::string* path) { 235 CreateLogicalPartitionParams::OwnedData owned_data; 236 if (!params.InitDefaults(&owned_data)) return false; 237 238 DmTable table; 239 if (!CreateDmTableInternal(params, &table)) { 240 return false; 241 } 242 243 DeviceMapper& dm = DeviceMapper::Instance(); 244 if (!dm.CreateDevice(params.device_name, table, path, params.timeout_ms)) { 245 return false; 246 } 247 LINFO << "Created logical partition " << params.device_name << " on device " << *path; 248 return true; 249 } 250 GetDeviceName() const251 std::string CreateLogicalPartitionParams::GetDeviceName() const { 252 if (!device_name.empty()) return device_name; 253 return GetPartitionName(); 254 } 255 GetPartitionName() const256 std::string CreateLogicalPartitionParams::GetPartitionName() const { 257 if (!partition_name.empty()) return partition_name; 258 if (partition) return android::fs_mgr::GetPartitionName(*partition); 259 return "<unknown partition>"; 260 } 261 UnmapDevice(const std::string & name)262 bool UnmapDevice(const std::string& name) { 263 DeviceMapper& dm = DeviceMapper::Instance(); 264 if (!dm.DeleteDevice(name)) { 265 return false; 266 } 267 return true; 268 } 269 DestroyLogicalPartition(const std::string & name)270 bool DestroyLogicalPartition(const std::string& name) { 271 if (!UnmapDevice(name)) { 272 return false; 273 } 274 LINFO << "Unmapped logical partition " << name; 275 return true; 276 } 277 278 } // namespace fs_mgr 279 } // namespace android 280