| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_STORAGE_FVM_METADATA_H_ |
| #define SRC_STORAGE_FVM_METADATA_H_ |
| |
| #include <lib/zx/status.h> |
| #include <zircon/types.h> |
| |
| #include <limits> |
| |
| #include "src/storage/fvm/format.h" |
| #include "src/storage/fvm/metadata_buffer.h" |
| |
| namespace fvm { |
| |
| // Metadata is an in-memory representation of the metadata for an FVM image. |
| // |
| // At construction, |Metadata| objects are well-formed, since they validate the underlying metadata |
| // when first created by |Metadata::Create| or |Metadata::Synthesize|. Subsequent updates by clients |
| // can, of course, corrupt the metadata. |
| // |
| // This class owns the underlying buffer (see |MetadataBuffer)|. |
| // |
| // This class is not thread-safe. |
| class Metadata { |
| public: |
| // Constructs a default, uninitialized instance. |
| Metadata() = default; |
| Metadata(const Metadata&) = delete; |
| Metadata& operator=(const Metadata&) = delete; |
| Metadata(Metadata&&) noexcept; |
| Metadata& operator=(Metadata&&) noexcept; |
| |
| // Returns the minimum number of bytes needed for a |MetadataBuffer| object to back FVM metadata |
| // described by |header|. |
| static size_t BytesNeeded(const Header& header); |
| |
| // Attempts to parse the FVM metadata stored at |data_a| and |data_b|, picking the latest copy. |
| // The copy with the latest generation (that is also valid) will be retained; the other is |
| // discarded. |
| // Returns a |Metadata| instance over the passed metadata on success, or a failure if neither was |
| // valid. |
| static zx::status<Metadata> Create(std::unique_ptr<MetadataBuffer> data_a, |
| std::unique_ptr<MetadataBuffer> data_b); |
| |
| // Override of |Create| that allows specifying disk dimensions; the sizes of each metadata copy |
| // will be checked against these sizes (see |::fvm::PickValidHeader|) and only deemed valid if |
| // they fit within the disk. |
| static zx::status<Metadata> Create(size_t disk_size, size_t disk_block_size, |
| std::unique_ptr<MetadataBuffer> data_a, |
| std::unique_ptr<MetadataBuffer> data_b); |
| |
| // Creates an instance of |Metadata|, initialized by copying the contents of |header|, |
| // |partitions| and |slices|. |
| // All of the passed metadata is copied into both the A and B slots. Any additional partitions |
| // and slices in the tables past |partitions| and |slices| are default-initialized. |
| // The passed |header| must be configured appropriately to manage tables at least as big as |
| // |num_partitions| and |num_slices| respectively. If not, an error is returned. |
| static zx::status<Metadata> Synthesize(const fvm::Header& header, |
| const VPartitionEntry* partitions, size_t num_partitions, |
| const SliceEntry* slices, size_t num_slices); |
| |
| // Checks the validity of the metadata. The underlying device's information is passed in, see |
| // fvm::Header::IsValid(). The defaults for the disk information skips validation of the metadata |
| // relative to these values. |
| // |
| // Should be called before serializing the contents to disk. |
| bool CheckValidity(uint64_t disk_size = std::numeric_limits<uint64_t>::max(), |
| uint64_t disk_block_size = kBlockSize) const; |
| |
| // Updates the hash stored in the metadata, based on its contents. |
| void UpdateHash(); |
| |
| // Returns the disk offset where the metadata should be persisted. This points to the |
| // offset of the *inactive* copy (see |inactive_header()|). |
| size_t GetInactiveHeaderOffset() const; |
| |
| // Returns whether the Metadata represents an active A copy or B copy. |
| SuperblockType active_header() const { return active_header_; } |
| SuperblockType inactive_header() const { return OppositeHeader(active_header_); } |
| |
| // Switches whether the Metadata represents an active A or B copy. |
| void SwitchActiveHeaders(); |
| |
| // Accesses the header managed by the Metadata instance. |
| Header& GetHeader() const; |
| |
| // Accesses the partition table. Note that |idx| is one-based. |
| VPartitionEntry& GetPartitionEntry(unsigned idx) const; |
| |
| // Accesses the allocation table. Note that |idx| is one-based. |
| SliceEntry& GetSliceEntry(unsigned idx) const; |
| |
| // Gets a view of the raw metadata buffer. |
| const MetadataBuffer* Get() const; |
| |
| // Creates a copy of this Metadata instance, with additional room described by |dimensions|. |
| // The metadata is not copied verbatim; for instance, which of the A/B copies is active |
| // may change, and old generations may be lost. The only guarantee is that all partition/slice |
| // entries in the active tables will be copied over from this instance. |
| // TODO(jfsulliv): Only fvm/host needs this method, and it is not very graceful. Consider removal. |
| zx::status<Metadata> CopyWithNewDimensions(const Header& dimensions) const; |
| |
| private: |
| Metadata(std::unique_ptr<MetadataBuffer> data, SuperblockType active_header); |
| |
| constexpr static SuperblockType OppositeHeader(SuperblockType type) { |
| switch (type) { |
| case SuperblockType::kPrimary: |
| return SuperblockType::kSecondary; |
| case SuperblockType::kSecondary: |
| return SuperblockType::kPrimary; |
| } |
| } |
| |
| void MoveFrom(Metadata&& o); |
| |
| size_t MetadataOffset(SuperblockType type) const; |
| |
| std::unique_ptr<MetadataBuffer> data_; |
| SuperblockType active_header_{SuperblockType::kPrimary}; |
| }; |
| |
| } // namespace fvm |
| |
| #endif // SRC_STORAGE_FVM_METADATA_H_ |