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 <liblp/reader.h>
42
43 #include "fs_mgr_priv.h"
44
45 namespace android {
46 namespace fs_mgr {
47
48 using DeviceMapper = android::dm::DeviceMapper;
49 using DmTable = android::dm::DmTable;
50 using DmTarget = android::dm::DmTarget;
51 using DmTargetZero = android::dm::DmTargetZero;
52 using DmTargetLinear = android::dm::DmTargetLinear;
53
GetPhysicalPartitionDevicePath(const LpMetadata & metadata,const LpMetadataBlockDevice & block_device,const std::string & super_device,std::string * result)54 static bool GetPhysicalPartitionDevicePath(const LpMetadata& metadata,
55 const LpMetadataBlockDevice& block_device,
56 const std::string& super_device,
57 std::string* result) {
58 // Note: device-mapper will not accept symlinks, so we must use realpath
59 // here.
60 std::string name = GetBlockDevicePartitionName(block_device);
61 std::string path = "/dev/block/by-name/" + name;
62 // If the super device is the source of this block device's metadata,
63 // make sure we use the correct super device (and not just "super",
64 // which might not exist.)
65 if (GetMetadataSuperBlockDevice(metadata) == &block_device) {
66 path = super_device;
67 }
68 if (!android::base::Realpath(path, result)) {
69 PERROR << "realpath: " << path;
70 return false;
71 }
72 return true;
73 }
74
CreateDmTable(const LpMetadata & metadata,const LpMetadataPartition & partition,const std::string & super_device,DmTable * table)75 static bool CreateDmTable(const LpMetadata& metadata, const LpMetadataPartition& partition,
76 const std::string& super_device, DmTable* table) {
77 uint64_t sector = 0;
78 for (size_t i = 0; i < partition.num_extents; i++) {
79 const auto& extent = metadata.extents[partition.first_extent_index + i];
80 std::unique_ptr<DmTarget> target;
81 switch (extent.target_type) {
82 case LP_TARGET_TYPE_ZERO:
83 target = std::make_unique<DmTargetZero>(sector, extent.num_sectors);
84 break;
85 case LP_TARGET_TYPE_LINEAR: {
86 const auto& block_device = metadata.block_devices[extent.target_source];
87 std::string path;
88 if (!GetPhysicalPartitionDevicePath(metadata, block_device, super_device, &path)) {
89 LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
90 return false;
91 }
92 target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, path,
93 extent.target_data);
94 break;
95 }
96 default:
97 LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type;
98 return false;
99 }
100 if (!table->AddTarget(std::move(target))) {
101 return false;
102 }
103 sector += extent.num_sectors;
104 }
105 if (partition.attributes & LP_PARTITION_ATTR_READONLY) {
106 table->set_readonly(true);
107 }
108 return true;
109 }
110
CreateLogicalPartition(const LpMetadata & metadata,const LpMetadataPartition & partition,bool force_writable,const std::chrono::milliseconds & timeout_ms,const std::string & super_device,std::string * path)111 static bool CreateLogicalPartition(const LpMetadata& metadata, const LpMetadataPartition& partition,
112 bool force_writable, const std::chrono::milliseconds& timeout_ms,
113 const std::string& super_device, std::string* path) {
114 DeviceMapper& dm = DeviceMapper::Instance();
115
116 DmTable table;
117 if (!CreateDmTable(metadata, partition, super_device, &table)) {
118 return false;
119 }
120 if (force_writable) {
121 table.set_readonly(false);
122 }
123 std::string name = GetPartitionName(partition);
124 if (!dm.CreateDevice(name, table)) {
125 return false;
126 }
127 if (!dm.GetDmDevicePathByName(name, path)) {
128 return false;
129 }
130 if (timeout_ms > std::chrono::milliseconds::zero()) {
131 if (!fs_mgr_wait_for_file(*path, timeout_ms, FileWaitMode::Exists)) {
132 DestroyLogicalPartition(name, {});
133 LERROR << "Timed out waiting for device path: " << *path;
134 return false;
135 }
136 }
137 LINFO << "Created logical partition " << name << " on device " << *path;
138 return true;
139 }
140
CreateLogicalPartitions(const std::string & block_device)141 bool CreateLogicalPartitions(const std::string& block_device) {
142 uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
143 auto metadata = ReadMetadata(block_device.c_str(), slot);
144 if (!metadata) {
145 LOG(ERROR) << "Could not read partition table.";
146 return true;
147 }
148 return CreateLogicalPartitions(*metadata.get(), block_device);
149 }
150
ReadCurrentMetadata(const std::string & block_device)151 std::unique_ptr<LpMetadata> ReadCurrentMetadata(const std::string& block_device) {
152 uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
153 return ReadMetadata(block_device.c_str(), slot);
154 }
155
CreateLogicalPartitions(const LpMetadata & metadata,const std::string & super_device)156 bool CreateLogicalPartitions(const LpMetadata& metadata, const std::string& super_device) {
157 for (const auto& partition : metadata.partitions) {
158 if (!partition.num_extents) {
159 LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition);
160 continue;
161 }
162 std::string path;
163 if (!CreateLogicalPartition(metadata, partition, false, {}, super_device, &path)) {
164 LERROR << "Could not create logical partition: " << GetPartitionName(partition);
165 return false;
166 }
167 }
168 return true;
169 }
170
CreateLogicalPartition(const std::string & block_device,const LpMetadata & metadata,const std::string & partition_name,bool force_writable,const std::chrono::milliseconds & timeout_ms,std::string * path)171 bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
172 const std::string& partition_name, bool force_writable,
173 const std::chrono::milliseconds& timeout_ms, std::string* path) {
174 for (const auto& partition : metadata.partitions) {
175 if (GetPartitionName(partition) == partition_name) {
176 return CreateLogicalPartition(metadata, partition, force_writable, timeout_ms,
177 block_device, path);
178 }
179 }
180 LERROR << "Could not find any partition with name: " << partition_name;
181 return false;
182 }
183
CreateLogicalPartition(const std::string & block_device,uint32_t metadata_slot,const std::string & partition_name,bool force_writable,const std::chrono::milliseconds & timeout_ms,std::string * path)184 bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_slot,
185 const std::string& partition_name, bool force_writable,
186 const std::chrono::milliseconds& timeout_ms, std::string* path) {
187 auto metadata = ReadMetadata(block_device.c_str(), metadata_slot);
188 if (!metadata) {
189 LOG(ERROR) << "Could not read partition table.";
190 return true;
191 }
192 return CreateLogicalPartition(block_device, *metadata.get(), partition_name, force_writable,
193 timeout_ms, path);
194 }
195
UnmapDevice(const std::string & name,const std::chrono::milliseconds & timeout_ms)196 bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
197 DeviceMapper& dm = DeviceMapper::Instance();
198 std::string path;
199 if (timeout_ms > std::chrono::milliseconds::zero()) {
200 dm.GetDmDevicePathByName(name, &path);
201 }
202 if (!dm.DeleteDevice(name)) {
203 return false;
204 }
205 if (!path.empty() && !fs_mgr_wait_for_file(path, timeout_ms, FileWaitMode::DoesNotExist)) {
206 LERROR << "Timed out waiting for device path to unlink: " << path;
207 return false;
208 }
209 return true;
210 }
211
DestroyLogicalPartition(const std::string & name,const std::chrono::milliseconds & timeout_ms)212 bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
213 if (!UnmapDevice(name, timeout_ms)) {
214 return false;
215 }
216 LINFO << "Unmapped logical partition " << name;
217 return true;
218 }
219
220 } // namespace fs_mgr
221 } // namespace android
222