• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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