• 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 
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