123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- /* SPDX-License-Identifier: GPL-2.0 */
- /*
- * Copyright 2018 Google LLC
- */
- /*
- * Overview
- * --------
- * The backbone of the incremental-fs ondisk format is an append only linked
- * list of metadata blocks. Each metadata block contains an offset of the next
- * one. These blocks describe files and directories on the
- * file system. They also represent actions of adding and removing file names
- * (hard links).
- *
- * Every time incremental-fs instance is mounted, it reads through this list
- * to recreate filesystem's state in memory. An offset of the first record in
- * the metadata list is stored in the superblock at the beginning of the backing
- * file.
- *
- * Most of the backing file is taken by data areas and blockmaps.
- * Since data blocks can be compressed and have different sizes,
- * single per-file data area can't be pre-allocated. That's why blockmaps are
- * needed in order to find a location and size of each data block in
- * the backing file. Each time a file is created, a corresponding block map is
- * allocated to store future offsets of data blocks.
- *
- * Whenever a data block is given by data loader to incremental-fs:
- * - A data area with the given block is appended to the end of
- * the backing file.
- * - A record in the blockmap for the given block index is updated to reflect
- * its location, size, and compression algorithm.
- * Metadata records
- * ----------------
- * incfs_blockmap - metadata record that specifies size and location
- * of a blockmap area for a given file. This area
- * contains an array of incfs_blockmap_entry-s.
- * incfs_file_signature - metadata record that specifies where file signature
- * and its hash tree can be found in the backing file.
- *
- * incfs_file_attr - metadata record that specifies where additional file
- * attributes blob can be found.
- *
- * Metadata header
- * ---------------
- * incfs_md_header - header of a metadata record. It's always a part
- * of other structures and served purpose of metadata
- * bookkeeping.
- *
- * +-----------------------------------------------+ ^
- * | incfs_md_header | |
- * | 1. type of body(BLOCKMAP, FILE_ATTR..) | |
- * | 2. size of the whole record header + body | |
- * | 3. CRC the whole record header + body | |
- * | 4. offset of the previous md record |]------+
- * | 5. offset of the next md record (md link) |]---+
- * +-----------------------------------------------+ |
- * | Metadata record body with useful data | |
- * +-----------------------------------------------+ |
- * +--->
- *
- * Other ondisk structures
- * -----------------------
- * incfs_super_block - backing file header
- * incfs_blockmap_entry - a record in a blockmap area that describes size
- * and location of a data block.
- * Data blocks dont have any particular structure, they are written to the
- * backing file in a raw form as they come from a data loader.
- *
- * Backing file layout
- * -------------------
- *
- *
- * +-------------------------------------------+
- * | incfs_file_header |]---+
- * +-------------------------------------------+ |
- * | metadata |<---+
- * | incfs_file_signature |]---+
- * +-------------------------------------------+ |
- * ......................... |
- * +-------------------------------------------+ | metadata
- * +------->| blockmap area | | list links
- * | | [incfs_blockmap_entry] | |
- * | | [incfs_blockmap_entry] | |
- * | | [incfs_blockmap_entry] | |
- * | +--[| [incfs_blockmap_entry] | |
- * | | | [incfs_blockmap_entry] | |
- * | | | [incfs_blockmap_entry] | |
- * | | +-------------------------------------------+ |
- * | | ......................... |
- * | | +-------------------------------------------+ |
- * | | | metadata |<---+
- * +----|--[| incfs_blockmap |]---+
- * | +-------------------------------------------+ |
- * | ......................... |
- * | +-------------------------------------------+ |
- * +-->| data block | |
- * +-------------------------------------------+ |
- * ......................... |
- * +-------------------------------------------+ |
- * | metadata |<---+
- * | incfs_file_attr |
- * +-------------------------------------------+
- */
- #ifndef _INCFS_FORMAT_H
- #define _INCFS_FORMAT_H
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <uapi/linux/incrementalfs.h>
- #include "internal.h"
- #define INCFS_MAX_NAME_LEN 255
- #define INCFS_FORMAT_V1 1
- #define INCFS_FORMAT_CURRENT_VER INCFS_FORMAT_V1
- enum incfs_metadata_type {
- INCFS_MD_NONE = 0,
- INCFS_MD_BLOCK_MAP = 1,
- INCFS_MD_FILE_ATTR = 2,
- INCFS_MD_SIGNATURE = 3,
- INCFS_MD_STATUS = 4,
- INCFS_MD_VERITY_SIGNATURE = 5,
- };
- enum incfs_file_header_flags {
- INCFS_FILE_MAPPED = 1 << 1,
- };
- /* Header included at the beginning of all metadata records on the disk. */
- struct incfs_md_header {
- __u8 h_md_entry_type;
- /*
- * Size of the metadata record.
- * (e.g. inode, dir entry etc) not just this struct.
- */
- __le16 h_record_size;
- /*
- * Was: CRC32 of the metadata record.
- * (e.g. inode, dir entry etc) not just this struct.
- */
- __le32 h_unused1;
- /* Offset of the next metadata entry if any */
- __le64 h_next_md_offset;
- /* Was: Offset of the previous metadata entry if any */
- __le64 h_unused2;
- } __packed;
- /* Backing file header */
- struct incfs_file_header {
- /* Magic number: INCFS_MAGIC_NUMBER */
- __le64 fh_magic;
- /* Format version: INCFS_FORMAT_CURRENT_VER */
- __le64 fh_version;
- /* sizeof(incfs_file_header) */
- __le16 fh_header_size;
- /* INCFS_DATA_FILE_BLOCK_SIZE */
- __le16 fh_data_block_size;
- /* File flags, from incfs_file_header_flags */
- __le32 fh_flags;
- union {
- /* Standard incfs file */
- struct {
- /* Offset of the first metadata record */
- __le64 fh_first_md_offset;
- /* Full size of the file's content */
- __le64 fh_file_size;
- /* File uuid */
- incfs_uuid_t fh_uuid;
- };
- /* Mapped file - INCFS_FILE_MAPPED set in fh_flags */
- struct {
- /* Offset in original file */
- __le64 fh_original_offset;
- /* Full size of the file's content */
- __le64 fh_mapped_file_size;
- /* Original file's uuid */
- incfs_uuid_t fh_original_uuid;
- };
- };
- } __packed;
- enum incfs_block_map_entry_flags {
- INCFS_BLOCK_COMPRESSED_LZ4 = 1,
- INCFS_BLOCK_COMPRESSED_ZSTD = 2,
- /* Reserve 3 bits for compression alg */
- INCFS_BLOCK_COMPRESSED_MASK = 7,
- };
- /* Block map entry pointing to an actual location of the data block. */
- struct incfs_blockmap_entry {
- /* Offset of the actual data block. Lower 32 bits */
- __le32 me_data_offset_lo;
- /* Offset of the actual data block. Higher 16 bits */
- __le16 me_data_offset_hi;
- /* How many bytes the data actually occupies in the backing file */
- __le16 me_data_size;
- /* Block flags from incfs_block_map_entry_flags */
- __le16 me_flags;
- } __packed;
- /* Metadata record for locations of file blocks. Type = INCFS_MD_BLOCK_MAP */
- struct incfs_blockmap {
- struct incfs_md_header m_header;
- /* Base offset of the array of incfs_blockmap_entry */
- __le64 m_base_offset;
- /* Size of the map entry array in blocks */
- __le32 m_block_count;
- } __packed;
- /*
- * Metadata record for file signature. Type = INCFS_MD_SIGNATURE
- *
- * The signature stored here is the APK V4 signature data blob. See the
- * definition of incfs_new_file_args::signature_info for an explanation of this
- * blob. Specifically, it contains the root hash, but it does *not* contain
- * anything that the kernel treats as a signature.
- *
- * When FS_IOC_ENABLE_VERITY is called on a file without this record, an APK V4
- * signature blob and a hash tree are added to the file, and then this metadata
- * record is created to record their locations.
- */
- struct incfs_file_signature {
- struct incfs_md_header sg_header;
- __le32 sg_sig_size; /* The size of the signature. */
- __le64 sg_sig_offset; /* Signature's offset in the backing file */
- __le32 sg_hash_tree_size; /* The size of the hash tree. */
- __le64 sg_hash_tree_offset; /* Hash tree offset in the backing file */
- } __packed;
- /* In memory version of above */
- struct incfs_df_signature {
- u32 sig_size;
- u64 sig_offset;
- u32 hash_size;
- u64 hash_offset;
- };
- struct incfs_status {
- struct incfs_md_header is_header;
- __le32 is_data_blocks_written; /* Number of data blocks written */
- __le32 is_hash_blocks_written; /* Number of hash blocks written */
- __le32 is_dummy[6]; /* Spare fields */
- } __packed;
- /*
- * Metadata record for verity signature. Type = INCFS_MD_VERITY_SIGNATURE
- *
- * This record will only exist for verity-enabled files with signatures. Verity
- * enabled files without signatures do not have this record. This signature is
- * checked by fs-verity identically to any other fs-verity signature.
- */
- struct incfs_file_verity_signature {
- struct incfs_md_header vs_header;
- /* The size of the signature */
- __le32 vs_size;
- /* Signature's offset in the backing file */
- __le64 vs_offset;
- } __packed;
- /* In memory version of above */
- struct incfs_df_verity_signature {
- u32 size;
- u64 offset;
- };
- /* State of the backing file. */
- struct backing_file_context {
- /* Protects writes to bc_file */
- struct mutex bc_mutex;
- /* File object to read data from */
- struct file *bc_file;
- /*
- * Offset of the last known metadata record in the backing file.
- * 0 means there are no metadata records.
- */
- loff_t bc_last_md_record_offset;
- /*
- * Credentials to set before reads/writes
- * Note that this is a pointer to the mount_info mi_owner field so
- * there is no need to get/put the creds
- */
- const struct cred *bc_cred;
- };
- struct metadata_handler {
- loff_t md_record_offset;
- loff_t md_prev_record_offset;
- void *context;
- union {
- struct incfs_md_header md_header;
- struct incfs_blockmap blockmap;
- struct incfs_file_signature signature;
- struct incfs_status status;
- struct incfs_file_verity_signature verity_signature;
- } md_buffer;
- int (*handle_blockmap)(struct incfs_blockmap *bm,
- struct metadata_handler *handler);
- int (*handle_signature)(struct incfs_file_signature *sig,
- struct metadata_handler *handler);
- int (*handle_status)(struct incfs_status *sig,
- struct metadata_handler *handler);
- int (*handle_verity_signature)(struct incfs_file_verity_signature *s,
- struct metadata_handler *handler);
- };
- #define INCFS_MAX_METADATA_RECORD_SIZE \
- sizeof_field(struct metadata_handler, md_buffer)
- /* Backing file context management */
- struct mount_info;
- struct backing_file_context *incfs_alloc_bfc(struct mount_info *mi,
- struct file *backing_file);
- void incfs_free_bfc(struct backing_file_context *bfc);
- /* Writing stuff */
- int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc,
- u32 block_count);
- int incfs_write_fh_to_backing_file(struct backing_file_context *bfc,
- incfs_uuid_t *uuid, u64 file_size);
- int incfs_write_mapping_fh_to_backing_file(struct backing_file_context *bfc,
- incfs_uuid_t *uuid, u64 file_size, u64 offset);
- int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc,
- struct mem_range block,
- int block_index, loff_t bm_base_off,
- u16 flags);
- int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc,
- struct mem_range block,
- int block_index,
- loff_t hash_area_off,
- loff_t bm_base_off,
- loff_t file_size);
- int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
- struct mem_range sig, u32 tree_size,
- loff_t *tree_offset, loff_t *sig_offset);
- int incfs_write_status_to_backing_file(struct backing_file_context *bfc,
- loff_t status_offset,
- u32 data_blocks_written,
- u32 hash_blocks_written);
- int incfs_write_verity_signature_to_backing_file(
- struct backing_file_context *bfc, struct mem_range signature,
- loff_t *offset);
- /* Reading stuff */
- int incfs_read_file_header(struct backing_file_context *bfc,
- loff_t *first_md_off, incfs_uuid_t *uuid,
- u64 *file_size, u32 *flags);
- int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index,
- loff_t bm_base_off,
- struct incfs_blockmap_entry *bm_entry);
- int incfs_read_blockmap_entries(struct backing_file_context *bfc,
- struct incfs_blockmap_entry *entries,
- int start_index, int blocks_number,
- loff_t bm_base_off);
- int incfs_read_next_metadata_record(struct backing_file_context *bfc,
- struct metadata_handler *handler);
- ssize_t incfs_kread(struct backing_file_context *bfc, void *buf, size_t size,
- loff_t pos);
- ssize_t incfs_kwrite(struct backing_file_context *bfc, const void *buf,
- size_t size, loff_t pos);
- #endif /* _INCFS_FORMAT_H */
|