From 102a0743326a03cd1a1202ceda21e175b7d3575c Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:20:52 +0000
Subject: [PATCH] add new system file

---
 kernel/fs/incfs/format.c |  323 +++++++++++++++++++++++++++++++----------------------
 1 files changed, 187 insertions(+), 136 deletions(-)

diff --git a/kernel/fs/incfs/format.c b/kernel/fs/incfs/format.c
index b976668..9128cd2 100644
--- a/kernel/fs/incfs/format.c
+++ b/kernel/fs/incfs/format.c
@@ -42,7 +42,7 @@
 	kfree(bfc);
 }
 
-loff_t incfs_get_end_offset(struct file *f)
+static loff_t incfs_get_end_offset(struct file *f)
 {
 	/*
 	 * This function assumes that file size and the end-offset
@@ -91,11 +91,42 @@
 	return result;
 }
 
+static int write_to_bf(struct backing_file_context *bfc, const void *buf,
+			size_t count, loff_t pos)
+{
+	ssize_t res = incfs_kwrite(bfc, buf, count, pos);
+
+	if (res < 0)
+		return res;
+	if (res != count)
+		return -EIO;
+	return 0;
+}
+
+static int append_zeros_no_fallocate(struct backing_file_context *bfc,
+				     size_t file_size, size_t len)
+{
+	u8 buffer[256] = {};
+	size_t i;
+
+	for (i = 0; i < len; i += sizeof(buffer)) {
+		int to_write = len - i > sizeof(buffer)
+			? sizeof(buffer) : len - i;
+		int err = write_to_bf(bfc, buffer, to_write, file_size + i);
+
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 /* Append a given number of zero bytes to the end of the backing file. */
 static int append_zeros(struct backing_file_context *bfc, size_t len)
 {
 	loff_t file_size = 0;
 	loff_t new_last_byte_offset = 0;
+	int result;
 
 	if (!bfc)
 		return -EFAULT;
@@ -112,39 +143,11 @@
 	 */
 	file_size = incfs_get_end_offset(bfc->bc_file);
 	new_last_byte_offset = file_size + len - 1;
-	return vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1);
-}
+	result = vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1);
+	if (result != -EOPNOTSUPP)
+		return result;
 
-static int write_to_bf(struct backing_file_context *bfc, const void *buf,
-			size_t count, loff_t pos)
-{
-	ssize_t res = incfs_kwrite(bfc, buf, count, pos);
-
-	if (res < 0)
-		return res;
-	if (res != count)
-		return -EIO;
-	return 0;
-}
-
-static u32 calc_md_crc(struct incfs_md_header *record)
-{
-	u32 result = 0;
-	__le32 saved_crc = record->h_record_crc;
-	__le64 saved_md_offset = record->h_next_md_offset;
-	size_t record_size = min_t(size_t, le16_to_cpu(record->h_record_size),
-				INCFS_MAX_METADATA_RECORD_SIZE);
-
-	/* Zero fields which needs to be excluded from CRC calculation. */
-	record->h_record_crc = 0;
-	record->h_next_md_offset = 0;
-	result = crc32(0, record, record_size);
-
-	/* Restore excluded fields. */
-	record->h_record_crc = saved_crc;
-	record->h_next_md_offset = saved_md_offset;
-
-	return result;
+	return append_zeros_no_fallocate(bfc, file_size, len);
 }
 
 /*
@@ -170,9 +173,7 @@
 
 	record_size = le16_to_cpu(record->h_record_size);
 	file_pos = incfs_get_end_offset(bfc->bc_file);
-	record->h_prev_md_offset = cpu_to_le64(bfc->bc_last_md_record_offset);
 	record->h_next_md_offset = 0;
-	record->h_record_crc = cpu_to_le32(calc_md_crc(record));
 
 	/* Write the metadata record to the end of the backing file */
 	record_offset = file_pos;
@@ -204,16 +205,6 @@
 
 	bfc->bc_last_md_record_offset = record_offset;
 	return result;
-}
-
-int incfs_write_file_header_flags(struct backing_file_context *bfc, u32 flags)
-{
-	if (!bfc)
-		return -EFAULT;
-
-	return write_to_bf(bfc, &flags, sizeof(flags),
-			   offsetof(struct incfs_file_header,
-				    fh_file_header_flags));
 }
 
 /*
@@ -254,51 +245,9 @@
 	return result;
 }
 
-/*
- * Write file attribute data and metadata record to the backing file.
- */
-int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc,
-		struct mem_range value, struct incfs_file_attr *attr)
-{
-	struct incfs_file_attr file_attr = {};
-	int result = 0;
-	u32 crc = 0;
-	loff_t value_offset = 0;
-
-	if (!bfc)
-		return -EFAULT;
-
-	if (value.len > INCFS_MAX_FILE_ATTR_SIZE)
-		return -ENOSPC;
-
-	LOCK_REQUIRED(bfc->bc_mutex);
-
-	crc = crc32(0, value.data, value.len);
-	value_offset = incfs_get_end_offset(bfc->bc_file);
-	file_attr.fa_header.h_md_entry_type = INCFS_MD_FILE_ATTR;
-	file_attr.fa_header.h_record_size = cpu_to_le16(sizeof(file_attr));
-	file_attr.fa_header.h_next_md_offset = cpu_to_le64(0);
-	file_attr.fa_size = cpu_to_le16((u16)value.len);
-	file_attr.fa_offset = cpu_to_le64(value_offset);
-	file_attr.fa_crc = cpu_to_le32(crc);
-
-	result = write_to_bf(bfc, value.data, value.len, value_offset);
-	if (result)
-		return result;
-
-	result = append_md_to_backing_file(bfc, &file_attr.fa_header);
-	if (result) {
-		/* Error, rollback file changes */
-		truncate_backing_file(bfc, value_offset);
-	} else if (attr) {
-		*attr = file_attr;
-	}
-
-	return result;
-}
-
 int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
-					  struct mem_range sig, u32 tree_size)
+					struct mem_range sig, u32 tree_size,
+					loff_t *tree_offset, loff_t *sig_offset)
 {
 	struct incfs_file_signature sg = {};
 	int result = 0;
@@ -317,12 +266,10 @@
 	sg.sg_header.h_record_size = cpu_to_le16(sizeof(sg));
 	sg.sg_header.h_next_md_offset = cpu_to_le64(0);
 	if (sig.data != NULL && sig.len > 0) {
-		loff_t pos = incfs_get_end_offset(bfc->bc_file);
-
 		sg.sg_sig_size = cpu_to_le32(sig.len);
-		sg.sg_sig_offset = cpu_to_le64(pos);
+		sg.sg_sig_offset = cpu_to_le64(rollback_pos);
 
-		result = write_to_bf(bfc, sig.data, sig.len, pos);
+		result = write_to_bf(bfc, sig.data, sig.len, rollback_pos);
 		if (result)
 			goto err;
 	}
@@ -358,13 +305,112 @@
 	if (result)
 		/* Error, rollback file changes */
 		truncate_backing_file(bfc, rollback_pos);
+	else {
+		if (tree_offset)
+			*tree_offset = tree_area_pos;
+		if (sig_offset)
+			*sig_offset = rollback_pos;
+	}
+
+	return result;
+}
+
+static int write_new_status_to_backing_file(struct backing_file_context *bfc,
+				       u32 data_blocks_written,
+				       u32 hash_blocks_written)
+{
+	int result;
+	loff_t rollback_pos;
+	struct incfs_status is = {
+		.is_header = {
+			.h_md_entry_type = INCFS_MD_STATUS,
+			.h_record_size = cpu_to_le16(sizeof(is)),
+		},
+		.is_data_blocks_written = cpu_to_le32(data_blocks_written),
+		.is_hash_blocks_written = cpu_to_le32(hash_blocks_written),
+	};
+
+	LOCK_REQUIRED(bfc->bc_mutex);
+	rollback_pos = incfs_get_end_offset(bfc->bc_file);
+	result = append_md_to_backing_file(bfc, &is.is_header);
+	if (result)
+		truncate_backing_file(bfc, rollback_pos);
+
+	return result;
+}
+
+int incfs_write_status_to_backing_file(struct backing_file_context *bfc,
+				       loff_t status_offset,
+				       u32 data_blocks_written,
+				       u32 hash_blocks_written)
+{
+	struct incfs_status is;
+	int result;
+
+	if (!bfc)
+		return -EFAULT;
+
+	if (status_offset == 0)
+		return write_new_status_to_backing_file(bfc,
+				data_blocks_written, hash_blocks_written);
+
+	result = incfs_kread(bfc, &is, sizeof(is), status_offset);
+	if (result != sizeof(is))
+		return -EIO;
+
+	is.is_data_blocks_written = cpu_to_le32(data_blocks_written);
+	is.is_hash_blocks_written = cpu_to_le32(hash_blocks_written);
+	result = incfs_kwrite(bfc, &is, sizeof(is), status_offset);
+	if (result != sizeof(is))
+		return -EIO;
+
+	return 0;
+}
+
+int incfs_write_verity_signature_to_backing_file(
+		struct backing_file_context *bfc, struct mem_range signature,
+		loff_t *offset)
+{
+	struct incfs_file_verity_signature vs = {};
+	int result;
+	loff_t pos;
+
+	/* No verity signature section is equivalent to an empty section */
+	if (signature.data == NULL || signature.len == 0)
+		return 0;
+
+	pos = incfs_get_end_offset(bfc->bc_file);
+
+	vs = (struct incfs_file_verity_signature) {
+		.vs_header = (struct incfs_md_header) {
+			.h_md_entry_type = INCFS_MD_VERITY_SIGNATURE,
+			.h_record_size = cpu_to_le16(sizeof(vs)),
+			.h_next_md_offset = cpu_to_le64(0),
+		},
+		.vs_size = cpu_to_le32(signature.len),
+		.vs_offset = cpu_to_le64(pos),
+	};
+
+	result = write_to_bf(bfc, signature.data, signature.len, pos);
+	if (result)
+		goto err;
+
+	result = append_md_to_backing_file(bfc, &vs.vs_header);
+	if (result)
+		goto err;
+
+	*offset = pos;
+err:
+	if (result)
+		/* Error, rollback file changes */
+		truncate_backing_file(bfc, pos);
 	return result;
 }
 
 /*
  * Write a backing file header
  * It should always be called only on empty file.
- * incfs_super_block.s_first_md_offset is 0 for now, but will be updated
+ * fh.fh_first_md_offset is 0 for now, but will be updated
  * once first metadata record is added.
  */
 int incfs_write_fh_to_backing_file(struct backing_file_context *bfc,
@@ -384,6 +430,38 @@
 
 	fh.fh_file_size = cpu_to_le64(file_size);
 	fh.fh_uuid = *uuid;
+
+	LOCK_REQUIRED(bfc->bc_mutex);
+
+	file_pos = incfs_get_end_offset(bfc->bc_file);
+	if (file_pos != 0)
+		return -EEXIST;
+
+	return write_to_bf(bfc, &fh, sizeof(fh), file_pos);
+}
+
+/*
+ * Write a backing file header for a mapping file
+ * It should always be called only on empty file.
+ */
+int incfs_write_mapping_fh_to_backing_file(struct backing_file_context *bfc,
+				incfs_uuid_t *uuid, u64 file_size, u64 offset)
+{
+	struct incfs_file_header fh = {};
+	loff_t file_pos = 0;
+
+	if (!bfc)
+		return -EFAULT;
+
+	fh.fh_magic = cpu_to_le64(INCFS_MAGIC_NUMBER);
+	fh.fh_version = cpu_to_le64(INCFS_FORMAT_CURRENT_VER);
+	fh.fh_header_size = cpu_to_le16(sizeof(fh));
+	fh.fh_original_offset = cpu_to_le64(offset);
+	fh.fh_data_block_size = cpu_to_le16(INCFS_DATA_FILE_BLOCK_SIZE);
+
+	fh.fh_mapped_file_size = cpu_to_le64(file_size);
+	fh.fh_original_uuid = *uuid;
+	fh.fh_flags = cpu_to_le32(INCFS_FILE_MAPPED);
 
 	LOCK_REQUIRED(bfc->bc_mutex);
 
@@ -469,32 +547,8 @@
 	bm_entry.me_data_offset_lo = cpu_to_le32((u32)data_offset);
 	bm_entry.me_data_offset_hi = cpu_to_le16((u16)(data_offset >> 32));
 	bm_entry.me_data_size = cpu_to_le16(INCFS_DATA_FILE_BLOCK_SIZE);
-	bm_entry.me_flags = cpu_to_le16(INCFS_BLOCK_HASH);
 
 	return write_to_bf(bfc, &bm_entry, sizeof(bm_entry), bm_entry_off);
-}
-
-/* Initialize a new image in a given backing file. */
-int incfs_make_empty_backing_file(struct backing_file_context *bfc,
-				  incfs_uuid_t *uuid, u64 file_size)
-{
-	int result = 0;
-
-	if (!bfc || !bfc->bc_file)
-		return -EFAULT;
-
-	result = mutex_lock_interruptible(&bfc->bc_mutex);
-	if (result)
-		goto out;
-
-	result = truncate_backing_file(bfc, 0);
-	if (result)
-		goto out;
-
-	result = incfs_write_fh_to_backing_file(bfc, uuid, file_size);
-out:
-	mutex_unlock(&bfc->bc_mutex);
-	return result;
 }
 
 int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index,
@@ -575,7 +629,7 @@
 	if (file_size)
 		*file_size = le64_to_cpu(fh.fh_file_size);
 	if (flags)
-		*flags = le32_to_cpu(fh.fh_file_header_flags);
+		*flags = le32_to_cpu(fh.fh_flags);
 	return 0;
 }
 
@@ -590,14 +644,11 @@
 	ssize_t bytes_read = 0;
 	size_t md_record_size = 0;
 	loff_t next_record = 0;
-	loff_t prev_record = 0;
 	int res = 0;
 	struct incfs_md_header *md_hdr = NULL;
 
 	if (!bfc || !handler)
 		return -EFAULT;
-
-	LOCK_REQUIRED(bfc->bc_mutex);
 
 	if (handler->md_record_offset == 0)
 		return -EPERM;
@@ -612,7 +663,6 @@
 
 	md_hdr = &handler->md_buffer.md_header;
 	next_record = le64_to_cpu(md_hdr->h_next_md_offset);
-	prev_record = le64_to_cpu(md_hdr->h_prev_md_offset);
 	md_record_size = le16_to_cpu(md_hdr->h_record_size);
 
 	if (md_record_size > max_md_size) {
@@ -632,16 +682,6 @@
 		return -EBADMSG;
 	}
 
-	if (prev_record != handler->md_prev_record_offset) {
-		pr_warn("incfs: Metadata chain has been corrupted.");
-		return -EBADMSG;
-	}
-
-	if (le32_to_cpu(md_hdr->h_record_crc) != calc_md_crc(md_hdr)) {
-		pr_warn("incfs: Metadata CRC mismatch.");
-		return -EBADMSG;
-	}
-
 	switch (md_hdr->h_md_entry_type) {
 	case INCFS_MD_NONE:
 		break;
@@ -651,15 +691,26 @@
 				&handler->md_buffer.blockmap, handler);
 		break;
 	case INCFS_MD_FILE_ATTR:
-		if (handler->handle_file_attr)
-			res = handler->handle_file_attr(
-				&handler->md_buffer.file_attr, handler);
+		/*
+		 * File attrs no longer supported, ignore section for
+		 * compatibility
+		 */
 		break;
 	case INCFS_MD_SIGNATURE:
 		if (handler->handle_signature)
 			res = handler->handle_signature(
 				&handler->md_buffer.signature, handler);
 		break;
+	case INCFS_MD_STATUS:
+		if (handler->handle_status)
+			res = handler->handle_status(
+				&handler->md_buffer.status, handler);
+		break;
+	case INCFS_MD_VERITY_SIGNATURE:
+		if (handler->handle_verity_signature)
+			res = handler->handle_verity_signature(
+				&handler->md_buffer.verity_signature, handler);
+		break;
 	default:
 		res = -ENOTSUPP;
 		break;

--
Gitblit v1.6.2