xref: /OK3568_Linux_fs/kernel/fs/incfs/format.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2018 Google LLC
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include <linux/fs.h>
6*4882a593Smuzhiyun #include <linux/file.h>
7*4882a593Smuzhiyun #include <linux/types.h>
8*4882a593Smuzhiyun #include <linux/mutex.h>
9*4882a593Smuzhiyun #include <linux/mm.h>
10*4882a593Smuzhiyun #include <linux/falloc.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/crc32.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "format.h"
16*4882a593Smuzhiyun #include "data_mgmt.h"
17*4882a593Smuzhiyun 
incfs_alloc_bfc(struct mount_info * mi,struct file * backing_file)18*4882a593Smuzhiyun struct backing_file_context *incfs_alloc_bfc(struct mount_info *mi,
19*4882a593Smuzhiyun 					     struct file *backing_file)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	struct backing_file_context *result = NULL;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	result = kzalloc(sizeof(*result), GFP_NOFS);
24*4882a593Smuzhiyun 	if (!result)
25*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun 	result->bc_file = get_file(backing_file);
28*4882a593Smuzhiyun 	result->bc_cred = mi->mi_owner;
29*4882a593Smuzhiyun 	mutex_init(&result->bc_mutex);
30*4882a593Smuzhiyun 	return result;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
incfs_free_bfc(struct backing_file_context * bfc)33*4882a593Smuzhiyun void incfs_free_bfc(struct backing_file_context *bfc)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	if (!bfc)
36*4882a593Smuzhiyun 		return;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	if (bfc->bc_file)
39*4882a593Smuzhiyun 		fput(bfc->bc_file);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	mutex_destroy(&bfc->bc_mutex);
42*4882a593Smuzhiyun 	kfree(bfc);
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
incfs_get_end_offset(struct file * f)45*4882a593Smuzhiyun static loff_t incfs_get_end_offset(struct file *f)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	/*
48*4882a593Smuzhiyun 	 * This function assumes that file size and the end-offset
49*4882a593Smuzhiyun 	 * are the same. This is not always true.
50*4882a593Smuzhiyun 	 */
51*4882a593Smuzhiyun 	return i_size_read(file_inode(f));
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /*
55*4882a593Smuzhiyun  * Truncate the tail of the file to the given length.
56*4882a593Smuzhiyun  * Used to rollback partially successful multistep writes.
57*4882a593Smuzhiyun  */
truncate_backing_file(struct backing_file_context * bfc,loff_t new_end)58*4882a593Smuzhiyun static int truncate_backing_file(struct backing_file_context *bfc,
59*4882a593Smuzhiyun 				loff_t new_end)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	struct inode *inode = NULL;
62*4882a593Smuzhiyun 	struct dentry *dentry = NULL;
63*4882a593Smuzhiyun 	loff_t old_end = 0;
64*4882a593Smuzhiyun 	struct iattr attr;
65*4882a593Smuzhiyun 	int result = 0;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	if (!bfc)
68*4882a593Smuzhiyun 		return -EFAULT;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	if (!bfc->bc_file)
73*4882a593Smuzhiyun 		return -EFAULT;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	old_end = incfs_get_end_offset(bfc->bc_file);
76*4882a593Smuzhiyun 	if (old_end == new_end)
77*4882a593Smuzhiyun 		return 0;
78*4882a593Smuzhiyun 	if (old_end < new_end)
79*4882a593Smuzhiyun 		return -EINVAL;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	inode = bfc->bc_file->f_inode;
82*4882a593Smuzhiyun 	dentry = bfc->bc_file->f_path.dentry;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	attr.ia_size = new_end;
85*4882a593Smuzhiyun 	attr.ia_valid = ATTR_SIZE;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	inode_lock(inode);
88*4882a593Smuzhiyun 	result = notify_change(dentry, &attr, NULL);
89*4882a593Smuzhiyun 	inode_unlock(inode);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return result;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
write_to_bf(struct backing_file_context * bfc,const void * buf,size_t count,loff_t pos)94*4882a593Smuzhiyun static int write_to_bf(struct backing_file_context *bfc, const void *buf,
95*4882a593Smuzhiyun 			size_t count, loff_t pos)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	ssize_t res = incfs_kwrite(bfc, buf, count, pos);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	if (res < 0)
100*4882a593Smuzhiyun 		return res;
101*4882a593Smuzhiyun 	if (res != count)
102*4882a593Smuzhiyun 		return -EIO;
103*4882a593Smuzhiyun 	return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
append_zeros_no_fallocate(struct backing_file_context * bfc,size_t file_size,size_t len)106*4882a593Smuzhiyun static int append_zeros_no_fallocate(struct backing_file_context *bfc,
107*4882a593Smuzhiyun 				     size_t file_size, size_t len)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	u8 buffer[256] = {};
110*4882a593Smuzhiyun 	size_t i;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	for (i = 0; i < len; i += sizeof(buffer)) {
113*4882a593Smuzhiyun 		int to_write = len - i > sizeof(buffer)
114*4882a593Smuzhiyun 			? sizeof(buffer) : len - i;
115*4882a593Smuzhiyun 		int err = write_to_bf(bfc, buffer, to_write, file_size + i);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 		if (err)
118*4882a593Smuzhiyun 			return err;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return 0;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun /* Append a given number of zero bytes to the end of the backing file. */
append_zeros(struct backing_file_context * bfc,size_t len)125*4882a593Smuzhiyun static int append_zeros(struct backing_file_context *bfc, size_t len)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	loff_t file_size = 0;
128*4882a593Smuzhiyun 	loff_t new_last_byte_offset = 0;
129*4882a593Smuzhiyun 	int result;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (!bfc)
132*4882a593Smuzhiyun 		return -EFAULT;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	if (len == 0)
135*4882a593Smuzhiyun 		return 0;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	/*
140*4882a593Smuzhiyun 	 * Allocate only one byte at the new desired end of the file.
141*4882a593Smuzhiyun 	 * It will increase file size and create a zeroed area of
142*4882a593Smuzhiyun 	 * a given size.
143*4882a593Smuzhiyun 	 */
144*4882a593Smuzhiyun 	file_size = incfs_get_end_offset(bfc->bc_file);
145*4882a593Smuzhiyun 	new_last_byte_offset = file_size + len - 1;
146*4882a593Smuzhiyun 	result = vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1);
147*4882a593Smuzhiyun 	if (result != -EOPNOTSUPP)
148*4882a593Smuzhiyun 		return result;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	return append_zeros_no_fallocate(bfc, file_size, len);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun /*
154*4882a593Smuzhiyun  * Append a given metadata record to the backing file and update a previous
155*4882a593Smuzhiyun  * record to add the new record the the metadata list.
156*4882a593Smuzhiyun  */
append_md_to_backing_file(struct backing_file_context * bfc,struct incfs_md_header * record)157*4882a593Smuzhiyun static int append_md_to_backing_file(struct backing_file_context *bfc,
158*4882a593Smuzhiyun 			      struct incfs_md_header *record)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	int result = 0;
161*4882a593Smuzhiyun 	loff_t record_offset;
162*4882a593Smuzhiyun 	loff_t file_pos;
163*4882a593Smuzhiyun 	__le64 new_md_offset;
164*4882a593Smuzhiyun 	size_t record_size;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (!bfc || !record)
167*4882a593Smuzhiyun 		return -EFAULT;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	if (bfc->bc_last_md_record_offset < 0)
170*4882a593Smuzhiyun 		return -EINVAL;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	record_size = le16_to_cpu(record->h_record_size);
175*4882a593Smuzhiyun 	file_pos = incfs_get_end_offset(bfc->bc_file);
176*4882a593Smuzhiyun 	record->h_next_md_offset = 0;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	/* Write the metadata record to the end of the backing file */
179*4882a593Smuzhiyun 	record_offset = file_pos;
180*4882a593Smuzhiyun 	new_md_offset = cpu_to_le64(record_offset);
181*4882a593Smuzhiyun 	result = write_to_bf(bfc, record, record_size, file_pos);
182*4882a593Smuzhiyun 	if (result)
183*4882a593Smuzhiyun 		return result;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	/* Update next metadata offset in a previous record or a superblock. */
186*4882a593Smuzhiyun 	if (bfc->bc_last_md_record_offset) {
187*4882a593Smuzhiyun 		/*
188*4882a593Smuzhiyun 		 * Find a place in the previous md record where new record's
189*4882a593Smuzhiyun 		 * offset needs to be saved.
190*4882a593Smuzhiyun 		 */
191*4882a593Smuzhiyun 		file_pos = bfc->bc_last_md_record_offset +
192*4882a593Smuzhiyun 			offsetof(struct incfs_md_header, h_next_md_offset);
193*4882a593Smuzhiyun 	} else {
194*4882a593Smuzhiyun 		/*
195*4882a593Smuzhiyun 		 * No metadata yet, file a place to update in the
196*4882a593Smuzhiyun 		 * file_header.
197*4882a593Smuzhiyun 		 */
198*4882a593Smuzhiyun 		file_pos = offsetof(struct incfs_file_header,
199*4882a593Smuzhiyun 				    fh_first_md_offset);
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 	result = write_to_bf(bfc, &new_md_offset, sizeof(new_md_offset),
202*4882a593Smuzhiyun 			     file_pos);
203*4882a593Smuzhiyun 	if (result)
204*4882a593Smuzhiyun 		return result;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	bfc->bc_last_md_record_offset = record_offset;
207*4882a593Smuzhiyun 	return result;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun /*
211*4882a593Smuzhiyun  * Reserve 0-filled space for the blockmap body, and append
212*4882a593Smuzhiyun  * incfs_blockmap metadata record pointing to it.
213*4882a593Smuzhiyun  */
incfs_write_blockmap_to_backing_file(struct backing_file_context * bfc,u32 block_count)214*4882a593Smuzhiyun int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc,
215*4882a593Smuzhiyun 					 u32 block_count)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	struct incfs_blockmap blockmap = {};
218*4882a593Smuzhiyun 	int result = 0;
219*4882a593Smuzhiyun 	loff_t file_end = 0;
220*4882a593Smuzhiyun 	size_t map_size = block_count * sizeof(struct incfs_blockmap_entry);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (!bfc)
223*4882a593Smuzhiyun 		return -EFAULT;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	blockmap.m_header.h_md_entry_type = INCFS_MD_BLOCK_MAP;
226*4882a593Smuzhiyun 	blockmap.m_header.h_record_size = cpu_to_le16(sizeof(blockmap));
227*4882a593Smuzhiyun 	blockmap.m_header.h_next_md_offset = cpu_to_le64(0);
228*4882a593Smuzhiyun 	blockmap.m_block_count = cpu_to_le32(block_count);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* Reserve 0-filled space for the blockmap body in the backing file. */
233*4882a593Smuzhiyun 	file_end = incfs_get_end_offset(bfc->bc_file);
234*4882a593Smuzhiyun 	result = append_zeros(bfc, map_size);
235*4882a593Smuzhiyun 	if (result)
236*4882a593Smuzhiyun 		return result;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	/* Write blockmap metadata record pointing to the body written above. */
239*4882a593Smuzhiyun 	blockmap.m_base_offset = cpu_to_le64(file_end);
240*4882a593Smuzhiyun 	result = append_md_to_backing_file(bfc, &blockmap.m_header);
241*4882a593Smuzhiyun 	if (result)
242*4882a593Smuzhiyun 		/* Error, rollback file changes */
243*4882a593Smuzhiyun 		truncate_backing_file(bfc, file_end);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	return result;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
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)248*4882a593Smuzhiyun int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
249*4882a593Smuzhiyun 					struct mem_range sig, u32 tree_size,
250*4882a593Smuzhiyun 					loff_t *tree_offset, loff_t *sig_offset)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	struct incfs_file_signature sg = {};
253*4882a593Smuzhiyun 	int result = 0;
254*4882a593Smuzhiyun 	loff_t rollback_pos = 0;
255*4882a593Smuzhiyun 	loff_t tree_area_pos = 0;
256*4882a593Smuzhiyun 	size_t alignment = 0;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	if (!bfc)
259*4882a593Smuzhiyun 		return -EFAULT;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	rollback_pos = incfs_get_end_offset(bfc->bc_file);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	sg.sg_header.h_md_entry_type = INCFS_MD_SIGNATURE;
266*4882a593Smuzhiyun 	sg.sg_header.h_record_size = cpu_to_le16(sizeof(sg));
267*4882a593Smuzhiyun 	sg.sg_header.h_next_md_offset = cpu_to_le64(0);
268*4882a593Smuzhiyun 	if (sig.data != NULL && sig.len > 0) {
269*4882a593Smuzhiyun 		sg.sg_sig_size = cpu_to_le32(sig.len);
270*4882a593Smuzhiyun 		sg.sg_sig_offset = cpu_to_le64(rollback_pos);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 		result = write_to_bf(bfc, sig.data, sig.len, rollback_pos);
273*4882a593Smuzhiyun 		if (result)
274*4882a593Smuzhiyun 			goto err;
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	tree_area_pos = incfs_get_end_offset(bfc->bc_file);
278*4882a593Smuzhiyun 	if (tree_size > 0) {
279*4882a593Smuzhiyun 		if (tree_size > 5 * INCFS_DATA_FILE_BLOCK_SIZE) {
280*4882a593Smuzhiyun 			/*
281*4882a593Smuzhiyun 			 * If hash tree is big enough, it makes sense to
282*4882a593Smuzhiyun 			 * align in the backing file for faster access.
283*4882a593Smuzhiyun 			 */
284*4882a593Smuzhiyun 			loff_t offset = round_up(tree_area_pos, PAGE_SIZE);
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 			alignment = offset - tree_area_pos;
287*4882a593Smuzhiyun 			tree_area_pos = offset;
288*4882a593Smuzhiyun 		}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 		/*
291*4882a593Smuzhiyun 		 * If root hash is not the only hash in the tree.
292*4882a593Smuzhiyun 		 * reserve 0-filled space for the tree.
293*4882a593Smuzhiyun 		 */
294*4882a593Smuzhiyun 		result = append_zeros(bfc, tree_size + alignment);
295*4882a593Smuzhiyun 		if (result)
296*4882a593Smuzhiyun 			goto err;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 		sg.sg_hash_tree_size = cpu_to_le32(tree_size);
299*4882a593Smuzhiyun 		sg.sg_hash_tree_offset = cpu_to_le64(tree_area_pos);
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	/* Write a hash tree metadata record pointing to the hash tree above. */
303*4882a593Smuzhiyun 	result = append_md_to_backing_file(bfc, &sg.sg_header);
304*4882a593Smuzhiyun err:
305*4882a593Smuzhiyun 	if (result)
306*4882a593Smuzhiyun 		/* Error, rollback file changes */
307*4882a593Smuzhiyun 		truncate_backing_file(bfc, rollback_pos);
308*4882a593Smuzhiyun 	else {
309*4882a593Smuzhiyun 		if (tree_offset)
310*4882a593Smuzhiyun 			*tree_offset = tree_area_pos;
311*4882a593Smuzhiyun 		if (sig_offset)
312*4882a593Smuzhiyun 			*sig_offset = rollback_pos;
313*4882a593Smuzhiyun 	}
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return result;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
write_new_status_to_backing_file(struct backing_file_context * bfc,u32 data_blocks_written,u32 hash_blocks_written)318*4882a593Smuzhiyun static int write_new_status_to_backing_file(struct backing_file_context *bfc,
319*4882a593Smuzhiyun 				       u32 data_blocks_written,
320*4882a593Smuzhiyun 				       u32 hash_blocks_written)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	int result;
323*4882a593Smuzhiyun 	loff_t rollback_pos;
324*4882a593Smuzhiyun 	struct incfs_status is = {
325*4882a593Smuzhiyun 		.is_header = {
326*4882a593Smuzhiyun 			.h_md_entry_type = INCFS_MD_STATUS,
327*4882a593Smuzhiyun 			.h_record_size = cpu_to_le16(sizeof(is)),
328*4882a593Smuzhiyun 		},
329*4882a593Smuzhiyun 		.is_data_blocks_written = cpu_to_le32(data_blocks_written),
330*4882a593Smuzhiyun 		.is_hash_blocks_written = cpu_to_le32(hash_blocks_written),
331*4882a593Smuzhiyun 	};
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
334*4882a593Smuzhiyun 	rollback_pos = incfs_get_end_offset(bfc->bc_file);
335*4882a593Smuzhiyun 	result = append_md_to_backing_file(bfc, &is.is_header);
336*4882a593Smuzhiyun 	if (result)
337*4882a593Smuzhiyun 		truncate_backing_file(bfc, rollback_pos);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	return result;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
incfs_write_status_to_backing_file(struct backing_file_context * bfc,loff_t status_offset,u32 data_blocks_written,u32 hash_blocks_written)342*4882a593Smuzhiyun int incfs_write_status_to_backing_file(struct backing_file_context *bfc,
343*4882a593Smuzhiyun 				       loff_t status_offset,
344*4882a593Smuzhiyun 				       u32 data_blocks_written,
345*4882a593Smuzhiyun 				       u32 hash_blocks_written)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	struct incfs_status is;
348*4882a593Smuzhiyun 	int result;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (!bfc)
351*4882a593Smuzhiyun 		return -EFAULT;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	if (status_offset == 0)
354*4882a593Smuzhiyun 		return write_new_status_to_backing_file(bfc,
355*4882a593Smuzhiyun 				data_blocks_written, hash_blocks_written);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	result = incfs_kread(bfc, &is, sizeof(is), status_offset);
358*4882a593Smuzhiyun 	if (result != sizeof(is))
359*4882a593Smuzhiyun 		return -EIO;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	is.is_data_blocks_written = cpu_to_le32(data_blocks_written);
362*4882a593Smuzhiyun 	is.is_hash_blocks_written = cpu_to_le32(hash_blocks_written);
363*4882a593Smuzhiyun 	result = incfs_kwrite(bfc, &is, sizeof(is), status_offset);
364*4882a593Smuzhiyun 	if (result != sizeof(is))
365*4882a593Smuzhiyun 		return -EIO;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
incfs_write_verity_signature_to_backing_file(struct backing_file_context * bfc,struct mem_range signature,loff_t * offset)370*4882a593Smuzhiyun int incfs_write_verity_signature_to_backing_file(
371*4882a593Smuzhiyun 		struct backing_file_context *bfc, struct mem_range signature,
372*4882a593Smuzhiyun 		loff_t *offset)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	struct incfs_file_verity_signature vs = {};
375*4882a593Smuzhiyun 	int result;
376*4882a593Smuzhiyun 	loff_t pos;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	/* No verity signature section is equivalent to an empty section */
379*4882a593Smuzhiyun 	if (signature.data == NULL || signature.len == 0)
380*4882a593Smuzhiyun 		return 0;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	pos = incfs_get_end_offset(bfc->bc_file);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	vs = (struct incfs_file_verity_signature) {
385*4882a593Smuzhiyun 		.vs_header = (struct incfs_md_header) {
386*4882a593Smuzhiyun 			.h_md_entry_type = INCFS_MD_VERITY_SIGNATURE,
387*4882a593Smuzhiyun 			.h_record_size = cpu_to_le16(sizeof(vs)),
388*4882a593Smuzhiyun 			.h_next_md_offset = cpu_to_le64(0),
389*4882a593Smuzhiyun 		},
390*4882a593Smuzhiyun 		.vs_size = cpu_to_le32(signature.len),
391*4882a593Smuzhiyun 		.vs_offset = cpu_to_le64(pos),
392*4882a593Smuzhiyun 	};
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	result = write_to_bf(bfc, signature.data, signature.len, pos);
395*4882a593Smuzhiyun 	if (result)
396*4882a593Smuzhiyun 		goto err;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	result = append_md_to_backing_file(bfc, &vs.vs_header);
399*4882a593Smuzhiyun 	if (result)
400*4882a593Smuzhiyun 		goto err;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	*offset = pos;
403*4882a593Smuzhiyun err:
404*4882a593Smuzhiyun 	if (result)
405*4882a593Smuzhiyun 		/* Error, rollback file changes */
406*4882a593Smuzhiyun 		truncate_backing_file(bfc, pos);
407*4882a593Smuzhiyun 	return result;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun /*
411*4882a593Smuzhiyun  * Write a backing file header
412*4882a593Smuzhiyun  * It should always be called only on empty file.
413*4882a593Smuzhiyun  * fh.fh_first_md_offset is 0 for now, but will be updated
414*4882a593Smuzhiyun  * once first metadata record is added.
415*4882a593Smuzhiyun  */
incfs_write_fh_to_backing_file(struct backing_file_context * bfc,incfs_uuid_t * uuid,u64 file_size)416*4882a593Smuzhiyun int incfs_write_fh_to_backing_file(struct backing_file_context *bfc,
417*4882a593Smuzhiyun 				   incfs_uuid_t *uuid, u64 file_size)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun 	struct incfs_file_header fh = {};
420*4882a593Smuzhiyun 	loff_t file_pos = 0;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (!bfc)
423*4882a593Smuzhiyun 		return -EFAULT;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	fh.fh_magic = cpu_to_le64(INCFS_MAGIC_NUMBER);
426*4882a593Smuzhiyun 	fh.fh_version = cpu_to_le64(INCFS_FORMAT_CURRENT_VER);
427*4882a593Smuzhiyun 	fh.fh_header_size = cpu_to_le16(sizeof(fh));
428*4882a593Smuzhiyun 	fh.fh_first_md_offset = cpu_to_le64(0);
429*4882a593Smuzhiyun 	fh.fh_data_block_size = cpu_to_le16(INCFS_DATA_FILE_BLOCK_SIZE);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	fh.fh_file_size = cpu_to_le64(file_size);
432*4882a593Smuzhiyun 	fh.fh_uuid = *uuid;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	file_pos = incfs_get_end_offset(bfc->bc_file);
437*4882a593Smuzhiyun 	if (file_pos != 0)
438*4882a593Smuzhiyun 		return -EEXIST;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	return write_to_bf(bfc, &fh, sizeof(fh), file_pos);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun /*
444*4882a593Smuzhiyun  * Write a backing file header for a mapping file
445*4882a593Smuzhiyun  * It should always be called only on empty file.
446*4882a593Smuzhiyun  */
incfs_write_mapping_fh_to_backing_file(struct backing_file_context * bfc,incfs_uuid_t * uuid,u64 file_size,u64 offset)447*4882a593Smuzhiyun int incfs_write_mapping_fh_to_backing_file(struct backing_file_context *bfc,
448*4882a593Smuzhiyun 				incfs_uuid_t *uuid, u64 file_size, u64 offset)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct incfs_file_header fh = {};
451*4882a593Smuzhiyun 	loff_t file_pos = 0;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	if (!bfc)
454*4882a593Smuzhiyun 		return -EFAULT;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	fh.fh_magic = cpu_to_le64(INCFS_MAGIC_NUMBER);
457*4882a593Smuzhiyun 	fh.fh_version = cpu_to_le64(INCFS_FORMAT_CURRENT_VER);
458*4882a593Smuzhiyun 	fh.fh_header_size = cpu_to_le16(sizeof(fh));
459*4882a593Smuzhiyun 	fh.fh_original_offset = cpu_to_le64(offset);
460*4882a593Smuzhiyun 	fh.fh_data_block_size = cpu_to_le16(INCFS_DATA_FILE_BLOCK_SIZE);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	fh.fh_mapped_file_size = cpu_to_le64(file_size);
463*4882a593Smuzhiyun 	fh.fh_original_uuid = *uuid;
464*4882a593Smuzhiyun 	fh.fh_flags = cpu_to_le32(INCFS_FILE_MAPPED);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	file_pos = incfs_get_end_offset(bfc->bc_file);
469*4882a593Smuzhiyun 	if (file_pos != 0)
470*4882a593Smuzhiyun 		return -EEXIST;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	return write_to_bf(bfc, &fh, sizeof(fh), file_pos);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun /* Write a given data block and update file's blockmap to point it. */
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)476*4882a593Smuzhiyun int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc,
477*4882a593Smuzhiyun 				     struct mem_range block, int block_index,
478*4882a593Smuzhiyun 				     loff_t bm_base_off, u16 flags)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	struct incfs_blockmap_entry bm_entry = {};
481*4882a593Smuzhiyun 	int result = 0;
482*4882a593Smuzhiyun 	loff_t data_offset = 0;
483*4882a593Smuzhiyun 	loff_t bm_entry_off =
484*4882a593Smuzhiyun 		bm_base_off + sizeof(struct incfs_blockmap_entry) * block_index;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (!bfc)
487*4882a593Smuzhiyun 		return -EFAULT;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	if (block.len >= (1 << 16) || block_index < 0)
490*4882a593Smuzhiyun 		return -EINVAL;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	data_offset = incfs_get_end_offset(bfc->bc_file);
495*4882a593Smuzhiyun 	if (data_offset <= bm_entry_off) {
496*4882a593Smuzhiyun 		/* Blockmap entry is beyond the file's end. It is not normal. */
497*4882a593Smuzhiyun 		return -EINVAL;
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	/* Write the block data at the end of the backing file. */
501*4882a593Smuzhiyun 	result = write_to_bf(bfc, block.data, block.len, data_offset);
502*4882a593Smuzhiyun 	if (result)
503*4882a593Smuzhiyun 		return result;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	/* Update the blockmap to point to the newly written data. */
506*4882a593Smuzhiyun 	bm_entry.me_data_offset_lo = cpu_to_le32((u32)data_offset);
507*4882a593Smuzhiyun 	bm_entry.me_data_offset_hi = cpu_to_le16((u16)(data_offset >> 32));
508*4882a593Smuzhiyun 	bm_entry.me_data_size = cpu_to_le16((u16)block.len);
509*4882a593Smuzhiyun 	bm_entry.me_flags = cpu_to_le16(flags);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	return write_to_bf(bfc, &bm_entry, sizeof(bm_entry),
512*4882a593Smuzhiyun 				bm_entry_off);
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
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)515*4882a593Smuzhiyun int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc,
516*4882a593Smuzhiyun 					   struct mem_range block,
517*4882a593Smuzhiyun 					   int block_index,
518*4882a593Smuzhiyun 					   loff_t hash_area_off,
519*4882a593Smuzhiyun 					   loff_t bm_base_off,
520*4882a593Smuzhiyun 					   loff_t file_size)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	struct incfs_blockmap_entry bm_entry = {};
523*4882a593Smuzhiyun 	int result;
524*4882a593Smuzhiyun 	loff_t data_offset = 0;
525*4882a593Smuzhiyun 	loff_t file_end = 0;
526*4882a593Smuzhiyun 	loff_t bm_entry_off =
527*4882a593Smuzhiyun 		bm_base_off +
528*4882a593Smuzhiyun 		sizeof(struct incfs_blockmap_entry) *
529*4882a593Smuzhiyun 			(block_index + get_blocks_count_for_size(file_size));
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	if (!bfc)
532*4882a593Smuzhiyun 		return -EFAULT;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	LOCK_REQUIRED(bfc->bc_mutex);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	data_offset = hash_area_off + block_index * INCFS_DATA_FILE_BLOCK_SIZE;
537*4882a593Smuzhiyun 	file_end = incfs_get_end_offset(bfc->bc_file);
538*4882a593Smuzhiyun 	if (data_offset + block.len > file_end) {
539*4882a593Smuzhiyun 		/* Block is located beyond the file's end. It is not normal. */
540*4882a593Smuzhiyun 		return -EINVAL;
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	result = write_to_bf(bfc, block.data, block.len, data_offset);
544*4882a593Smuzhiyun 	if (result)
545*4882a593Smuzhiyun 		return result;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	bm_entry.me_data_offset_lo = cpu_to_le32((u32)data_offset);
548*4882a593Smuzhiyun 	bm_entry.me_data_offset_hi = cpu_to_le16((u16)(data_offset >> 32));
549*4882a593Smuzhiyun 	bm_entry.me_data_size = cpu_to_le16(INCFS_DATA_FILE_BLOCK_SIZE);
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	return write_to_bf(bfc, &bm_entry, sizeof(bm_entry), bm_entry_off);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun 
incfs_read_blockmap_entry(struct backing_file_context * bfc,int block_index,loff_t bm_base_off,struct incfs_blockmap_entry * bm_entry)554*4882a593Smuzhiyun int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index,
555*4882a593Smuzhiyun 			loff_t bm_base_off,
556*4882a593Smuzhiyun 			struct incfs_blockmap_entry *bm_entry)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	int error = incfs_read_blockmap_entries(bfc, bm_entry, block_index, 1,
559*4882a593Smuzhiyun 						bm_base_off);
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	if (error < 0)
562*4882a593Smuzhiyun 		return error;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	if (error == 0)
565*4882a593Smuzhiyun 		return -EIO;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	if (error != 1)
568*4882a593Smuzhiyun 		return -EFAULT;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	return 0;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun 
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)573*4882a593Smuzhiyun int incfs_read_blockmap_entries(struct backing_file_context *bfc,
574*4882a593Smuzhiyun 		struct incfs_blockmap_entry *entries,
575*4882a593Smuzhiyun 		int start_index, int blocks_number,
576*4882a593Smuzhiyun 		loff_t bm_base_off)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun 	loff_t bm_entry_off =
579*4882a593Smuzhiyun 		bm_base_off + sizeof(struct incfs_blockmap_entry) * start_index;
580*4882a593Smuzhiyun 	const size_t bytes_to_read = sizeof(struct incfs_blockmap_entry)
581*4882a593Smuzhiyun 					* blocks_number;
582*4882a593Smuzhiyun 	int result = 0;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	if (!bfc || !entries)
585*4882a593Smuzhiyun 		return -EFAULT;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	if (start_index < 0 || bm_base_off <= 0)
588*4882a593Smuzhiyun 		return -ENODATA;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	result = incfs_kread(bfc, entries, bytes_to_read, bm_entry_off);
591*4882a593Smuzhiyun 	if (result < 0)
592*4882a593Smuzhiyun 		return result;
593*4882a593Smuzhiyun 	return result / sizeof(*entries);
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun 
incfs_read_file_header(struct backing_file_context * bfc,loff_t * first_md_off,incfs_uuid_t * uuid,u64 * file_size,u32 * flags)596*4882a593Smuzhiyun int incfs_read_file_header(struct backing_file_context *bfc,
597*4882a593Smuzhiyun 			   loff_t *first_md_off, incfs_uuid_t *uuid,
598*4882a593Smuzhiyun 			   u64 *file_size, u32 *flags)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun 	ssize_t bytes_read = 0;
601*4882a593Smuzhiyun 	struct incfs_file_header fh = {};
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	if (!bfc || !first_md_off)
604*4882a593Smuzhiyun 		return -EFAULT;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	bytes_read = incfs_kread(bfc, &fh, sizeof(fh), 0);
607*4882a593Smuzhiyun 	if (bytes_read < 0)
608*4882a593Smuzhiyun 		return bytes_read;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	if (bytes_read < sizeof(fh))
611*4882a593Smuzhiyun 		return -EBADMSG;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	if (le64_to_cpu(fh.fh_magic) != INCFS_MAGIC_NUMBER)
614*4882a593Smuzhiyun 		return -EILSEQ;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	if (le64_to_cpu(fh.fh_version) > INCFS_FORMAT_CURRENT_VER)
617*4882a593Smuzhiyun 		return -EILSEQ;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	if (le16_to_cpu(fh.fh_data_block_size) != INCFS_DATA_FILE_BLOCK_SIZE)
620*4882a593Smuzhiyun 		return -EILSEQ;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	if (le16_to_cpu(fh.fh_header_size) != sizeof(fh))
623*4882a593Smuzhiyun 		return -EILSEQ;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (first_md_off)
626*4882a593Smuzhiyun 		*first_md_off = le64_to_cpu(fh.fh_first_md_offset);
627*4882a593Smuzhiyun 	if (uuid)
628*4882a593Smuzhiyun 		*uuid = fh.fh_uuid;
629*4882a593Smuzhiyun 	if (file_size)
630*4882a593Smuzhiyun 		*file_size = le64_to_cpu(fh.fh_file_size);
631*4882a593Smuzhiyun 	if (flags)
632*4882a593Smuzhiyun 		*flags = le32_to_cpu(fh.fh_flags);
633*4882a593Smuzhiyun 	return 0;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun /*
637*4882a593Smuzhiyun  * Read through metadata records from the backing file one by one
638*4882a593Smuzhiyun  * and call provided metadata handlers.
639*4882a593Smuzhiyun  */
incfs_read_next_metadata_record(struct backing_file_context * bfc,struct metadata_handler * handler)640*4882a593Smuzhiyun int incfs_read_next_metadata_record(struct backing_file_context *bfc,
641*4882a593Smuzhiyun 			      struct metadata_handler *handler)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	const ssize_t max_md_size = INCFS_MAX_METADATA_RECORD_SIZE;
644*4882a593Smuzhiyun 	ssize_t bytes_read = 0;
645*4882a593Smuzhiyun 	size_t md_record_size = 0;
646*4882a593Smuzhiyun 	loff_t next_record = 0;
647*4882a593Smuzhiyun 	int res = 0;
648*4882a593Smuzhiyun 	struct incfs_md_header *md_hdr = NULL;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	if (!bfc || !handler)
651*4882a593Smuzhiyun 		return -EFAULT;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	if (handler->md_record_offset == 0)
654*4882a593Smuzhiyun 		return -EPERM;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	memset(&handler->md_buffer, 0, max_md_size);
657*4882a593Smuzhiyun 	bytes_read = incfs_kread(bfc, &handler->md_buffer, max_md_size,
658*4882a593Smuzhiyun 				 handler->md_record_offset);
659*4882a593Smuzhiyun 	if (bytes_read < 0)
660*4882a593Smuzhiyun 		return bytes_read;
661*4882a593Smuzhiyun 	if (bytes_read < sizeof(*md_hdr))
662*4882a593Smuzhiyun 		return -EBADMSG;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	md_hdr = &handler->md_buffer.md_header;
665*4882a593Smuzhiyun 	next_record = le64_to_cpu(md_hdr->h_next_md_offset);
666*4882a593Smuzhiyun 	md_record_size = le16_to_cpu(md_hdr->h_record_size);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	if (md_record_size > max_md_size) {
669*4882a593Smuzhiyun 		pr_warn("incfs: The record is too large. Size: %zu",
670*4882a593Smuzhiyun 				md_record_size);
671*4882a593Smuzhiyun 		return -EBADMSG;
672*4882a593Smuzhiyun 	}
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	if (bytes_read < md_record_size) {
675*4882a593Smuzhiyun 		pr_warn("incfs: The record hasn't been fully read.");
676*4882a593Smuzhiyun 		return -EBADMSG;
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	if (next_record <= handler->md_record_offset && next_record != 0) {
680*4882a593Smuzhiyun 		pr_warn("incfs: Next record (%lld) points back in file.",
681*4882a593Smuzhiyun 			next_record);
682*4882a593Smuzhiyun 		return -EBADMSG;
683*4882a593Smuzhiyun 	}
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	switch (md_hdr->h_md_entry_type) {
686*4882a593Smuzhiyun 	case INCFS_MD_NONE:
687*4882a593Smuzhiyun 		break;
688*4882a593Smuzhiyun 	case INCFS_MD_BLOCK_MAP:
689*4882a593Smuzhiyun 		if (handler->handle_blockmap)
690*4882a593Smuzhiyun 			res = handler->handle_blockmap(
691*4882a593Smuzhiyun 				&handler->md_buffer.blockmap, handler);
692*4882a593Smuzhiyun 		break;
693*4882a593Smuzhiyun 	case INCFS_MD_FILE_ATTR:
694*4882a593Smuzhiyun 		/*
695*4882a593Smuzhiyun 		 * File attrs no longer supported, ignore section for
696*4882a593Smuzhiyun 		 * compatibility
697*4882a593Smuzhiyun 		 */
698*4882a593Smuzhiyun 		break;
699*4882a593Smuzhiyun 	case INCFS_MD_SIGNATURE:
700*4882a593Smuzhiyun 		if (handler->handle_signature)
701*4882a593Smuzhiyun 			res = handler->handle_signature(
702*4882a593Smuzhiyun 				&handler->md_buffer.signature, handler);
703*4882a593Smuzhiyun 		break;
704*4882a593Smuzhiyun 	case INCFS_MD_STATUS:
705*4882a593Smuzhiyun 		if (handler->handle_status)
706*4882a593Smuzhiyun 			res = handler->handle_status(
707*4882a593Smuzhiyun 				&handler->md_buffer.status, handler);
708*4882a593Smuzhiyun 		break;
709*4882a593Smuzhiyun 	case INCFS_MD_VERITY_SIGNATURE:
710*4882a593Smuzhiyun 		if (handler->handle_verity_signature)
711*4882a593Smuzhiyun 			res = handler->handle_verity_signature(
712*4882a593Smuzhiyun 				&handler->md_buffer.verity_signature, handler);
713*4882a593Smuzhiyun 		break;
714*4882a593Smuzhiyun 	default:
715*4882a593Smuzhiyun 		res = -ENOTSUPP;
716*4882a593Smuzhiyun 		break;
717*4882a593Smuzhiyun 	}
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	if (!res) {
720*4882a593Smuzhiyun 		if (next_record == 0) {
721*4882a593Smuzhiyun 			/*
722*4882a593Smuzhiyun 			 * Zero offset for the next record means that the last
723*4882a593Smuzhiyun 			 * metadata record has just been processed.
724*4882a593Smuzhiyun 			 */
725*4882a593Smuzhiyun 			bfc->bc_last_md_record_offset =
726*4882a593Smuzhiyun 				handler->md_record_offset;
727*4882a593Smuzhiyun 		}
728*4882a593Smuzhiyun 		handler->md_prev_record_offset = handler->md_record_offset;
729*4882a593Smuzhiyun 		handler->md_record_offset = next_record;
730*4882a593Smuzhiyun 	}
731*4882a593Smuzhiyun 	return res;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
incfs_kread(struct backing_file_context * bfc,void * buf,size_t size,loff_t pos)734*4882a593Smuzhiyun ssize_t incfs_kread(struct backing_file_context *bfc, void *buf, size_t size,
735*4882a593Smuzhiyun 		    loff_t pos)
736*4882a593Smuzhiyun {
737*4882a593Smuzhiyun 	const struct cred *old_cred = override_creds(bfc->bc_cred);
738*4882a593Smuzhiyun 	int ret = kernel_read(bfc->bc_file, buf, size, &pos);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	revert_creds(old_cred);
741*4882a593Smuzhiyun 	return ret;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun 
incfs_kwrite(struct backing_file_context * bfc,const void * buf,size_t size,loff_t pos)744*4882a593Smuzhiyun ssize_t incfs_kwrite(struct backing_file_context *bfc, const void *buf,
745*4882a593Smuzhiyun 		     size_t size, loff_t pos)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun 	const struct cred *old_cred = override_creds(bfc->bc_cred);
748*4882a593Smuzhiyun 	int ret = kernel_write(bfc->bc_file, buf, size, &pos);
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	revert_creds(old_cred);
751*4882a593Smuzhiyun 	return ret;
752*4882a593Smuzhiyun }
753