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