blob: eaa515aea7d985714815d184b9cdc4532b6ce4bf [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
Alistair Strachan1906d5f2018-11-27 17:39:00 -080055static bool GetPhysicalPartitionDevicePath(const LpMetadata& metadata,
56 const LpMetadataBlockDevice& block_device,
57 const std::string& super_device,
58 std::string* result) {
David Anderson9a532412018-10-12 13:51:52 -070059 // Note: device-mapper will not accept symlinks, so we must use realpath
60 // here.
61 std::string name = GetBlockDevicePartitionName(block_device);
62 std::string path = "/dev/block/by-name/" + name;
Alistair Strachan1906d5f2018-11-27 17:39:00 -080063 // If the super device is the source of this block device's metadata,
64 // make sure we use the correct super device (and not just "super",
65 // which might not exist.)
66 if (GetMetadataSuperBlockDevice(metadata) == &block_device) {
67 path = super_device;
68 }
David Anderson9a532412018-10-12 13:51:52 -070069 if (!android::base::Realpath(path, result)) {
70 PERROR << "realpath: " << path;
71 return false;
72 }
73 return true;
74}
75
76static bool CreateDmTable(const LpMetadata& metadata, const LpMetadataPartition& partition,
Alistair Strachan1906d5f2018-11-27 17:39:00 -080077 const std::string& super_device, DmTable* table) {
David Anderson4b524402018-06-21 16:19:48 -070078 uint64_t sector = 0;
79 for (size_t i = 0; i < partition.num_extents; i++) {
80 const auto& extent = metadata.extents[partition.first_extent_index + i];
81 std::unique_ptr<DmTarget> target;
82 switch (extent.target_type) {
83 case LP_TARGET_TYPE_ZERO:
84 target = std::make_unique<DmTargetZero>(sector, extent.num_sectors);
85 break;
David Anderson9a532412018-10-12 13:51:52 -070086 case LP_TARGET_TYPE_LINEAR: {
David Andersonef9740c2018-10-23 14:43:10 -070087 const auto& block_device = metadata.block_devices[extent.target_source];
David Anderson9a532412018-10-12 13:51:52 -070088 std::string path;
Alistair Strachan1906d5f2018-11-27 17:39:00 -080089 if (!GetPhysicalPartitionDevicePath(metadata, block_device, super_device, &path)) {
David Anderson9a532412018-10-12 13:51:52 -070090 LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
91 return false;
92 }
93 target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, path,
David Anderson4b524402018-06-21 16:19:48 -070094 extent.target_data);
95 break;
David Anderson9a532412018-10-12 13:51:52 -070096 }
David Anderson4b524402018-06-21 16:19:48 -070097 default:
98 LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type;
99 return false;
100 }
101 if (!table->AddTarget(std::move(target))) {
102 return false;
103 }
104 sector += extent.num_sectors;
105 }
106 if (partition.attributes & LP_PARTITION_ATTR_READONLY) {
107 table->set_readonly(true);
108 }
109 return true;
110}
111
David Anderson6590df22018-06-14 15:03:53 -0700112bool CreateLogicalPartitions(const std::string& block_device) {
113 uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
114 auto metadata = ReadMetadata(block_device.c_str(), slot);
115 if (!metadata) {
116 LOG(ERROR) << "Could not read partition table.";
117 return true;
118 }
Alistair Strachan1906d5f2018-11-27 17:39:00 -0800119 return CreateLogicalPartitions(*metadata.get(), block_device);
David Andersonf89b1df2018-11-05 17:30:16 -0800120}
121
122std::unique_ptr<LpMetadata> ReadCurrentMetadata(const std::string& block_device) {
123 uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
124 return ReadMetadata(block_device.c_str(), slot);
125}
126
Alistair Strachan1906d5f2018-11-27 17:39:00 -0800127bool CreateLogicalPartitions(const LpMetadata& metadata, const std::string& super_device) {
David Anderson15aa9542019-08-12 17:07:50 -0700128 CreateLogicalPartitionParams params = {
129 .block_device = super_device,
130 .metadata = &metadata,
131 };
David Andersonf89b1df2018-11-05 17:30:16 -0800132 for (const auto& partition : metadata.partitions) {
David Anderson6868cb92018-08-06 15:53:38 -0700133 if (!partition.num_extents) {
134 LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition);
135 continue;
136 }
David Anderson15aa9542019-08-12 17:07:50 -0700137
138 params.partition = &partition;
139
140 std::string ignore_path;
141 if (!CreateLogicalPartition(params, &ignore_path)) {
David Anderson23de22d2018-07-20 16:28:04 -0700142 LERROR << "Could not create logical partition: " << GetPartitionName(partition);
143 return false;
144 }
David Anderson6590df22018-06-14 15:03:53 -0700145 }
David Anderson4b524402018-06-21 16:19:48 -0700146 return true;
David Anderson6590df22018-06-14 15:03:53 -0700147}
148
David Anderson15aa9542019-08-12 17:07:50 -0700149bool CreateLogicalPartition(const CreateLogicalPartitionParams& params, std::string* path) {
150 const LpMetadata* metadata = params.metadata;
151
152 // Read metadata if needed.
153 std::unique_ptr<LpMetadata> local_metadata;
154 if (!metadata) {
155 if (!params.metadata_slot) {
156 LOG(ERROR) << "Either metadata or a metadata slot must be specified.";
157 return false;
158 }
159 auto slot = *params.metadata_slot;
160 if (local_metadata = ReadMetadata(params.block_device, slot); !local_metadata) {
161 LOG(ERROR) << "Could not read partition table for: " << params.block_device;
162 return false;
163 }
164 metadata = local_metadata.get();
165 }
166
167 // Find the partition by name if needed.
168 const LpMetadataPartition* partition = params.partition;
169 if (!partition) {
170 for (const auto& iter : metadata->partitions) {
171 if (GetPartitionName(iter) == params.partition_name) {
172 partition = &iter;
173 break;
174 }
175 }
176 if (!partition) {
177 LERROR << "Could not find any partition with name: " << params.partition_name;
178 return false;
David Anderson908f07b2019-01-07 18:29:27 -0800179 }
180 }
David Anderson908f07b2019-01-07 18:29:27 -0800181
David Anderson15aa9542019-08-12 17:07:50 -0700182 DmTable table;
183 if (!CreateDmTable(*metadata, *partition, params.block_device, &table)) {
184 return false;
David Anderson23de22d2018-07-20 16:28:04 -0700185 }
David Anderson15aa9542019-08-12 17:07:50 -0700186 if (params.force_writable) {
187 table.set_readonly(false);
188 }
189
190 std::string device_name = params.device_name;
191 if (device_name.empty()) {
192 device_name = GetPartitionName(*partition);
193 }
194
195 DeviceMapper& dm = DeviceMapper::Instance();
196 if (!dm.CreateDevice(device_name, table, path, params.timeout_ms)) {
197 return false;
198 }
199 LINFO << "Created logical partition " << device_name << " on device " << *path;
200 return true;
David Anderson23de22d2018-07-20 16:28:04 -0700201}
202
David Anderson470fe2b2019-07-10 18:09:50 -0700203bool UnmapDevice(const std::string& name) {
David Anderson23de22d2018-07-20 16:28:04 -0700204 DeviceMapper& dm = DeviceMapper::Instance();
David Andersonb9f734c2018-08-03 10:12:16 -0700205 if (!dm.DeleteDevice(name)) {
206 return false;
207 }
Yifan Hong402633d2019-04-09 10:11:34 -0700208 return true;
209}
210
David Anderson470fe2b2019-07-10 18:09:50 -0700211bool DestroyLogicalPartition(const std::string& name) {
212 if (!UnmapDevice(name)) {
Yifan Hong402633d2019-04-09 10:11:34 -0700213 return false;
214 }
David Andersonb9f734c2018-08-03 10:12:16 -0700215 LINFO << "Unmapped logical partition " << name;
216 return true;
David Anderson23de22d2018-07-20 16:28:04 -0700217}
218
David Anderson62e5b202018-05-01 17:09:17 -0700219} // namespace fs_mgr
220} // namespace android