Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27fe7f00 authored by Paul Lawrence's avatar Paul Lawrence Committed by Sahil Sonar
Browse files

ANDROID: Incremental fs: Add INCFS_IOC_GET_BLOCK_COUNT



Bug: 166638631
Test: incfs_test passes
Signed-off-by: default avatarPaul Lawrence <paullawrence@google.com>
Change-Id: Ib0f53dca9fc33dd87fd9f3992787e29104a1b12e
parent 87d88092
Loading
Loading
Loading
Loading
+37 −1
Original line number Diff line number Diff line
@@ -274,9 +274,29 @@ struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf)

void incfs_free_data_file(struct data_file *df)
{
	u32 blocks_written;

	if (!df)
		return;

	blocks_written = atomic_read(&df->df_data_blocks_written);
	if (blocks_written != df->df_initial_data_blocks_written) {
		struct backing_file_context *bfc = df->df_backing_file_context;
		int error = -1;

		if (bfc && !mutex_lock_interruptible(&bfc->bc_mutex)) {
			error = incfs_write_status_to_backing_file(
						df->df_backing_file_context,
						df->df_status_offset,
						blocks_written);
			mutex_unlock(&bfc->bc_mutex);
		}

		if (error)
			/* Nothing can be done, just warn */
			pr_warn("incfs: failed to write status to backing file\n");
	}

	incfs_free_mtree(df->df_hash_tree);
	incfs_free_bfc(df->df_backing_file_context);
	kfree(df);
@@ -1125,8 +1145,10 @@ int incfs_process_new_data_block(struct data_file *df,
			df->df_blockmap_off, flags);
		mutex_unlock(&bfc->bc_mutex);
	}
	if (!error)
	if (!error) {
		notify_pending_reads(mi, segment, block->block_index);
		atomic_inc(&df->df_data_blocks_written);
	}

	up_write(&segment->rwsem);

@@ -1303,6 +1325,19 @@ static int process_file_signature_md(struct incfs_file_signature *sg,
	return error;
}

static int process_status_md(struct incfs_status *is,
			     struct metadata_handler *handler)
{
	struct data_file *df = handler->context;

	df->df_initial_data_blocks_written = le32_to_cpu(is->is_blocks_written);
	atomic_set(&df->df_data_blocks_written,
		   df->df_initial_data_blocks_written);
	df->df_status_offset = handler->md_record_offset;

	return 0;
}

int incfs_scan_metadata_chain(struct data_file *df)
{
	struct metadata_handler *handler = NULL;
@@ -1330,6 +1365,7 @@ int incfs_scan_metadata_chain(struct data_file *df)
	handler->context = df;
	handler->handle_blockmap = process_blockmap_md;
	handler->handle_signature = process_file_signature_md;
	handler->handle_status = process_status_md;

	while (handler->md_record_offset > 0) {
		error = incfs_read_next_metadata_record(bfc, handler);
+8 −1
Original line number Diff line number Diff line
@@ -249,7 +249,14 @@ struct data_file {
	/* For mapped files, the offset into the actual file */
	loff_t df_mapped_offset;

	struct file_attr n_attr;
	/* Number of data blocks written to file */
	atomic_t df_data_blocks_written;

	/* Number of data blocks in the status block */
	u32 df_initial_data_blocks_written;

	/* Offset to status metadata header */
	loff_t df_status_offset;

	struct mtree *df_hash_tree;

+52 −0
Original line number Diff line number Diff line
@@ -316,6 +316,53 @@ int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
	return result;
}

static int write_new_status_to_backing_file(struct backing_file_context *bfc,
				       u32 blocks_written)
{
	struct incfs_status is = {};
	int result;
	loff_t rollback_pos;

	if (!bfc)
		return -EFAULT;

	LOCK_REQUIRED(bfc->bc_mutex);

	rollback_pos = incfs_get_end_offset(bfc->bc_file);

	is.is_header.h_md_entry_type = INCFS_MD_STATUS;
	is.is_header.h_record_size = cpu_to_le16(sizeof(is));
	is.is_blocks_written = cpu_to_le32(blocks_written);

	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 blocks_written)
{
	struct incfs_status is;
	int result;

	if (status_offset == 0)
		return write_new_status_to_backing_file(bfc, blocks_written);

	result = incfs_kread(bfc->bc_file, &is, sizeof(is), status_offset);
	if (result != sizeof(is))
		return -EIO;

	is.is_blocks_written = cpu_to_le32(blocks_written);
	result = incfs_kwrite(bfc->bc_file, &is, sizeof(is), status_offset);
	if (result != sizeof(is))
		return -EIO;

	return 0;
}

/*
 * Write a backing file header
 * It should always be called only on empty file.
@@ -637,6 +684,11 @@ int incfs_read_next_metadata_record(struct backing_file_context *bfc,
			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;
	default:
		res = -ENOTSUPP;
		break;
+17 −1
Original line number Diff line number Diff line
@@ -118,7 +118,8 @@ enum incfs_metadata_type {
	INCFS_MD_NONE = 0,
	INCFS_MD_BLOCK_MAP = 1,
	INCFS_MD_FILE_ATTR = 2,
	INCFS_MD_SIGNATURE = 3
	INCFS_MD_SIGNATURE = 3,
	INCFS_MD_STATUS = 4,
};

enum incfs_file_header_flags {
@@ -245,6 +246,14 @@ struct incfs_df_signature {
	u64 hash_offset;
};

struct incfs_status {
	struct incfs_md_header is_header;

	__le32 is_blocks_written; /* Number of blocks written */

	__le32 is_dummy[7]; /* Three spare fields */
};

/* State of the backing file. */
struct backing_file_context {
	/* Protects writes to bc_file */
@@ -269,12 +278,15 @@ struct metadata_handler {
		struct incfs_md_header md_header;
		struct incfs_blockmap blockmap;
		struct incfs_file_signature signature;
		struct incfs_status status;
	} 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);
};
#define INCFS_MAX_METADATA_RECORD_SIZE \
	FIELD_SIZEOF(struct metadata_handler, md_buffer)
@@ -311,6 +323,10 @@ int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc,
int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
					  struct mem_range sig, u32 tree_size);

int incfs_write_status_to_backing_file(struct backing_file_context *bfc,
				       loff_t status_offset,
				       u32 blocks_written);

int incfs_write_file_header_flags(struct backing_file_context *bfc, u32 flags);

int incfs_make_empty_backing_file(struct backing_file_context *bfc,
+21 −2
Original line number Diff line number Diff line
@@ -85,8 +85,6 @@ static const struct file_operations incfs_dir_fops = {
	.iterate = iterate_incfs_dir,
	.open = file_open,
	.release = file_release,
	.unlocked_ioctl = dispatch_ioctl,
	.compat_ioctl = dispatch_ioctl
};

static const struct dentry_operations incfs_dentry_ops = {
@@ -663,6 +661,25 @@ static long ioctl_get_filled_blocks(struct file *f, void __user *arg)
	return error;
}

static long ioctl_get_block_count(struct file *f, void __user *arg)
{
	struct incfs_get_block_count_args __user *args_usr_ptr = arg;
	struct incfs_get_block_count_args args = {};
	struct data_file *df = get_incfs_data_file(f);
	int error;

	if (!df)
		return -EINVAL;

	args.total_blocks_out = df->df_data_block_count;
	args.filled_blocks_out = atomic_read(&df->df_data_blocks_written);

	if (copy_to_user(args_usr_ptr, &args, sizeof(args)))
		return -EFAULT;

	return error;
}

static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg)
{
	switch (req) {
@@ -672,6 +689,8 @@ static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg)
		return ioctl_read_file_signature(f, (void __user *)arg);
	case INCFS_IOC_GET_FILLED_BLOCKS:
		return ioctl_get_filled_blocks(f, (void __user *)arg);
	case INCFS_IOC_GET_BLOCK_COUNT:
		return ioctl_get_block_count(f, (void __user *)arg);
	default:
		return -EINVAL;
	}
Loading