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

Commit 20ec909f authored by Paul Lawrence's avatar Paul Lawrence
Browse files

ANDROID: Incremental fs: Add UID to pending_read



Test: incfs_test passes
Bug: 160634477
Signed-off-by: default avatarPaul Lawrence <paullawrence@google.com>
Change-Id: Iaf817cf1f7ccd0109b2114b425ea7f26718345ab
parent 0eae0d27
Loading
Loading
Loading
Loading
+53 −21
Original line number Diff line number Diff line
@@ -391,6 +391,7 @@ static void log_block_read(struct mount_info *mi, incfs_uuid_t *id,
	s64 relative_us;
	union log_record record;
	size_t record_size;
	uid_t uid = current_uid().val;

	/*
	 * This may read the old value, but it's OK to delay the logging start
@@ -412,12 +413,14 @@ static void log_block_read(struct mount_info *mi, incfs_uuid_t *id,
	relative_us = now_us - head->base_record.absolute_ts_us;

	if (memcmp(id, &head->base_record.file_id, sizeof(incfs_uuid_t)) ||
	    relative_us >= 1ll << 32) {
	    relative_us >= 1ll << 32 ||
	    uid != head->base_record.uid) {
		record.full_record = (struct full_record){
			.type = FULL,
			.block_index = block_index,
			.file_id = *id,
			.absolute_ts_us = now_us,
			.uid = uid,
		};
		head->base_record.file_id = *id;
		record_size = sizeof(struct full_record);
@@ -833,6 +836,7 @@ static struct pending_read *add_pending_read(struct data_file *df,
	result->file_id = df->df_id;
	result->block_index = block_index;
	result->timestamp_us = ktime_to_us(ktime_get());
	result->uid = current_uid().val;

	spin_lock(&mi->pending_read_lock);

@@ -1396,6 +1400,7 @@ bool incfs_fresh_pending_reads_exist(struct mount_info *mi, int last_number)

int incfs_collect_pending_reads(struct mount_info *mi, int sn_lowerbound,
				struct incfs_pending_read_info *reads,
				struct incfs_pending_read_info2 *reads2,
				int reads_size, int *new_max_sn)
{
	int reported_reads = 0;
@@ -1424,10 +1429,24 @@ int incfs_collect_pending_reads(struct mount_info *mi, int sn_lowerbound,
		if (entry->serial_number <= sn_lowerbound)
			continue;

		if (reads) {
			reads[reported_reads].file_id = entry->file_id;
			reads[reported_reads].block_index = entry->block_index;
		reads[reported_reads].serial_number = entry->serial_number;
		reads[reported_reads].timestamp_us = entry->timestamp_us;
			reads[reported_reads].serial_number =
				entry->serial_number;
			reads[reported_reads].timestamp_us =
				entry->timestamp_us;
		}

		if (reads2) {
			reads2[reported_reads].file_id = entry->file_id;
			reads2[reported_reads].block_index = entry->block_index;
			reads2[reported_reads].serial_number =
				entry->serial_number;
			reads2[reported_reads].timestamp_us =
				entry->timestamp_us;
			reads2[reported_reads].uid = entry->uid;
		}

		if (entry->serial_number > *new_max_sn)
			*new_max_sn = entry->serial_number;
@@ -1473,8 +1492,9 @@ int incfs_get_uncollected_logs_count(struct mount_info *mi,
}

int incfs_collect_logged_reads(struct mount_info *mi,
			       struct read_log_state *reader_state,
			       struct read_log_state *state,
			       struct incfs_pending_read_info *reads,
			       struct incfs_pending_read_info2 *reads2,
			       int reads_size)
{
	int dst_idx;
@@ -1485,35 +1505,47 @@ int incfs_collect_logged_reads(struct mount_info *mi,
	head = &log->rl_head;
	tail = &log->rl_tail;

	if (reader_state->generation_id != head->generation_id) {
	if (state->generation_id != head->generation_id) {
		pr_debug("read ptr is wrong generation: %u/%u",
			 reader_state->generation_id, head->generation_id);
			 state->generation_id, head->generation_id);

		*reader_state = (struct read_log_state){
		*state = (struct read_log_state){
			.generation_id = head->generation_id,
		};
	}

	if (reader_state->current_record_no < tail->current_record_no) {
	if (state->current_record_no < tail->current_record_no) {
		pr_debug("read ptr is behind, moving: %u/%u -> %u/%u\n",
			 (u32)reader_state->next_offset,
			 (u32)reader_state->current_pass_no,
			 (u32)state->next_offset,
			 (u32)state->current_pass_no,
			 (u32)tail->next_offset, (u32)tail->current_pass_no);

		*reader_state = *tail;
		*state = *tail;
	}

	for (dst_idx = 0; dst_idx < reads_size; dst_idx++) {
		if (reader_state->current_record_no == head->current_record_no)
		if (state->current_record_no == head->current_record_no)
			break;

		log_read_one_record(log, reader_state);
		log_read_one_record(log, state);

		if (reads)
			reads[dst_idx] = (struct incfs_pending_read_info) {
			.file_id = reader_state->base_record.file_id,
			.block_index = reader_state->base_record.block_index,
			.serial_number = reader_state->current_record_no,
			.timestamp_us = reader_state->base_record.absolute_ts_us
				.file_id = state->base_record.file_id,
				.block_index = state->base_record.block_index,
				.serial_number = state->current_record_no,
				.timestamp_us =
					state->base_record.absolute_ts_us,
			};

		if (reads2)
			reads2[dst_idx] = (struct incfs_pending_read_info2) {
				.file_id = state->base_record.file_id,
				.block_index = state->base_record.block_index,
				.serial_number = state->current_record_no,
				.timestamp_us =
					state->base_record.absolute_ts_us,
				.uid = state->base_record.uid,
			};
	}

+6 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ struct full_record {
	u32 block_index : 30;
	incfs_uuid_t file_id;
	u64 absolute_ts_us;
	uid_t uid;
} __packed; /* 28 bytes */

struct same_file_record {
@@ -103,6 +104,7 @@ struct mount_options {
	unsigned int read_log_wakeup_count;
	bool no_backing_file_cache;
	bool no_backing_file_readahead;
	bool report_uid;
};

struct mount_info {
@@ -174,6 +176,8 @@ struct pending_read {

	int serial_number;

	uid_t uid;

	struct list_head mi_reads_list;

	struct list_head segment_reads_list;
@@ -308,11 +312,13 @@ bool incfs_fresh_pending_reads_exist(struct mount_info *mi, int last_number);
 */
int incfs_collect_pending_reads(struct mount_info *mi, int sn_lowerbound,
				struct incfs_pending_read_info *reads,
				struct incfs_pending_read_info2 *reads2,
				int reads_size, int *new_max_sn);

int incfs_collect_logged_reads(struct mount_info *mi,
			       struct read_log_state *start_state,
			       struct incfs_pending_read_info *reads,
			       struct incfs_pending_read_info2 *reads2,
			       int reads_size);
struct read_log_state incfs_get_log_state(struct mount_info *mi);
int incfs_get_uncollected_logs_count(struct mount_info *mi,
+9 −0
Original line number Diff line number Diff line
@@ -30,8 +30,17 @@ static ssize_t corefs_show(struct kobject *kobj,

static struct kobj_attribute corefs_attr = __ATTR_RO(corefs);

static ssize_t report_uid_show(struct kobject *kobj,
			       struct kobj_attribute *attr, char *buff)
{
	return snprintf(buff, PAGE_SIZE, "supported\n");
}

static struct kobj_attribute report_uid_attr = __ATTR_RO(report_uid);

static struct attribute *attributes[] = {
	&corefs_attr.attr,
	&report_uid_attr.attr,
	NULL,
};

+67 −26
Original line number Diff line number Diff line
@@ -217,6 +217,7 @@ enum parse_parameter {
	Opt_no_backing_file_readahead,
	Opt_rlog_pages,
	Opt_rlog_wakeup_cnt,
	Opt_report_uid,
	Opt_err
};

@@ -239,6 +240,7 @@ static const match_table_t option_tokens = {
	{ Opt_no_backing_file_readahead, "no_bf_readahead=%u" },
	{ Opt_rlog_pages, "rlog_pages=%u" },
	{ Opt_rlog_wakeup_cnt, "rlog_wakeup_cnt=%u" },
	{ Opt_report_uid, "report_uid" },
	{ Opt_err, NULL }
};

@@ -299,6 +301,9 @@ static int parse_options(struct mount_options *opts, char *str)
				return -EINVAL;
			opts->read_log_wakeup_count = value;
			break;
		case Opt_report_uid:
			opts->report_uid = true;
			break;
		default:
			return -EINVAL;
		}
@@ -462,8 +467,12 @@ static ssize_t pending_reads_read(struct file *f, char __user *buf, size_t len,
{
	struct pending_reads_state *pr_state = f->private_data;
	struct mount_info *mi = get_mount_info(file_superblock(f));
	bool report_uid;
	unsigned long page = 0;
	struct incfs_pending_read_info *reads_buf = NULL;
	size_t reads_to_collect = len / sizeof(*reads_buf);
	struct incfs_pending_read_info2 *reads_buf2 = NULL;
	size_t record_size;
	size_t reads_to_collect;
	int last_known_read_sn = READ_ONCE(pr_state->last_pending_read_sn);
	int new_max_sn = last_known_read_sn;
	int reads_collected = 0;
@@ -472,18 +481,29 @@ static ssize_t pending_reads_read(struct file *f, char __user *buf, size_t len,
	if (!mi)
		return -EFAULT;

	report_uid = mi->mi_options.report_uid;
	record_size = report_uid ? sizeof(*reads_buf2) : sizeof(*reads_buf);
	reads_to_collect = len / record_size;

	if (!incfs_fresh_pending_reads_exist(mi, last_known_read_sn))
		return 0;

	reads_buf = (struct incfs_pending_read_info *)get_zeroed_page(GFP_NOFS);
	if (!reads_buf)
	page = get_zeroed_page(GFP_NOFS);
	if (!page)
		return -ENOMEM;

	if (report_uid)
		reads_buf2 = (struct incfs_pending_read_info2 *) page;
	else
		reads_buf = (struct incfs_pending_read_info *) page;

	reads_to_collect =
		min_t(size_t, PAGE_SIZE / sizeof(*reads_buf), reads_to_collect);
		min_t(size_t, PAGE_SIZE / record_size, reads_to_collect);

	reads_collected = incfs_collect_pending_reads(mi, last_known_read_sn,
				reads_buf, reads_buf2, reads_to_collect,
				&new_max_sn);

	reads_collected = incfs_collect_pending_reads(
		mi, last_known_read_sn, reads_buf, reads_to_collect, &new_max_sn);
	if (reads_collected < 0) {
		result = reads_collected;
		goto out;
@@ -494,19 +514,19 @@ static ssize_t pending_reads_read(struct file *f, char __user *buf, size_t len,
	 * to reads buffer than userspace can handle.
	 */
	reads_collected = min_t(size_t, reads_collected, reads_to_collect);
	result = reads_collected * sizeof(*reads_buf);
	result = reads_collected * record_size;

	/* Copy reads info to the userspace buffer */
	if (copy_to_user(buf, reads_buf, result)) {
	if (copy_to_user(buf, (void *)page, result)) {
		result = -EFAULT;
		goto out;
	}

	WRITE_ONCE(pr_state->last_pending_read_sn, new_max_sn);
	*ppos = 0;

out:
	if (reads_buf)
		free_page((unsigned long)reads_buf);
	free_page(page);
	return result;
}

@@ -588,18 +608,35 @@ static ssize_t log_read(struct file *f, char __user *buf, size_t len,
	int total_reads_collected = 0;
	int rl_size;
	ssize_t result = 0;
	struct incfs_pending_read_info *reads_buf;
	ssize_t reads_to_collect = len / sizeof(*reads_buf);
	ssize_t reads_per_page = PAGE_SIZE / sizeof(*reads_buf);
	bool report_uid;
	unsigned long page = 0;
	struct incfs_pending_read_info *reads_buf = NULL;
	struct incfs_pending_read_info2 *reads_buf2 = NULL;
	size_t record_size;
	ssize_t reads_to_collect;
	ssize_t reads_per_page;

	if (!mi)
		return -EFAULT;

	report_uid = mi->mi_options.report_uid;
	record_size = report_uid ? sizeof(*reads_buf2) : sizeof(*reads_buf);
	reads_to_collect = len / record_size;
	reads_per_page = PAGE_SIZE / record_size;

	rl_size = READ_ONCE(mi->mi_log.rl_size);
	if (rl_size == 0)
		return 0;

	reads_buf = (struct incfs_pending_read_info *)__get_free_page(GFP_NOFS);
	if (!reads_buf)
	page = __get_free_page(GFP_NOFS);
	if (!page)
		return -ENOMEM;

	if (report_uid)
		reads_buf2 = (struct incfs_pending_read_info2 *) page;
	else
		reads_buf = (struct incfs_pending_read_info *) page;

	reads_to_collect = min_t(ssize_t, rl_size, reads_to_collect);
	while (reads_to_collect > 0) {
		struct read_log_state next_state;
@@ -607,35 +644,32 @@ static ssize_t log_read(struct file *f, char __user *buf, size_t len,

		memcpy(&next_state, &log_state->state, sizeof(next_state));
		reads_collected = incfs_collect_logged_reads(
			mi, &next_state, reads_buf,
			mi, &next_state, reads_buf, reads_buf2,
			min_t(ssize_t, reads_to_collect, reads_per_page));
		if (reads_collected <= 0) {
			result = total_reads_collected ?
					 total_reads_collected *
						 sizeof(*reads_buf) :
					 total_reads_collected * record_size :
					 reads_collected;
			goto out;
		}
		if (copy_to_user(buf, reads_buf,
				 reads_collected * sizeof(*reads_buf))) {
		if (copy_to_user(buf, (void *) page,
				 reads_collected * record_size)) {
			result = total_reads_collected ?
					 total_reads_collected *
						 sizeof(*reads_buf) :
					 total_reads_collected * record_size :
					 -EFAULT;
			goto out;
		}

		memcpy(&log_state->state, &next_state, sizeof(next_state));
		total_reads_collected += reads_collected;
		buf += reads_collected * sizeof(*reads_buf);
		buf += reads_collected * record_size;
		reads_to_collect -= reads_collected;
	}

	result = total_reads_collected * sizeof(*reads_buf);
	result = total_reads_collected * record_size;
	*ppos = 0;
out:
	if (reads_buf)
		free_page((unsigned long)reads_buf);
	free_page(page);
	return result;
}

@@ -2473,6 +2507,11 @@ static int incfs_remount_fs(struct super_block *sb, int *flags, char *data)
	if (err)
		return err;

	if (options.report_uid != mi->mi_options.report_uid) {
		pr_err("incfs: Can't change report_uid mount option on remount\n");
		return -EOPNOTSUPP;
	}

	err = incfs_realloc_mount_info(mi, &options);
	if (err)
		return err;
@@ -2505,5 +2544,7 @@ static int show_options(struct seq_file *m, struct dentry *root)
		seq_puts(m, ",no_bf_cache");
	if (mi->mi_options.no_backing_file_readahead)
		seq_puts(m, ",no_bf_readahead");
	if (mi->mi_options.report_uid)
		seq_puts(m, ",report_uid");
	return 0;
}
+45 −0
Original line number Diff line number Diff line
@@ -96,6 +96,23 @@
#define INCFS_IOC_CREATE_MAPPED_FILE \
	_IOWR(INCFS_IOCTL_BASE_CODE, 35, struct incfs_create_mapped_file_args)

/* ===== sysfs feature flags ===== */
/*
 * Each flag is represented by a file in /sys/fs/incremental-fs/features
 * If the file exists the feature is supported
 * Also the file contents will be the line "supported"
 */

/*
 * Basic flag stating that the core incfs file system is available
 */
#define INCFS_FEATURE_FLAG_COREFS "corefs"

/*
 * report_uid mount option is supported
 */
#define INCFS_FEATURE_FLAG_REPORT_UID "report_uid"

enum incfs_compression_alg {
	COMPRESSION_NONE = 0,
	COMPRESSION_LZ4 = 1
@@ -113,6 +130,8 @@ typedef struct {
/*
 * Description of a pending read. A pending read - a read call by
 * a userspace program for which the filesystem currently doesn't have data.
 *
 * Reads from .pending_reads and .log return an array of these structure
 */
struct incfs_pending_read_info {
	/* Id of a file that is being read from. */
@@ -128,6 +147,32 @@ struct incfs_pending_read_info {
	__u32 serial_number;
};

/*
 * Description of a pending read. A pending read - a read call by
 * a userspace program for which the filesystem currently doesn't have data.
 *
 * This version of incfs_pending_read_info is used whenever the file system is
 * mounted with the report_uid flag
 */
struct incfs_pending_read_info2 {
	/* Id of a file that is being read from. */
	incfs_uuid_t file_id;

	/* A number of microseconds since system boot to the read. */
	__aligned_u64 timestamp_us;

	/* Index of a file block that is being read. */
	__u32 block_index;

	/* A serial number of this pending read. */
	__u32 serial_number;

	/* The UID of the reading process */
	__u32 uid;

	__u32 reserved;
};

/*
 * Description of a data or hash block to add to a data file.
 */
Loading