1 // 2 // Copyright (C) 2018 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef LIBLP_METADATA_BUILDER_H 18 #define LIBLP_METADATA_BUILDER_H 19 20 #include <stddef.h> 21 #include <stdint.h> 22 23 #include <map> 24 #include <memory> 25 #include <optional> 26 #include <set> 27 28 #include "liblp.h" 29 #include "partition_opener.h" 30 31 namespace android { 32 namespace fs_mgr { 33 34 class LinearExtent; 35 36 // By default, partitions are aligned on a 1MiB boundary. 37 static const uint32_t kDefaultPartitionAlignment = 1024 * 1024; 38 static const uint32_t kDefaultBlockSize = 4096; 39 40 // Abstraction around dm-targets that can be encoded into logical partition tables. 41 class Extent { 42 public: Extent(uint64_t num_sectors)43 explicit Extent(uint64_t num_sectors) : num_sectors_(num_sectors) {} ~Extent()44 virtual ~Extent() {} 45 46 virtual bool AddTo(LpMetadata* out) const = 0; AsLinearExtent()47 virtual LinearExtent* AsLinearExtent() { return nullptr; } 48 num_sectors()49 uint64_t num_sectors() const { return num_sectors_; } set_num_sectors(uint64_t num_sectors)50 void set_num_sectors(uint64_t num_sectors) { num_sectors_ = num_sectors; } 51 52 protected: 53 uint64_t num_sectors_; 54 }; 55 56 // This corresponds to a dm-linear target. 57 class LinearExtent final : public Extent { 58 public: LinearExtent(uint64_t num_sectors,uint32_t device_index,uint64_t physical_sector)59 LinearExtent(uint64_t num_sectors, uint32_t device_index, uint64_t physical_sector) 60 : Extent(num_sectors), device_index_(device_index), physical_sector_(physical_sector) {} 61 62 bool AddTo(LpMetadata* metadata) const override; AsLinearExtent()63 LinearExtent* AsLinearExtent() override { return this; } 64 physical_sector()65 uint64_t physical_sector() const { return physical_sector_; } end_sector()66 uint64_t end_sector() const { return physical_sector_ + num_sectors_; } device_index()67 uint32_t device_index() const { return device_index_; } 68 OwnsSector(uint64_t sector)69 bool OwnsSector(uint64_t sector) const { 70 return sector >= physical_sector_ && sector < end_sector(); 71 } 72 73 private: 74 uint32_t device_index_; 75 uint64_t physical_sector_; 76 }; 77 78 // This corresponds to a dm-zero target. 79 class ZeroExtent final : public Extent { 80 public: ZeroExtent(uint64_t num_sectors)81 explicit ZeroExtent(uint64_t num_sectors) : Extent(num_sectors) {} 82 83 bool AddTo(LpMetadata* out) const override; 84 }; 85 86 class PartitionGroup final { 87 friend class MetadataBuilder; 88 89 public: PartitionGroup(const std::string & name,uint64_t maximum_size)90 explicit PartitionGroup(const std::string& name, uint64_t maximum_size) 91 : name_(name), maximum_size_(maximum_size) {} 92 name()93 const std::string& name() const { return name_; } maximum_size()94 uint64_t maximum_size() const { return maximum_size_; } 95 96 private: set_maximum_size(uint64_t maximum_size)97 void set_maximum_size(uint64_t maximum_size) { maximum_size_ = maximum_size; } 98 99 std::string name_; 100 uint64_t maximum_size_; 101 }; 102 103 class Partition final { 104 friend class MetadataBuilder; 105 106 public: 107 Partition(const std::string& name, const std::string& group_name, uint32_t attributes); 108 109 // Add a raw extent. 110 void AddExtent(std::unique_ptr<Extent>&& extent); 111 112 // Remove all extents from this partition. 113 void RemoveExtents(); 114 115 // Compute the size used by linear extents. This is the same as size(), 116 // but does not factor in extents which do not take up space. 117 uint64_t BytesOnDisk() const; 118 name()119 const std::string& name() const { return name_; } group_name()120 const std::string& group_name() const { return group_name_; } attributes()121 uint32_t attributes() const { return attributes_; } extents()122 const std::vector<std::unique_ptr<Extent>>& extents() const { return extents_; } size()123 uint64_t size() const { return size_; } 124 125 private: 126 void ShrinkTo(uint64_t aligned_size); set_group_name(const std::string & group_name)127 void set_group_name(const std::string& group_name) { group_name_ = group_name; } 128 129 std::string name_; 130 std::string group_name_; 131 std::vector<std::unique_ptr<Extent>> extents_; 132 uint32_t attributes_; 133 uint64_t size_; 134 }; 135 136 class MetadataBuilder { 137 public: 138 // Construct an empty logical partition table builder given the specified 139 // map of partitions that are available for storing logical partitions. 140 // 141 // At least one partition in the list must be the "super" device, where 142 // metadata will be stored. 143 // 144 // If the parameters would yield invalid metadata, nullptr is returned. This 145 // could happen if the super device is too small to store all required 146 // metadata. 147 static std::unique_ptr<MetadataBuilder> New(const std::vector<BlockDeviceInfo>& block_devices, 148 const std::string& super_partition, 149 uint32_t metadata_max_size, 150 uint32_t metadata_slot_count); 151 152 // Import an existing table for modification. This reads metadata off the 153 // given block device and imports it. It also adjusts alignment information 154 // based on run-time values in the operating system. 155 static std::unique_ptr<MetadataBuilder> New(const IPartitionOpener& opener, 156 const std::string& super_partition, 157 uint32_t slot_number); 158 159 // Same as above, but use the default PartitionOpener. 160 static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition, 161 uint32_t slot_number); 162 163 // This is when performing an A/B update. The source partition must be a 164 // super partition. On a normal device, the metadata for the source slot 165 // is imported and the target slot is ignored. On a retrofit device, the 166 // metadata may not have the target slot's devices listed yet, in which 167 // case, it is automatically upgraded to include all available block 168 // devices. 169 static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener, 170 const std::string& source_partition, 171 uint32_t source_slot_number, 172 uint32_t target_slot_number); 173 174 // Import an existing table for modification. If the table is not valid, for 175 // example it contains duplicate partition names, then nullptr is returned. 176 // 177 // If an IPartitionOpener is specified, then block device informatiom will 178 // be updated. 179 static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata, 180 const IPartitionOpener* opener = nullptr); 181 182 // Helper function for a single super partition, for tests. New(const BlockDeviceInfo & device_info,uint32_t metadata_max_size,uint32_t metadata_slot_count)183 static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info, 184 uint32_t metadata_max_size, 185 uint32_t metadata_slot_count) { 186 return New({device_info}, device_info.partition_name, metadata_max_size, 187 metadata_slot_count); 188 } 189 190 // Wrapper around New() with a BlockDeviceInfo that only specifies a device 191 // size. This is a convenience method for tests. New(uint64_t blockdev_size,uint32_t metadata_max_size,uint32_t metadata_slot_count)192 static std::unique_ptr<MetadataBuilder> New(uint64_t blockdev_size, uint32_t metadata_max_size, 193 uint32_t metadata_slot_count) { 194 BlockDeviceInfo device_info(LP_METADATA_DEFAULT_PARTITION_NAME, blockdev_size, 0, 0, 195 kDefaultBlockSize); 196 return New(device_info, metadata_max_size, metadata_slot_count); 197 } 198 199 // Used by the test harness to override whether the device is "A/B". 200 static void OverrideABForTesting(bool ab_device); 201 202 // Define a new partition group. By default there is one group called 203 // "default", with an unrestricted size. A non-zero size will restrict the 204 // total space used by all partitions in the group. 205 // 206 // This can fail and return false if the group already exists. 207 bool AddGroup(const std::string& group_name, uint64_t maximum_size); 208 209 // Export metadata so it can be serialized to an image, to disk, or mounted 210 // via device-mapper. 211 std::unique_ptr<LpMetadata> Export(); 212 213 // Add a partition, returning a handle so it can be sized as needed. If a 214 // partition with the given name already exists, nullptr is returned. 215 Partition* AddPartition(const std::string& name, const std::string& group_name, 216 uint32_t attributes); 217 218 // Same as AddPartition above, but uses the default partition group which 219 // has no size restrictions. 220 Partition* AddPartition(const std::string& name, uint32_t attributes); 221 222 // Delete a partition by name if it exists. 223 void RemovePartition(const std::string& name); 224 225 // Find a partition by name. If no partition is found, nullptr is returned. 226 Partition* FindPartition(const std::string& name); 227 228 // Find a group by name. If no group is found, nullptr is returned. 229 PartitionGroup* FindGroup(const std::string& name); 230 231 // Add a predetermined extent to a partition. 232 bool AddLinearExtent(Partition* partition, const std::string& block_device, 233 uint64_t num_sectors, uint64_t physical_sector); 234 235 // Grow or shrink a partition to the requested size. This size will be 236 // rounded UP to the nearest block (512 bytes). 237 // 238 // When growing a partition, a greedy algorithm is used to find free gaps 239 // in the partition table and allocate them. If not enough space can be 240 // allocated, false is returned, and the parition table will not be 241 // modified. 242 // 243 // Note, this is an in-memory operation, and it does not alter the 244 // underlying filesystem or contents of the partition on disk. 245 bool ResizePartition(Partition* partition, uint64_t requested_size); 246 247 // Return the list of partitions belonging to a group. 248 std::vector<Partition*> ListPartitionsInGroup(const std::string& group_name); 249 250 // Changes a partition's group. Size constraints will not be checked until 251 // the metadata is exported, to avoid errors during potential group and 252 // size shuffling operations. This will return false if the new group does 253 // not exist. 254 bool ChangePartitionGroup(Partition* partition, const std::string& group_name); 255 256 // Changes the size of a partition group. Size constraints will not be 257 // checked until metadata is exported, to avoid errors during group 258 // reshuffling. This will return false if the group does not exist, or if 259 // the group name is "default". 260 bool ChangeGroupSize(const std::string& group_name, uint64_t maximum_size); 261 262 // Amount of space that can be allocated to logical partitions. 263 uint64_t AllocatableSpace() const; 264 uint64_t UsedSpace() const; 265 266 // Return a list of all group names. 267 std::vector<std::string> ListGroups() const; 268 269 // Remove all partitions belonging to a group, then remove the group. 270 void RemoveGroupAndPartitions(const std::string& group_name); 271 272 // Set the LP_METADATA_AUTO_SLOT_SUFFIXING flag. 273 void SetAutoSlotSuffixing(); 274 275 // If set, checks for slot suffixes will be ignored internally. 276 void IgnoreSlotSuffixing(); 277 278 bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const; 279 bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info); 280 281 // Attempt to preserve the named partitions from an older metadata. If this 282 // is not possible (for example, the block device list has changed) then 283 // false is returned. 284 bool ImportPartitions(const LpMetadata& metadata, const std::set<std::string>& partition_names); 285 286 // Return true if a block device is found, else false. 287 bool HasBlockDevice(const std::string& partition_name) const; 288 289 private: 290 MetadataBuilder(); 291 MetadataBuilder(const MetadataBuilder&) = delete; 292 MetadataBuilder(MetadataBuilder&&) = delete; 293 MetadataBuilder& operator=(const MetadataBuilder&) = delete; 294 MetadataBuilder& operator=(MetadataBuilder&&) = delete; 295 bool Init(const std::vector<BlockDeviceInfo>& block_devices, const std::string& super_partition, 296 uint32_t metadata_max_size, uint32_t metadata_slot_count); 297 bool Init(const LpMetadata& metadata); 298 bool GrowPartition(Partition* partition, uint64_t aligned_size); 299 void ShrinkPartition(Partition* partition, uint64_t aligned_size); 300 uint64_t AlignSector(const LpMetadataBlockDevice& device, uint64_t sector) const; 301 uint64_t TotalSizeOfGroup(PartitionGroup* group) const; 302 bool UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& info); 303 bool FindBlockDeviceByName(const std::string& partition_name, uint32_t* index) const; 304 bool ValidatePartitionSizeChange(Partition* partition, uint64_t old_size, uint64_t new_size, 305 bool force_check); 306 void ImportExtents(Partition* dest, const LpMetadata& metadata, 307 const LpMetadataPartition& source); 308 bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source); 309 bool IsABDevice() const; 310 bool IsRetrofitDevice() const; 311 bool ValidatePartitionGroups() const; 312 313 struct Interval { 314 uint32_t device_index; 315 uint64_t start; 316 uint64_t end; 317 IntervalInterval318 Interval(uint32_t device_index, uint64_t start, uint64_t end) 319 : device_index(device_index), start(start), end(end) {} lengthInterval320 uint64_t length() const { return end - start; } 321 322 // Note: the device index is not included in sorting (intervals are 323 // sorted in per-device lists). 324 bool operator<(const Interval& other) const { 325 return (start == other.start) ? end < other.end : start < other.start; 326 } 327 }; 328 std::vector<Interval> GetFreeRegions() const; 329 bool IsAnyRegionCovered(const std::vector<Interval>& regions, 330 const LinearExtent& candidate) const; 331 bool IsAnyRegionAllocated(const LinearExtent& candidate) const; 332 void ExtentsToFreeList(const std::vector<Interval>& extents, 333 std::vector<Interval>* free_regions) const; 334 std::vector<Interval> PrioritizeSecondHalfOfSuper(const std::vector<Interval>& free_list); 335 std::unique_ptr<LinearExtent> ExtendFinalExtent(Partition* partition, 336 const std::vector<Interval>& free_list, 337 uint64_t sectors_needed) const; 338 339 static bool sABOverrideValue; 340 static bool sABOverrideSet; 341 342 LpMetadataGeometry geometry_; 343 LpMetadataHeader header_; 344 std::vector<std::unique_ptr<Partition>> partitions_; 345 std::vector<std::unique_ptr<PartitionGroup>> groups_; 346 std::vector<LpMetadataBlockDevice> block_devices_; 347 bool auto_slot_suffixing_; 348 bool ignore_slot_suffixing_; 349 }; 350 351 // Read BlockDeviceInfo for a given block device. This always returns false 352 // for non-Linux operating systems. 353 bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info); 354 355 } // namespace fs_mgr 356 } // namespace android 357 358 #endif /* LIBLP_METADATA_BUILDER_H */ 359