blob: 9046132f817a57309b62e004210441aee48d688b [file] [log] [blame]
David Anderson62e5b202018-05-01 17:09:17 -07001/*
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
David Anderson9a532412018-10-12 13:51:52 -070036#include <android-base/file.h>
David Anderson62e5b202018-05-01 17:09:17 -070037#include <android-base/logging.h>
38#include <android-base/stringprintf.h>
39#include <android-base/strings.h>
40#include <android-base/unique_fd.h>
David Anderson5c475c72019-06-11 17:40:49 -070041#include <fs_mgr/file_wait.h>
David Anderson6590df22018-06-14 15:03:53 -070042#include <liblp/reader.h>
David Anderson62e5b202018-05-01 17:09:17 -070043
44#include "fs_mgr_priv.h"
David Anderson62e5b202018-05-01 17:09:17 -070045
46namespace android {
47namespace fs_mgr {
48
David Anderson4b524402018-06-21 16:19:48 -070049using DeviceMapper = android::dm::DeviceMapper;
50using DmTable = android::dm::DmTable;
51using DmTarget = android::dm::DmTarget;
52using DmTargetZero = android::dm::DmTargetZero;
53using DmTargetLinear = android::dm::DmTargetLinear;
David Anderson62e5b202018-05-01 17:09:17 -070054
David Anderson0d2bcd42020-05-19 05:52:57 +000055static bool GetPhysicalPartitionDevicePath(const CreateLogicalPartitionParams& params,
Alistair Strachan1906d5f2018-11-27 17:39:00 -080056 const LpMetadataBlockDevice& block_device,
David Anderson4929df02019-08-15 13:21:43 -070057 const std::string& super_device, std::string* result) {
Alistair Strachan1906d5f2018-11-27 17:39:00 -080058 // 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.)
David Anderson4929df02019-08-15 13:21:43 -070061 std::string name = GetBlockDevicePartitionName(block_device);
David Anderson0d2bcd42020-05-19 05:52:57 +000062 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);
Alistair Strachan1906d5f2018-11-27 17:39:00 -080076 }
David Anderson4929df02019-08-15 13:21:43 -070077
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;
David Anderson9a532412018-10-12 13:51:52 -070088 }
89 return true;
90}
91
Yifan Hongc02509b2019-09-11 18:15:22 -070092bool CreateDmTableInternal(const CreateLogicalPartitionParams& params, DmTable* table) {
93 const auto& super_device = params.block_device;
94
David Anderson4b524402018-06-21 16:19:48 -070095 uint64_t sector = 0;
Yifan Hongc02509b2019-09-11 18:15:22 -070096 for (size_t i = 0; i < params.partition->num_extents; i++) {
97 const auto& extent = params.metadata->extents[params.partition->first_extent_index + i];
David Anderson4b524402018-06-21 16:19:48 -070098 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;
David Anderson9a532412018-10-12 13:51:52 -0700103 case LP_TARGET_TYPE_LINEAR: {
Yifan Hongc02509b2019-09-11 18:15:22 -0700104 const auto& block_device = params.metadata->block_devices[extent.target_source];
David Anderson4929df02019-08-15 13:21:43 -0700105 std::string dev_string;
David Anderson0d2bcd42020-05-19 05:52:57 +0000106 if (!GetPhysicalPartitionDevicePath(params, block_device, super_device,
107 &dev_string)) {
David Anderson9a532412018-10-12 13:51:52 -0700108 LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
109 return false;
110 }
David Anderson4929df02019-08-15 13:21:43 -0700111 target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, dev_string,
David Anderson4b524402018-06-21 16:19:48 -0700112 extent.target_data);
113 break;
David Anderson9a532412018-10-12 13:51:52 -0700114 }
David Anderson4b524402018-06-21 16:19:48 -0700115 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 }
Yifan Hongc02509b2019-09-11 18:15:22 -0700124 if (params.partition->attributes & LP_PARTITION_ATTR_READONLY) {
David Anderson4b524402018-06-21 16:19:48 -0700125 table->set_readonly(true);
126 }
Yifan Hongc02509b2019-09-11 18:15:22 -0700127 if (params.force_writable) {
128 table->set_readonly(false);
129 }
David Anderson4b524402018-06-21 16:19:48 -0700130 return true;
131}
132
Yifan Hongc02509b2019-09-11 18:15:22 -0700133bool 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
David Anderson6590df22018-06-14 15:03:53 -0700139bool 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 }
Alistair Strachan1906d5f2018-11-27 17:39:00 -0800146 return CreateLogicalPartitions(*metadata.get(), block_device);
David Andersonf89b1df2018-11-05 17:30:16 -0800147}
148
149std::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
Alistair Strachan1906d5f2018-11-27 17:39:00 -0800154bool CreateLogicalPartitions(const LpMetadata& metadata, const std::string& super_device) {
David Anderson15aa9542019-08-12 17:07:50 -0700155 CreateLogicalPartitionParams params = {
156 .block_device = super_device,
157 .metadata = &metadata,
158 };
David Andersonf89b1df2018-11-05 17:30:16 -0800159 for (const auto& partition : metadata.partitions) {
David Anderson6868cb92018-08-06 15:53:38 -0700160 if (!partition.num_extents) {
161 LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition);
162 continue;
163 }
David Andersonf41c7bb2019-12-16 19:52:14 -0800164 if (partition.attributes & LP_PARTITION_ATTR_DISABLED) {
165 LINFO << "Skipping disabled partition: " << GetPartitionName(partition);
166 continue;
167 }
David Anderson15aa9542019-08-12 17:07:50 -0700168
169 params.partition = &partition;
170
171 std::string ignore_path;
172 if (!CreateLogicalPartition(params, &ignore_path)) {
David Anderson23de22d2018-07-20 16:28:04 -0700173 LERROR << "Could not create logical partition: " << GetPartitionName(partition);
174 return false;
175 }
David Anderson6590df22018-06-14 15:03:53 -0700176 }
David Anderson4b524402018-06-21 16:19:48 -0700177 return true;
David Anderson6590df22018-06-14 15:03:53 -0700178}
179
Yifan Hong1ada55e2019-08-16 15:31:12 -0700180bool CreateLogicalPartitionParams::InitDefaults(CreateLogicalPartitionParams::OwnedData* owned) {
181 if (block_device.empty()) {
182 LOG(ERROR) << "block_device is required for CreateLogicalPartition";
183 return false;
184 }
David Anderson15aa9542019-08-12 17:07:50 -0700185
Yifan Hongc02509b2019-09-11 18:15:22 -0700186 if (!partition_opener) {
187 owned->partition_opener = std::make_unique<PartitionOpener>();
188 partition_opener = owned->partition_opener.get();
189 }
190
David Anderson15aa9542019-08-12 17:07:50 -0700191 // Read metadata if needed.
David Anderson15aa9542019-08-12 17:07:50 -0700192 if (!metadata) {
Yifan Hong1ada55e2019-08-16 15:31:12 -0700193 if (!metadata_slot) {
David Anderson15aa9542019-08-12 17:07:50 -0700194 LOG(ERROR) << "Either metadata or a metadata slot must be specified.";
195 return false;
196 }
Yifan Hong1ada55e2019-08-16 15:31:12 -0700197 auto slot = *metadata_slot;
Yifan Hongc02509b2019-09-11 18:15:22 -0700198 if (owned->metadata = ReadMetadata(*partition_opener, block_device, slot);
199 !owned->metadata) {
Yifan Hong1ada55e2019-08-16 15:31:12 -0700200 LOG(ERROR) << "Could not read partition table for: " << block_device;
David Anderson15aa9542019-08-12 17:07:50 -0700201 return false;
202 }
Yifan Hong1ada55e2019-08-16 15:31:12 -0700203 metadata = owned->metadata.get();
David Anderson15aa9542019-08-12 17:07:50 -0700204 }
205
206 // Find the partition by name if needed.
David Anderson15aa9542019-08-12 17:07:50 -0700207 if (!partition) {
Yifan Hong1ada55e2019-08-16 15:31:12 -0700208 for (const auto& metadata_partition : metadata->partitions) {
209 if (android::fs_mgr::GetPartitionName(metadata_partition) == partition_name) {
210 partition = &metadata_partition;
David Anderson15aa9542019-08-12 17:07:50 -0700211 break;
212 }
213 }
Yifan Hong1ada55e2019-08-16 15:31:12 -0700214 }
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;
David Anderson908f07b2019-01-07 18:29:27 -0800225 }
David Anderson908f07b2019-01-07 18:29:27 -0800226
Yifan Hong1ada55e2019-08-16 15:31:12 -0700227 if (device_name.empty()) {
228 device_name = partition_name;
229 }
230
231 return true;
232}
233
234bool CreateLogicalPartition(CreateLogicalPartitionParams params, std::string* path) {
235 CreateLogicalPartitionParams::OwnedData owned_data;
236 if (!params.InitDefaults(&owned_data)) return false;
David Anderson4929df02019-08-15 13:21:43 -0700237
David Anderson15aa9542019-08-12 17:07:50 -0700238 DmTable table;
Yifan Hongc02509b2019-09-11 18:15:22 -0700239 if (!CreateDmTableInternal(params, &table)) {
David Anderson15aa9542019-08-12 17:07:50 -0700240 return false;
David Anderson23de22d2018-07-20 16:28:04 -0700241 }
David Anderson15aa9542019-08-12 17:07:50 -0700242
David Anderson15aa9542019-08-12 17:07:50 -0700243 DeviceMapper& dm = DeviceMapper::Instance();
Yifan Hong1ada55e2019-08-16 15:31:12 -0700244 if (!dm.CreateDevice(params.device_name, table, path, params.timeout_ms)) {
David Anderson15aa9542019-08-12 17:07:50 -0700245 return false;
246 }
Yifan Hong1ada55e2019-08-16 15:31:12 -0700247 LINFO << "Created logical partition " << params.device_name << " on device " << *path;
David Anderson15aa9542019-08-12 17:07:50 -0700248 return true;
David Anderson23de22d2018-07-20 16:28:04 -0700249}
250
David Anderson9267c3f2019-08-15 12:50:38 -0700251std::string CreateLogicalPartitionParams::GetDeviceName() const {
252 if (!device_name.empty()) return device_name;
253 return GetPartitionName();
254}
255
256std::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
David Anderson470fe2b2019-07-10 18:09:50 -0700262bool UnmapDevice(const std::string& name) {
David Anderson23de22d2018-07-20 16:28:04 -0700263 DeviceMapper& dm = DeviceMapper::Instance();
David Andersonb9f734c2018-08-03 10:12:16 -0700264 if (!dm.DeleteDevice(name)) {
265 return false;
266 }
Yifan Hong402633d2019-04-09 10:11:34 -0700267 return true;
268}
269
David Anderson470fe2b2019-07-10 18:09:50 -0700270bool DestroyLogicalPartition(const std::string& name) {
271 if (!UnmapDevice(name)) {
Yifan Hong402633d2019-04-09 10:11:34 -0700272 return false;
273 }
David Andersonb9f734c2018-08-03 10:12:16 -0700274 LINFO << "Unmapped logical partition " << name;
275 return true;
David Anderson23de22d2018-07-20 16:28:04 -0700276}
277
David Anderson62e5b202018-05-01 17:09:17 -0700278} // namespace fs_mgr
279} // namespace android