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 #include <string_view> 28 29 #include "liblp.h" 30 #include "partition_opener.h" 31 32 namespace android { 33 namespace fs_mgr { 34 35 class LinearExtent; 36 struct Interval; 37 38 // By default, partitions are aligned on a 1MiB boundary. 39 static constexpr uint32_t kDefaultPartitionAlignment = 1024 * 1024; 40 static constexpr uint32_t kDefaultBlockSize = 4096; 41 42 // Name of the default group in a metadata. 43 static constexpr std::string_view kDefaultGroup = "default"; 44 45 enum class ExtentType { 46 kZero, 47 kLinear, 48 }; 49 50 // Abstraction around dm-targets that can be encoded into logical partition tables. 51 class Extent { 52 public: Extent(uint64_t num_sectors)53 explicit Extent(uint64_t num_sectors) : num_sectors_(num_sectors) {} ~Extent()54 virtual ~Extent() {} 55 56 virtual bool AddTo(LpMetadata* out) const = 0; AsLinearExtent()57 virtual LinearExtent* AsLinearExtent() { return nullptr; } 58 virtual ExtentType GetExtentType() const = 0; 59 60 virtual bool operator==(const Extent& other) const = 0; 61 virtual bool operator!=(const Extent& other) const { return !(*this == other); } 62 num_sectors()63 uint64_t num_sectors() const { return num_sectors_; } set_num_sectors(uint64_t num_sectors)64 void set_num_sectors(uint64_t num_sectors) { num_sectors_ = num_sectors; } 65 66 protected: 67 uint64_t num_sectors_; 68 }; 69 70 std::ostream& operator<<(std::ostream& os, const Extent& extent); 71 72 // This corresponds to a dm-linear target. 73 class LinearExtent final : public Extent { 74 public: LinearExtent(uint64_t num_sectors,uint32_t device_index,uint64_t physical_sector)75 LinearExtent(uint64_t num_sectors, uint32_t device_index, uint64_t physical_sector) 76 : Extent(num_sectors), device_index_(device_index), physical_sector_(physical_sector) {} 77 78 bool AddTo(LpMetadata* metadata) const override; AsLinearExtent()79 LinearExtent* AsLinearExtent() override { return this; } GetExtentType()80 ExtentType GetExtentType() const override { return ExtentType::kLinear; } 81 82 bool operator==(const Extent& other) const override; 83 physical_sector()84 uint64_t physical_sector() const { return physical_sector_; } end_sector()85 uint64_t end_sector() const { return physical_sector_ + num_sectors_; } device_index()86 uint32_t device_index() const { return device_index_; } 87 88 bool OverlapsWith(const LinearExtent& other) const; 89 bool OverlapsWith(const Interval& interval) const; 90 91 Interval AsInterval() const; 92 93 private: 94 uint32_t device_index_; 95 uint64_t physical_sector_; 96 }; 97 98 // This corresponds to a dm-zero target. 99 class ZeroExtent final : public Extent { 100 public: ZeroExtent(uint64_t num_sectors)101 explicit ZeroExtent(uint64_t num_sectors) : Extent(num_sectors) {} 102 103 bool AddTo(LpMetadata* out) const override; GetExtentType()104 ExtentType GetExtentType() const override { return ExtentType::kZero; } 105 106 bool operator==(const Extent& other) const override; 107 }; 108 109 class PartitionGroup final { 110 friend class MetadataBuilder; 111 112 public: PartitionGroup(std::string_view name,uint64_t maximum_size)113 explicit PartitionGroup(std::string_view name, uint64_t maximum_size) 114 : name_(name), maximum_size_(maximum_size) {} 115 name()116 const std::string& name() const { return name_; } maximum_size()117 uint64_t maximum_size() const { return maximum_size_; } 118 119 private: set_maximum_size(uint64_t maximum_size)120 void set_maximum_size(uint64_t maximum_size) { maximum_size_ = maximum_size; } 121 122 std::string name_; 123 uint64_t maximum_size_; 124 }; 125 126 class Partition final { 127 friend class MetadataBuilder; 128 129 public: 130 Partition(std::string_view name, std::string_view group_name, uint32_t attributes); 131 132 // Add a raw extent. 133 void AddExtent(std::unique_ptr<Extent>&& extent); 134 135 // Remove all extents from this partition. 136 void RemoveExtents(); 137 138 // Compute the size used by linear extents. This is the same as size(), 139 // but does not factor in extents which do not take up space. 140 uint64_t BytesOnDisk() const; 141 name()142 const std::string& name() const { return name_; } group_name()143 const std::string& group_name() const { return group_name_; } attributes()144 uint32_t attributes() const { return attributes_; } set_attributes(uint32_t attributes)145 void set_attributes(uint32_t attributes) { attributes_ = attributes; } extents()146 const std::vector<std::unique_ptr<Extent>>& extents() const { return extents_; } size()147 uint64_t size() const { return size_; } 148 149 // Return a copy of *this, but with extents that includes only the first 150 // |aligned_size| bytes. |aligned_size| should be aligned to 151 // logical_block_size() of the MetadataBuilder that this partition belongs 152 // to. 153 Partition GetBeginningExtents(uint64_t aligned_size) const; 154 155 private: 156 void ShrinkTo(uint64_t aligned_size); set_group_name(std::string_view group_name)157 void set_group_name(std::string_view group_name) { group_name_ = group_name; } 158 159 std::string name_; 160 std::string group_name_; 161 std::vector<std::unique_ptr<Extent>> extents_; 162 uint32_t attributes_; 163 uint64_t size_; 164 }; 165 166 // An interval in the metadata. This is similar to a LinearExtent with one difference. 167 // LinearExtent represents a "used" region in the metadata, while Interval can also represent 168 // an "unused" region. 169 struct Interval { 170 uint32_t device_index; 171 uint64_t start; 172 uint64_t end; 173 IntervalInterval174 Interval(uint32_t device_index, uint64_t start, uint64_t end) 175 : device_index(device_index), start(start), end(end) {} lengthInterval176 uint64_t length() const { return end - start; } 177 178 // Note: the device index is not included in sorting (intervals are 179 // sorted in per-device lists). 180 bool operator<(const Interval& other) const { 181 return (start == other.start) ? end < other.end : start < other.start; 182 } 183 184 std::unique_ptr<Extent> AsExtent() const; 185 186 // Intersect |a| with |b|. 187 // If no intersection, result has 0 length(). 188 static Interval Intersect(const Interval& a, const Interval& b); 189 190 // Intersect two lists of intervals, and store result to |a|. 191 static std::vector<Interval> Intersect(const std::vector<Interval>& a, 192 const std::vector<Interval>& b); 193 }; 194 195 class MetadataBuilder { 196 public: 197 // Construct an empty logical partition table builder given the specified 198 // map of partitions that are available for storing logical partitions. 199 // 200 // At least one partition in the list must be the "super" device, where 201 // metadata will be stored. 202 // 203 // If the parameters would yield invalid metadata, nullptr is returned. This 204 // could happen if the super device is too small to store all required 205 // metadata. 206 static std::unique_ptr<MetadataBuilder> New(const std::vector<BlockDeviceInfo>& block_devices, 207 const std::string& super_partition, 208 uint32_t metadata_max_size, 209 uint32_t metadata_slot_count); 210 211 // Import an existing table for modification. This reads metadata off the 212 // given block device and imports it. It also adjusts alignment information 213 // based on run-time values in the operating system. 214 static std::unique_ptr<MetadataBuilder> New(const IPartitionOpener& opener, 215 const std::string& super_partition, 216 uint32_t slot_number); 217 218 // Same as above, but use the default PartitionOpener. 219 static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition, 220 uint32_t slot_number); 221 222 // This is when performing an A/B update. The source partition must be a 223 // super partition. On a normal device, the metadata for the source slot 224 // is imported and the target slot is ignored. On a retrofit device, the 225 // metadata may not have the target slot's devices listed yet, in which 226 // case, it is automatically upgraded to include all available block 227 // devices. 228 // If |always_keep_source_slot| is set, on a Virtual A/B device 229 // - source slot partitions are kept. 230 // - UPDATED flag is cleared. 231 // This is useful when applying a downgrade package. 232 static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener, 233 const std::string& source_partition, 234 uint32_t source_slot_number, 235 uint32_t target_slot_number, 236 bool always_keep_source_slot = false); 237 238 // Import an existing table for modification. If the table is not valid, for 239 // example it contains duplicate partition names, then nullptr is returned. 240 // 241 // If an IPartitionOpener is specified, then block device informatiom will 242 // be updated. 243 static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata, 244 const IPartitionOpener* opener = nullptr); 245 246 // Helper function for a single super partition, for tests. New(const BlockDeviceInfo & device_info,uint32_t metadata_max_size,uint32_t metadata_slot_count)247 static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info, 248 uint32_t metadata_max_size, 249 uint32_t metadata_slot_count) { 250 return New({device_info}, device_info.partition_name, metadata_max_size, 251 metadata_slot_count); 252 } 253 254 // Wrapper around New() with a BlockDeviceInfo that only specifies a device 255 // size. This is a convenience method for tests. New(uint64_t blockdev_size,uint32_t metadata_max_size,uint32_t metadata_slot_count)256 static std::unique_ptr<MetadataBuilder> New(uint64_t blockdev_size, uint32_t metadata_max_size, 257 uint32_t metadata_slot_count) { 258 BlockDeviceInfo device_info(LP_METADATA_DEFAULT_PARTITION_NAME, blockdev_size, 0, 0, 259 kDefaultBlockSize); 260 return New(device_info, metadata_max_size, metadata_slot_count); 261 } 262 263 // Verifies that the given partitions in the metadata have the same extents as the source 264 // metadata. 265 static bool VerifyExtentsAgainstSourceMetadata(const MetadataBuilder& source_metadata, 266 uint32_t source_slot_number, 267 const MetadataBuilder& target_metadata, 268 uint32_t target_slot_number, 269 const std::vector<std::string>& partitions); 270 271 // Define a new partition group. By default there is one group called 272 // "default", with an unrestricted size. A non-zero size will restrict the 273 // total space used by all partitions in the group. 274 // 275 // This can fail and return false if the group already exists. 276 bool AddGroup(std::string_view group_name, uint64_t maximum_size); 277 278 // Export metadata so it can be serialized to an image, to disk, or mounted 279 // via device-mapper. 280 std::unique_ptr<LpMetadata> Export(); 281 282 // Add a partition, returning a handle so it can be sized as needed. If a 283 // partition with the given name already exists, nullptr is returned. 284 Partition* AddPartition(std::string_view name, std::string_view group_name, 285 uint32_t attributes); 286 287 // Same as AddPartition above, but uses the default partition group which 288 // has no size restrictions. 289 Partition* AddPartition(const std::string& name, uint32_t attributes); 290 291 // Delete a partition by name if it exists. 292 void RemovePartition(std::string_view name); 293 294 // Find a partition by name. If no partition is found, nullptr is returned. 295 Partition* FindPartition(std::string_view name) const; 296 297 // Find a group by name. If no group is found, nullptr is returned. 298 PartitionGroup* FindGroup(std::string_view name) const; 299 300 // Add a predetermined extent to a partition. 301 bool AddLinearExtent(Partition* partition, const std::string& block_device, 302 uint64_t num_sectors, uint64_t physical_sector); 303 304 // Grow or shrink a partition to the requested size. This size will be 305 // rounded UP to the nearest block (512 bytes). 306 // 307 // When growing a partition, a greedy algorithm is used to find free gaps 308 // in the partition table and allocate them. If not enough space can be 309 // allocated, false is returned, and the parition table will not be 310 // modified. 311 // 312 // Note, this is an in-memory operation, and it does not alter the 313 // underlying filesystem or contents of the partition on disk. 314 // 315 // If |free_region_hint| is not empty, it will only try to allocate extents 316 // in regions within the list. 317 bool ResizePartition(Partition* partition, uint64_t requested_size, 318 const std::vector<Interval>& free_region_hint = {}); 319 320 // Return the list of partitions belonging to a group. 321 std::vector<Partition*> ListPartitionsInGroup(std::string_view group_name); 322 323 // Changes a partition's group. Size constraints will not be checked until 324 // the metadata is exported, to avoid errors during potential group and 325 // size shuffling operations. This will return false if the new group does 326 // not exist. 327 bool ChangePartitionGroup(Partition* partition, std::string_view group_name); 328 329 // Changes the size of a partition group. Size constraints will not be 330 // checked until metadata is exported, to avoid errors during group 331 // reshuffling. This will return false if the group does not exist, or if 332 // the group name is "default". 333 bool ChangeGroupSize(const std::string& group_name, uint64_t maximum_size); 334 335 // Amount of space that can be allocated to logical partitions. 336 uint64_t AllocatableSpace() const; 337 uint64_t UsedSpace() const; 338 339 // Return a list of all group names. 340 std::vector<std::string> ListGroups() const; 341 342 // Remove all partitions belonging to a group, then remove the group. 343 void RemoveGroupAndPartitions(std::string_view group_name); 344 345 // Set the LP_METADATA_AUTO_SLOT_SUFFIXING flag. 346 void SetAutoSlotSuffixing(); 347 // Set the LP_HEADER_FLAG_VIRTUAL_AB_DEVICE flag. 348 void SetVirtualABDeviceFlag(); 349 350 bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const; 351 bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info); 352 353 // Require the expanded metadata header. This is exposed for testing, and 354 // is normally only called as needed by other methods. 355 void RequireExpandedMetadataHeader(); 356 357 // Attempt to preserve the named partitions from an older metadata. If this 358 // is not possible (for example, the block device list has changed) then 359 // false is returned. 360 bool ImportPartitions(const LpMetadata& metadata, const std::set<std::string>& partition_names); 361 362 // Return true if a block device is found, else false. 363 bool HasBlockDevice(const std::string& partition_name) const; 364 365 // Return the name of the block device at |index|. 366 std::string GetBlockDevicePartitionName(uint64_t index) const; 367 368 // Return the list of free regions not occupied by extents in the metadata. 369 std::vector<Interval> GetFreeRegions() const; 370 371 uint64_t logical_block_size() const; 372 373 private: 374 MetadataBuilder(); 375 MetadataBuilder(const MetadataBuilder&) = delete; 376 MetadataBuilder(MetadataBuilder&&) = delete; 377 MetadataBuilder& operator=(const MetadataBuilder&) = delete; 378 MetadataBuilder& operator=(MetadataBuilder&&) = delete; 379 bool Init(const std::vector<BlockDeviceInfo>& block_devices, const std::string& super_partition, 380 uint32_t metadata_max_size, uint32_t metadata_slot_count); 381 bool Init(const LpMetadata& metadata); 382 bool GrowPartition(Partition* partition, uint64_t aligned_size, 383 const std::vector<Interval>& free_region_hint); 384 void ShrinkPartition(Partition* partition, uint64_t aligned_size); 385 bool AlignSector(const LpMetadataBlockDevice& device, uint64_t sector, uint64_t* out) const; 386 uint64_t TotalSizeOfGroup(PartitionGroup* group) const; 387 bool UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& info); 388 bool FindBlockDeviceByName(const std::string& partition_name, uint32_t* index) const; 389 bool ValidatePartitionSizeChange(Partition* partition, uint64_t old_size, uint64_t new_size, 390 bool force_check); 391 void ImportExtents(Partition* dest, const LpMetadata& metadata, 392 const LpMetadataPartition& source); 393 bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source); 394 395 // Return true if the device is an AB device. 396 static bool IsABDevice(); 397 398 // Return true if the device is retrofitting dynamic partitions. 399 static bool IsRetrofitDynamicPartitionsDevice(); 400 401 // Return true if _b partitions should be prioritized at the second half of the device. 402 bool ShouldHalveSuper() const; 403 404 bool ValidatePartitionGroups() const; 405 406 bool IsAnyRegionCovered(const std::vector<Interval>& regions, 407 const LinearExtent& candidate) const; 408 bool IsAnyRegionAllocated(const LinearExtent& candidate) const; 409 void ExtentsToFreeList(const std::vector<Interval>& extents, 410 std::vector<Interval>* free_regions) const; 411 std::vector<Interval> PrioritizeSecondHalfOfSuper(const std::vector<Interval>& free_list); 412 std::unique_ptr<LinearExtent> ExtendFinalExtent(Partition* partition, 413 const std::vector<Interval>& free_list, 414 uint64_t sectors_needed) const; 415 416 static bool UpdateMetadataForOtherSuper(LpMetadata* metadata, uint32_t source_slot_number, 417 uint32_t target_slot_number); 418 419 LpMetadataGeometry geometry_; 420 LpMetadataHeader header_; 421 std::vector<std::unique_ptr<Partition>> partitions_; 422 std::vector<std::unique_ptr<PartitionGroup>> groups_; 423 std::vector<LpMetadataBlockDevice> block_devices_; 424 bool auto_slot_suffixing_; 425 }; 426 427 // Read BlockDeviceInfo for a given block device. This always returns false 428 // for non-Linux operating systems. 429 bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info); 430 431 } // namespace fs_mgr 432 } // namespace android 433 434 #endif /* LIBLP_METADATA_BUILDER_H */ 435