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

Commit 712e380a authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Merge Incremental fs branch 'remotes/origin/tmp-04df3ce7' into msm-4.14"

parents 835224c4 f35a10bb
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@ config INCREMENTAL_FS
	select X509_CERTIFICATE_PARSER
	select ASYMMETRIC_KEY_TYPE
	select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
	select PKCS7_MESSAGE_PARSER
	help
	  Incremental FS is a read-only virtual file system that facilitates execution
	  of programs while their binaries are still being lazily downloaded over the
+565 −275

File changed.

Preview size limit exceeded, changes collapsed.

+83 −28
Original line number Diff line number Diff line
@@ -20,38 +20,78 @@

#define SEGMENTS_PER_FILE 3

struct read_log_record {
	u32 block_index : 31;

	u32 timed_out : 1;

	u64 timestamp_us;
enum LOG_RECORD_TYPE {
	FULL,
	SAME_FILE,
	SAME_FILE_NEXT_BLOCK,
	SAME_FILE_NEXT_BLOCK_SHORT,
};

struct full_record {
	enum LOG_RECORD_TYPE type : 2; /* FULL */
	u32 block_index : 30;
	incfs_uuid_t file_id;
} __packed;
	u64 absolute_ts_us;
} __packed; /* 28 bytes */

struct same_file_record {
	enum LOG_RECORD_TYPE type : 2; /* SAME_FILE */
	u32 block_index : 30;
	u32 relative_ts_us; /* max 2^32 us ~= 1 hour (1:11:30) */
} __packed; /* 12 bytes */

struct same_file_next_block {
	enum LOG_RECORD_TYPE type : 2; /* SAME_FILE_NEXT_BLOCK */
	u32 relative_ts_us : 30; /* max 2^30 us ~= 15 min (17:50) */
} __packed; /* 4 bytes */

struct same_file_next_block_short {
	enum LOG_RECORD_TYPE type : 2; /* SAME_FILE_NEXT_BLOCK_SHORT */
	u16 relative_ts_us : 14; /* max 2^14 us ~= 16 ms */
} __packed; /* 2 bytes */

union log_record {
	struct full_record full_record;
	struct same_file_record same_file_record;
	struct same_file_next_block same_file_next_block;
	struct same_file_next_block_short same_file_next_block_short;
};

struct read_log_state {
	/* Next slot in rl_ring_buf to write to. */
	u32 next_index;
	/* Log buffer generation id, incremented on configuration changes */
	u32 generation_id;

	/* Offset in rl_ring_buf to write into. */
	u32 next_offset;

	/* Current number of writer pass over rl_ring_buf */
	/* Current number of writer passes over rl_ring_buf */
	u32 current_pass_no;

	/* Current full_record to diff against */
	struct full_record base_record;

	/* Current record number counting from configuration change */
	u64 current_record_no;
};

/* A ring buffer to save records about data blocks which were recently read. */
struct read_log {
	struct read_log_record *rl_ring_buf;
	void *rl_ring_buf;

	struct read_log_state rl_state;
	int rl_size;

	spinlock_t rl_writer_lock;
	struct read_log_state rl_head;

	int rl_size;
	struct read_log_state rl_tail;

	/*
	 * A queue of waiters who want to be notified about reads.
	 */
	/* A lock to protect the above fields */
	spinlock_t rl_lock;

	/* A queue of waiters who want to be notified about reads */
	wait_queue_head_t ml_notif_wq;

	/* A work item to wake up those waiters without slowing down readers */
	struct delayed_work ml_wakeup_work;
};

struct mount_options {
@@ -105,6 +145,12 @@ struct mount_info {

	/* Temporary buffer for read logger. */
	struct read_log mi_log;

	void *log_xattr;
	size_t log_xattr_size;

	void *pending_read_xattr;
	size_t pending_read_xattr_size;
};

struct data_file_block {
@@ -177,16 +223,20 @@ struct data_file {
	/* File size in bytes */
	loff_t df_size;

	int df_block_count; /* File size in DATA_FILE_BLOCK_SIZE blocks */
	/* File header flags */
	u32 df_header_flags;

	/* File size in DATA_FILE_BLOCK_SIZE blocks */
	int df_data_block_count;

	/* Total number of blocks, data + hash */
	int df_total_block_count;

	struct file_attr n_attr;

	struct mtree *df_hash_tree;

	struct ondisk_signature *df_signature;

	/* True, if file signature has already been validated. */
	bool df_signature_validated;
	struct incfs_df_signature *df_signature;
};

struct dir_file {
@@ -213,6 +263,9 @@ struct mount_info *incfs_alloc_mount_info(struct super_block *sb,
					  struct mount_options *options,
					  struct path *backing_dir_path);

int incfs_realloc_mount_info(struct mount_info *mi,
			     struct mount_options *options);

void incfs_free_mount_info(struct mount_info *mi);

struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf);
@@ -223,18 +276,20 @@ int incfs_scan_metadata_chain(struct data_file *df);
struct dir_file *incfs_open_dir_file(struct mount_info *mi, struct file *bf);
void incfs_free_dir_file(struct dir_file *dir);

ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df,
ssize_t incfs_read_data_file_block(struct mem_range dst, struct file *f,
				   int index, int timeout_ms,
				   struct mem_range tmp);

int incfs_get_filled_blocks(struct data_file *df,
			    struct incfs_get_filled_blocks_args *arg);

int incfs_read_file_signature(struct data_file *df, struct mem_range dst);

int incfs_process_new_data_block(struct data_file *df,
				 struct incfs_new_data_block *block, u8 *data);
				 struct incfs_fill_block *block, u8 *data);

int incfs_process_new_hash_block(struct data_file *df,
				 struct incfs_new_data_block *block, u8 *data);

				 struct incfs_fill_block *block, u8 *data);

bool incfs_fresh_pending_reads_exist(struct mount_info *mi, int last_number);

@@ -253,14 +308,14 @@ int incfs_collect_logged_reads(struct mount_info *mi,
			       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,
				     struct read_log_state state);
				     const struct read_log_state *state);

static inline struct inode_info *get_incfs_node(struct inode *inode)
{
	if (!inode)
		return NULL;

	if (inode->i_sb->s_magic != INCFS_MAGIC_NUMBER) {
	if (inode->i_sb->s_magic != (long) INCFS_MAGIC_NUMBER) {
		/* This inode doesn't belong to us. */
		pr_warn_once("incfs: %s on an alien inode.", __func__);
		return NULL;
+65 −61
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/kernel.h>

#include "format.h"
#include "data_mgmt.h"

struct backing_file_context *incfs_alloc_bfc(struct file *backing_file)
{
@@ -93,7 +94,6 @@ 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 res = 0;

	if (!bfc)
		return -EFAULT;
@@ -110,28 +110,18 @@ static int append_zeros(struct backing_file_context *bfc, size_t len)
	 */
	file_size = incfs_get_end_offset(bfc->bc_file);
	new_last_byte_offset = file_size + len - 1;
	res = vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1);
	if (res)
		return res;

	res = vfs_fsync_range(bfc->bc_file, file_size, file_size + len, 1);
	return res;
	return vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1);
}

static int write_to_bf(struct backing_file_context *bfc, const void *buf,
			size_t count, loff_t pos, bool sync)
			size_t count, loff_t pos)
{
	ssize_t res = 0;
	ssize_t res = incfs_kwrite(bfc->bc_file, buf, count, pos);

	res = incfs_kwrite(bfc->bc_file, buf, count, pos);
	if (res < 0)
		return res;
	if (res != count)
		return -EIO;

	if (sync)
		return vfs_fsync_range(bfc->bc_file, pos, pos + count, 1);

	return 0;
}

@@ -185,7 +175,7 @@ static int append_md_to_backing_file(struct backing_file_context *bfc,
	/* Write the metadata record to the end of the backing file */
	record_offset = file_pos;
	new_md_offset = cpu_to_le64(record_offset);
	result = write_to_bf(bfc, record, record_size, file_pos, true);
	result = write_to_bf(bfc, record, record_size, file_pos);
	if (result)
		return result;

@@ -206,7 +196,7 @@ static int append_md_to_backing_file(struct backing_file_context *bfc,
				    fh_first_md_offset);
	}
	result = write_to_bf(bfc, &new_md_offset, sizeof(new_md_offset),
				file_pos, true);
			     file_pos);
	if (result)
		return result;

@@ -214,12 +204,22 @@ static int append_md_to_backing_file(struct backing_file_context *bfc,
	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));
}

/*
 * Reserve 0-filled space for the blockmap body, and append
 * incfs_blockmap metadata record pointing to it.
 */
int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc,
				u32 block_count, loff_t *map_base_off)
					 u32 block_count)
{
	struct incfs_blockmap blockmap = {};
	int result = 0;
@@ -245,12 +245,9 @@ int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc,
	/* Write blockmap metadata record pointing to the body written above. */
	blockmap.m_base_offset = cpu_to_le64(file_end);
	result = append_md_to_backing_file(bfc, &blockmap.m_header);
	if (result) {
	if (result)
		/* Error, rollback file changes */
		truncate_backing_file(bfc, file_end);
	} else if (map_base_off) {
		*map_base_off = file_end;
	}

	return result;
}
@@ -283,7 +280,7 @@ int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc,
	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, true);
	result = write_to_bf(bfc, value.data, value.len, value_offset);
	if (result)
		return result;

@@ -299,9 +296,7 @@ int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc,
}

int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
		u8 hash_alg, u32 tree_size,
		struct mem_range root_hash, struct mem_range add_data,
		struct mem_range sig)
					  struct mem_range sig, u32 tree_size)
{
	struct incfs_file_signature sg = {};
	int result = 0;
@@ -311,8 +306,6 @@ int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,

	if (!bfc)
		return -EFAULT;
	if (root_hash.len > sizeof(sg.sg_root_hash))
		return -E2BIG;

	LOCK_REQUIRED(bfc->bc_mutex);

@@ -321,32 +314,19 @@ int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
	sg.sg_header.h_md_entry_type = INCFS_MD_SIGNATURE;
	sg.sg_header.h_record_size = cpu_to_le16(sizeof(sg));
	sg.sg_header.h_next_md_offset = cpu_to_le64(0);
	sg.sg_hash_alg = hash_alg;
	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);

		result = write_to_bf(bfc, sig.data, sig.len, pos, false);
		if (result)
			goto err;
	}

	if (add_data.len > 0) {
		loff_t pos = incfs_get_end_offset(bfc->bc_file);

		sg.sg_add_data_size = cpu_to_le32(add_data.len);
		sg.sg_add_data_offset = cpu_to_le64(pos);

		result = write_to_bf(bfc, add_data.data,
			add_data.len, pos, false);
		result = write_to_bf(bfc, sig.data, sig.len, pos);
		if (result)
			goto err;
	}

	tree_area_pos = incfs_get_end_offset(bfc->bc_file);
	if (hash_alg && tree_size > 0) {
	if (tree_size > 0) {
		if (tree_size > 5 * INCFS_DATA_FILE_BLOCK_SIZE) {
			/*
			 * If hash tree is big enough, it makes sense to
@@ -369,15 +349,13 @@ int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
		sg.sg_hash_tree_size = cpu_to_le32(tree_size);
		sg.sg_hash_tree_offset = cpu_to_le64(tree_area_pos);
	}
	memcpy(sg.sg_root_hash, root_hash.data, root_hash.len);

	/* Write a hash tree metadata record pointing to the hash tree above. */
	result = append_md_to_backing_file(bfc, &sg.sg_header);
err:
	if (result) {
	if (result)
		/* Error, rollback file changes */
		truncate_backing_file(bfc, rollback_pos);
	}
	return result;
}

@@ -411,7 +389,7 @@ int incfs_write_fh_to_backing_file(struct backing_file_context *bfc,
	if (file_pos != 0)
		return -EEXIST;

	return write_to_bf(bfc, &fh, sizeof(fh), file_pos, true);
	return write_to_bf(bfc, &fh, sizeof(fh), file_pos);
}

/* Write a given data block and update file's blockmap to point it. */
@@ -440,7 +418,7 @@ int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc,
	}

	/* Write the block data at the end of the backing file. */
	result = write_to_bf(bfc, block.data, block.len, data_offset, false);
	result = write_to_bf(bfc, block.data, block.len, data_offset);
	if (result)
		return result;

@@ -450,18 +428,25 @@ int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc,
	bm_entry.me_data_size = cpu_to_le16((u16)block.len);
	bm_entry.me_flags = cpu_to_le16(flags);

	result = write_to_bf(bfc, &bm_entry, sizeof(bm_entry),
				bm_entry_off, false);
	return result;
	return write_to_bf(bfc, &bm_entry, sizeof(bm_entry),
				bm_entry_off);
}

int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc,
					   struct mem_range block,
					int block_index, loff_t hash_area_off)
					   int block_index,
					   loff_t hash_area_off,
					   loff_t bm_base_off,
					   loff_t file_size)
{
	struct incfs_blockmap_entry bm_entry = {};
	int result;
	loff_t data_offset = 0;
	loff_t file_end = 0;

	loff_t bm_entry_off =
		bm_base_off +
		sizeof(struct incfs_blockmap_entry) *
			(block_index + get_blocks_count_for_size(file_size));

	if (!bfc)
		return -EFAULT;
@@ -475,7 +460,16 @@ int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc,
		return -EINVAL;
	}

	return write_to_bf(bfc, block.data, block.len, data_offset, false);
	result = write_to_bf(bfc, block.data, block.len, data_offset);
	if (result)
		return result;

	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. */
@@ -505,8 +499,19 @@ int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index,
			loff_t bm_base_off,
			struct incfs_blockmap_entry *bm_entry)
{
	return incfs_read_blockmap_entries(bfc, bm_entry, block_index, 1,
	int error = incfs_read_blockmap_entries(bfc, bm_entry, block_index, 1,
						bm_base_off);

	if (error < 0)
		return error;

	if (error == 0)
		return -EIO;

	if (error != 1)
		return -EFAULT;

	return 0;
}

int incfs_read_blockmap_entries(struct backing_file_context *bfc,
@@ -530,15 +535,12 @@ int incfs_read_blockmap_entries(struct backing_file_context *bfc,
			     bm_entry_off);
	if (result < 0)
		return result;
	if (result < bytes_to_read)
		return -EIO;
	return 0;
	return result / sizeof(*entries);
}


int incfs_read_file_header(struct backing_file_context *bfc,
			   loff_t *first_md_off, incfs_uuid_t *uuid,
			   u64 *file_size)
			   u64 *file_size, u32 *flags)
{
	ssize_t bytes_read = 0;
	struct incfs_file_header fh = {};
@@ -572,6 +574,8 @@ int incfs_read_file_header(struct backing_file_context *bfc,
		*uuid = fh.fh_uuid;
	if (file_size)
		*file_size = le64_to_cpu(fh.fh_file_size);
	if (flags)
		*flags = le32_to_cpu(fh.fh_file_header_flags);
	return 0;
}

+29 −38
Original line number Diff line number Diff line
@@ -121,6 +121,10 @@ enum incfs_metadata_type {
	INCFS_MD_SIGNATURE = 3
};

enum incfs_file_header_flags {
	INCFS_FILE_COMPLETE = 1 << 0,
};

/* Header included at the beginning of all metadata records on the disk. */
struct incfs_md_header {
	__u8 h_md_entry_type;
@@ -159,8 +163,8 @@ struct incfs_file_header {
	/* INCFS_DATA_FILE_BLOCK_SIZE */
	__le16 fh_data_block_size;

	/* Padding, also reserved for future use. */
	__le32 fh_dummy;
	/* File flags, from incfs_file_header_flags */
	__le32 fh_file_header_flags;

	/* Offset of the first metadata record */
	__le64 fh_first_md_offset;
@@ -178,6 +182,7 @@ struct incfs_file_header {

enum incfs_block_map_entry_flags {
	INCFS_BLOCK_COMPRESSED_LZ4 = (1 << 0),
	INCFS_BLOCK_HASH = (1 << 1),
};

/* Block map entry pointing to an actual location of the data block. */
@@ -217,27 +222,27 @@ struct incfs_file_attr {
	__le32 fa_crc;
} __packed;

/* Metadata record for file attribute. Type = INCFS_MD_SIGNATURE */
/* Metadata record for file signature. Type = INCFS_MD_SIGNATURE */
struct incfs_file_signature {
	struct incfs_md_header sg_header;

	__u8 sg_hash_alg; /* Value from incfs_hash_tree_algorithm */
	__le32 sg_sig_size; /* The size of the signature. */

	__le64 sg_sig_offset; /* Signature's offset in the backing file */

	__le32 sg_hash_tree_size; /* The size of the hash tree. */

	__le64 sg_hash_tree_offset; /* Hash tree offset in the backing file */

	__u8 sg_root_hash[INCFS_MAX_HASH_SIZE];

	__le32 sg_sig_size; /* The size of the pkcs7 signature. */

	__le64 sg_sig_offset; /* pkcs7 signature's offset in the backing file */

	__le32 sg_add_data_size; /* The size of the additional data. */

	__le64 sg_add_data_offset; /* Additional data's offset */
} __packed;

/* In memory version of above */
struct incfs_df_signature {
	u32 sig_size;
	u64 sig_offset;
	u32 hash_size;
	u64 hash_offset;
};

/* State of the backing file. */
struct backing_file_context {
	/* Protects writes to bc_file */
@@ -253,23 +258,6 @@ struct backing_file_context {
	loff_t bc_last_md_record_offset;
};


/* Backing file locations of things required for signature validation. */
struct ondisk_signature {

	loff_t add_data_offset; /* Additional data's offset */

	loff_t sig_offset; /* pkcs7 signature's offset in the backing file */

	loff_t mtree_offset; /* Backing file offset of the hash tree. */

	u32 add_data_size; /* The size of the additional data. */

	u32 sig_size; /* The size of the pkcs7 signature. */

	u32 mtree_size; /* The size of the hash tree. */
};

struct metadata_handler {
	loff_t md_record_offset;
	loff_t md_prev_record_offset;
@@ -301,7 +289,7 @@ void incfs_free_bfc(struct backing_file_context *bfc);

/* Writing stuff */
int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc,
					 u32 block_count, loff_t *map_base_off);
					 u32 block_count);

int incfs_write_fh_to_backing_file(struct backing_file_context *bfc,
				   incfs_uuid_t *uuid, u64 file_size);
@@ -313,15 +301,18 @@ int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc,

int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc,
					   struct mem_range block,
					int block_index, loff_t hash_area_off);
					   int block_index,
					   loff_t hash_area_off,
					   loff_t bm_base_off,
					   loff_t file_size);

int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc,
		struct mem_range value, struct incfs_file_attr *attr);

int incfs_write_signature_to_backing_file(struct backing_file_context *bfc,
		u8 hash_alg, u32 tree_size,
		struct mem_range root_hash, struct mem_range add_data,
		struct mem_range sig);
					  struct mem_range sig, u32 tree_size);

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

int incfs_make_empty_backing_file(struct backing_file_context *bfc,
				  incfs_uuid_t *uuid, u64 file_size);
@@ -329,7 +320,7 @@ int incfs_make_empty_backing_file(struct backing_file_context *bfc,
/* Reading stuff */
int incfs_read_file_header(struct backing_file_context *bfc,
			   loff_t *first_md_off, incfs_uuid_t *uuid,
			   u64 *file_size);
			   u64 *file_size, u32 *flags);

int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index,
			      loff_t bm_base_off,
Loading