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