blob: 1b9231b8bfd59fe505d3d9fc2fbbf448607fdf61 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright 2018 Google LLC
4 */
5
6/*
7 * Overview
8 * --------
9 * The backbone of the incremental-fs ondisk format is an append only linked
10 * list of metadata blocks. Each metadata block contains an offset of the next
11 * one. These blocks describe files and directories on the
12 * file system. They also represent actions of adding and removing file names
13 * (hard links).
14 *
15 * Every time incremental-fs instance is mounted, it reads through this list
16 * to recreate filesystem's state in memory. An offset of the first record in
17 * the metadata list is stored in the superblock at the beginning of the backing
18 * file.
19 *
20 * Most of the backing file is taken by data areas and blockmaps.
21 * Since data blocks can be compressed and have different sizes,
22 * single per-file data area can't be pre-allocated. That's why blockmaps are
23 * needed in order to find a location and size of each data block in
24 * the backing file. Each time a file is created, a corresponding block map is
25 * allocated to store future offsets of data blocks.
26 *
27 * Whenever a data block is given by data loader to incremental-fs:
28 * - A data area with the given block is appended to the end of
29 * the backing file.
30 * - A record in the blockmap for the given block index is updated to reflect
31 * its location, size, and compression algorithm.
32
33 * Metadata records
34 * ----------------
35 * incfs_blockmap - metadata record that specifies size and location
36 * of a blockmap area for a given file. This area
37 * contains an array of incfs_blockmap_entry-s.
38 * incfs_file_signature - metadata record that specifies where file signature
39 * and its hash tree can be found in the backing file.
40 *
41 * incfs_file_attr - metadata record that specifies where additional file
42 * attributes blob can be found.
43 *
44 * Metadata header
45 * ---------------
46 * incfs_md_header - header of a metadata record. It's always a part
47 * of other structures and served purpose of metadata
48 * bookkeeping.
49 *
50 * +-----------------------------------------------+ ^
51 * | incfs_md_header | |
52 * | 1. type of body(BLOCKMAP, FILE_ATTR..) | |
53 * | 2. size of the whole record header + body | |
54 * | 3. CRC the whole record header + body | |
55 * | 4. offset of the previous md record |]------+
56 * | 5. offset of the next md record (md link) |]---+
57 * +-----------------------------------------------+ |
58 * | Metadata record body with useful data | |
59 * +-----------------------------------------------+ |
60 * +--->
61 *
62 * Other ondisk structures
63 * -----------------------
64 * incfs_super_block - backing file header
65 * incfs_blockmap_entry - a record in a blockmap area that describes size
66 * and location of a data block.
67 * Data blocks dont have any particular structure, they are written to the
68 * backing file in a raw form as they come from a data loader.
69 *
70 * Backing file layout
71 * -------------------
72 *
73 *
74 * +-------------------------------------------+
75 * | incfs_file_header |]---+
76 * +-------------------------------------------+ |
77 * | metadata |<---+
78 * | incfs_file_signature |]---+
79 * +-------------------------------------------+ |
80 * ......................... |
81 * +-------------------------------------------+ | metadata
82 * +------->| blockmap area | | list links
83 * | | [incfs_blockmap_entry] | |
84 * | | [incfs_blockmap_entry] | |
85 * | | [incfs_blockmap_entry] | |
86 * | +--[| [incfs_blockmap_entry] | |
87 * | | | [incfs_blockmap_entry] | |
88 * | | | [incfs_blockmap_entry] | |
89 * | | +-------------------------------------------+ |
90 * | | ......................... |
91 * | | +-------------------------------------------+ |
92 * | | | metadata |<---+
93 * +----|--[| incfs_blockmap |]---+
94 * | +-------------------------------------------+ |
95 * | ......................... |
96 * | +-------------------------------------------+ |
97 * +-->| data block | |
98 * +-------------------------------------------+ |
99 * ......................... |
100 * +-------------------------------------------+ |
101 * | metadata |<---+
102 * | incfs_file_attr |
103 * +-------------------------------------------+
104 */
105#ifndef _INCFS_FORMAT_H
106#define _INCFS_FORMAT_H
107#include <linux/types.h>
108#include <linux/kernel.h>
109#include <uapi/linux/incrementalfs.h>
110
111#include "internal.h"
112
113#define INCFS_MAX_NAME_LEN 255
114#define INCFS_FORMAT_V1 1
115#define INCFS_FORMAT_CURRENT_VER INCFS_FORMAT_V1
116
117enum incfs_metadata_type {
118 INCFS_MD_NONE = 0,
119 INCFS_MD_BLOCK_MAP = 1,
120 INCFS_MD_FILE_ATTR = 2,
121 INCFS_MD_SIGNATURE = 3,
122 INCFS_MD_STATUS = 4,
123 INCFS_MD_VERITY_SIGNATURE = 5,
124};
125
126enum incfs_file_header_flags {
127 INCFS_FILE_MAPPED = 1 << 1,
128};
129
130/* Header included at the beginning of all metadata records on the disk. */
131struct incfs_md_header {
132 __u8 h_md_entry_type;
133
134 /*
135 * Size of the metadata record.
136 * (e.g. inode, dir entry etc) not just this struct.
137 */
138 __le16 h_record_size;
139
140 /*
141 * Was: CRC32 of the metadata record.
142 * (e.g. inode, dir entry etc) not just this struct.
143 */
144 __le32 h_unused1;
145
146 /* Offset of the next metadata entry if any */
147 __le64 h_next_md_offset;
148
149 /* Was: Offset of the previous metadata entry if any */
150 __le64 h_unused2;
151
152} __packed;
153
154/* Backing file header */
155struct incfs_file_header {
156 /* Magic number: INCFS_MAGIC_NUMBER */
157 __le64 fh_magic;
158
159 /* Format version: INCFS_FORMAT_CURRENT_VER */
160 __le64 fh_version;
161
162 /* sizeof(incfs_file_header) */
163 __le16 fh_header_size;
164
165 /* INCFS_DATA_FILE_BLOCK_SIZE */
166 __le16 fh_data_block_size;
167
168 /* File flags, from incfs_file_header_flags */
169 __le32 fh_flags;
170
171 union {
172 /* Standard incfs file */
173 struct {
174 /* Offset of the first metadata record */
175 __le64 fh_first_md_offset;
176
177 /* Full size of the file's content */
178 __le64 fh_file_size;
179
180 /* File uuid */
181 incfs_uuid_t fh_uuid;
182 };
183
184 /* Mapped file - INCFS_FILE_MAPPED set in fh_flags */
185 struct {
186 /* Offset in original file */
187 __le64 fh_original_offset;
188
189 /* Full size of the file's content */
190 __le64 fh_mapped_file_size;
191
192 /* Original file's uuid */
193 incfs_uuid_t fh_original_uuid;
194 };
195 };
196} __packed;
197
198enum incfs_block_map_entry_flags {
199 INCFS_BLOCK_COMPRESSED_LZ4 = 1,
200 INCFS_BLOCK_COMPRESSED_ZSTD = 2,
201
202 /* Reserve 3 bits for compression alg */
203 INCFS_BLOCK_COMPRESSED_MASK = 7,
204};
205
206/* Block map entry pointing to an actual location of the data block. */
207struct incfs_blockmap_entry {
208 /* Offset of the actual data block. Lower 32 bits */
209 __le32 me_data_offset_lo;
210
211 /* Offset of the actual data block. Higher 16 bits */
212 __le16 me_data_offset_hi;
213
214 /* How many bytes the data actually occupies in the backing file */
215 __le16 me_data_size;
216
217 /* Block flags from incfs_block_map_entry_flags */
218 __le16 me_flags;
219} __packed;
220
221/* Metadata record for locations of file blocks. Type = INCFS_MD_BLOCK_MAP */
222struct incfs_blockmap {
223 struct incfs_md_header m_header;
224
225 /* Base offset of the array of incfs_blockmap_entry */
226 __le64 m_base_offset;
227
228 /* Size of the map entry array in blocks */
229 __le32 m_block_count;
230} __packed;
231
232/*
233 * Metadata record for file signature. Type = INCFS_MD_SIGNATURE
234 *
235 * The signature stored here is the APK V4 signature data blob. See the
236 * definition of incfs_new_file_args::signature_info for an explanation of this
237 * blob. Specifically, it contains the root hash, but it does *not* contain
238 * anything that the kernel treats as a signature.
239 *
240 * When FS_IOC_ENABLE_VERITY is called on a file without this record, an APK V4
241 * signature blob and a hash tree are added to the file, and then this metadata
242 * record is created to record their locations.
243 */
244struct incfs_file_signature {
245 struct incfs_md_header sg_header;
246
247 __le32 sg_sig_size; /* The size of the signature. */
248
249 __le64 sg_sig_offset; /* Signature's offset in the backing file */
250
251 __le32 sg_hash_tree_size; /* The size of the hash tree. */
252
253 __le64 sg_hash_tree_offset; /* Hash tree offset in the backing file */
254} __packed;
255
256/* In memory version of above */
257struct incfs_df_signature {
258 u32 sig_size;
259 u64 sig_offset;
260 u32 hash_size;
261 u64 hash_offset;
262};
263
264struct incfs_status {
265 struct incfs_md_header is_header;
266
267 __le32 is_data_blocks_written; /* Number of data blocks written */
268
269 __le32 is_hash_blocks_written; /* Number of hash blocks written */
270
271 __le32 is_dummy[6]; /* Spare fields */
272} __packed;
273
274/*
275 * Metadata record for verity signature. Type = INCFS_MD_VERITY_SIGNATURE
276 *
277 * This record will only exist for verity-enabled files with signatures. Verity
278 * enabled files without signatures do not have this record. This signature is
279 * checked by fs-verity identically to any other fs-verity signature.
280 */
281struct incfs_file_verity_signature {
282 struct incfs_md_header vs_header;
283
284 /* The size of the signature */
285 __le32 vs_size;
286
287 /* Signature's offset in the backing file */
288 __le64 vs_offset;
289} __packed;
290
291/* In memory version of above */
292struct incfs_df_verity_signature {
293 u32 size;
294 u64 offset;
295};
296
297/* State of the backing file. */
298struct backing_file_context {
299 /* Protects writes to bc_file */
300 struct mutex bc_mutex;
301
302 /* File object to read data from */
303 struct file *bc_file;
304
305 /*
306 * Offset of the last known metadata record in the backing file.
307 * 0 means there are no metadata records.
308 */
309 loff_t bc_last_md_record_offset;
310
311 /*
312 * Credentials to set before reads/writes
313 * Note that this is a pointer to the mount_info mi_owner field so
314 * there is no need to get/put the creds
315 */
316 const struct cred *bc_cred;
317};
318
319struct metadata_handler {
320 loff_t md_record_offset;
321 loff_t md_prev_record_offset;
322 void *context;
323
324 union {
325 struct incfs_md_header md_header;
326 struct incfs_blockmap blockmap;
327 struct incfs_file_signature signature;
328 struct incfs_status status;
329 struct incfs_file_verity_signature verity_signature;
330 } md_buffer;
331
332 int (*handle_blockmap)(struct incfs_blockmap *bm,
333 struct metadata_handler *handler);
334 int (*handle_signature)(struct incfs_file_signature *sig,
335 struct metadata_handler *handler);
336 int (*handle_status)(struct incfs_status *sig,
337 struct metadata_handler *handler);
338 int (*handle_verity_signature)(struct incfs_file_verity_signature *s,
339 struct metadata_handler *handler);
340};
341#define INCFS_MAX_METADATA_RECORD_SIZE \
342 FIELD_SIZEOF(struct metadata_handler, md_buffer)
343
344/* Backing file context management */
345struct mount_info;
346struct backing_file_context *incfs_alloc_bfc(struct mount_info *mi,
347 struct file *backing_file);
348
349void incfs_free_bfc(struct backing_file_context *bfc);
350
351/* Writing stuff */
352int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc,
353 u32 block_count);
354
355int incfs_write_fh_to_backing_file(struct backing_file_context *bfc,
356 incfs_uuid_t *uuid, u64 file_size);
357
358int incfs_write_mapping_fh_to_backing_file(struct backing_file_context *bfc,
359 incfs_uuid_t *uuid, u64 file_size, u64 offset);
360
361int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc,
362 struct mem_range block,
363 int block_index, loff_t bm_base_off,
364 u16 flags);
365
366int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc,
367 struct mem_range block,
368 int block_index,
369 loff_t hash_area_off,
370 loff_t bm_base_off,
371 loff_t file_size);
372
373int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
374 struct mem_range sig, u32 tree_size,
375 loff_t *tree_offset, loff_t *sig_offset);
376
377int incfs_write_status_to_backing_file(struct backing_file_context *bfc,
378 loff_t status_offset,
379 u32 data_blocks_written,
380 u32 hash_blocks_written);
381int incfs_write_verity_signature_to_backing_file(
382 struct backing_file_context *bfc, struct mem_range signature,
383 loff_t *offset);
384
385/* Reading stuff */
386int incfs_read_file_header(struct backing_file_context *bfc,
387 loff_t *first_md_off, incfs_uuid_t *uuid,
388 u64 *file_size, u32 *flags);
389
390int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index,
391 loff_t bm_base_off,
392 struct incfs_blockmap_entry *bm_entry);
393
394int incfs_read_blockmap_entries(struct backing_file_context *bfc,
395 struct incfs_blockmap_entry *entries,
396 int start_index, int blocks_number,
397 loff_t bm_base_off);
398
399int incfs_read_next_metadata_record(struct backing_file_context *bfc,
400 struct metadata_handler *handler);
401
402ssize_t incfs_kread(struct backing_file_context *bfc, void *buf, size_t size,
403 loff_t pos);
404ssize_t incfs_kwrite(struct backing_file_context *bfc, const void *buf,
405 size_t size, loff_t pos);
406
407#endif /* _INCFS_FORMAT_H */