[RFCv1 67/72] sec: support encrypted files handling in pfsck mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Sebastien Buisson <sbuisson@xxxxxxx>

e2fsck needs to be improved in order to support encrypted files
handling in parallel fsck mode. The e2fsck_merge_encrypted_info()
function is added to merge encrypted inodes info collected from
different threads in pass1, so that it can be used in pass2.

Signed-off-by: Sebastien Buisson <sbuisson@xxxxxxx>
Tested-by: Maloo <maloo@xxxxxxxxxxxxx>
Reviewed-by: Li Dongyang <dongyangli@xxxxxxx>
Reviewed-by: Andreas Dilger <adilger@xxxxxxxxxxxxx>
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@xxxxxxxxx>
---
 e2fsck/e2fsck.h          |   2 +
 e2fsck/encrypted_files.c | 139 +++++++++++++++++++++++++++++++++++++++
 e2fsck/pass1.c           |  26 +++++++-
 3 files changed, 164 insertions(+), 3 deletions(-)

diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 1e82b048..e4fb782a 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -642,6 +642,8 @@ __u32 find_encryption_policy(e2fsck_t ctx, ext2_ino_t ino);
 
 void destroy_encryption_policy_map(e2fsck_t ctx);
 void destroy_encrypted_file_info(e2fsck_t ctx);
+int e2fsck_merge_encrypted_info(e2fsck_t ctx, struct encrypted_file_info *src,
+				struct encrypted_file_info *dest);
 
 /* extents.c */
 errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino);
diff --git a/e2fsck/encrypted_files.c b/e2fsck/encrypted_files.c
index 16be2d6d..53e03a62 100644
--- a/e2fsck/encrypted_files.c
+++ b/e2fsck/encrypted_files.c
@@ -456,3 +456,142 @@ void destroy_encrypted_file_info(e2fsck_t ctx)
 		ctx->encrypted_files = NULL;
 	}
 }
+
+/**
+ * Search policy matching @policy in @info->policies
+ * @ctx: e2fsck context
+ * @info: encrypted_file_info to look into
+ * @policy: the policy we are looking for
+ * @parent: (out) last known parent, useful to insert a new leaf
+ *	    in @info->policies
+ *
+ * Return: id of found policy on success, -1 if no matching policy found.
+ */
+static inline int search_policy(e2fsck_t ctx, struct encrypted_file_info *info,
+				union fscrypt_policy policy,
+				struct rb_node **parent)
+{
+	struct rb_node *n = info->policies.rb_node;
+	struct policy_map_entry *entry;
+
+	while (n) {
+		int res;
+
+		*parent = n;
+		entry = ext2fs_rb_entry(n, struct policy_map_entry, node);
+		res = cmp_fscrypt_policies(ctx, &policy, &entry->policy);
+		if (res < 0)
+			n = n->rb_left;
+		else if (res > 0)
+			n = n->rb_right;
+		else
+			return entry->policy_id;
+	}
+	return -1;
+}
+
+/*
+ * Merge @src encrypted info into @dest
+ */
+int e2fsck_merge_encrypted_info(e2fsck_t ctx, struct encrypted_file_info *src,
+				 struct encrypted_file_info *dest)
+{
+	struct rb_root *src_policies = &src->policies;
+	__u32 *policy_trans;
+	int i, rc = 0;
+
+	if (dest->file_ranges[src->file_ranges_count - 1].last_ino >
+	    src->file_ranges[0].first_ino) {
+		/* Should never get here */
+		fatal_error(ctx, "Encrypted inodes processed out of order");
+	}
+
+	rc = ext2fs_get_array(src->next_policy_id, sizeof(__u32),
+			      &policy_trans);
+	if (rc)
+		return rc;
+
+	/* First, deal with the encryption policy => ID map.
+	 * Compare encryption policies in src with policies already recorded
+	 * in dest. It can be similar policies, but recorded with a different
+	 * id, so policy_trans array converts policy ids in src to ids in dest.
+	 * This loop examines each policy in src->policies rb tree, updates
+	 * policy_trans, and removes the entry from src, so that src->policies
+	 * rb tree is cleaned up at the end of the loop.
+	 */
+	while (!ext2fs_rb_empty_root(src_policies)) {
+		struct policy_map_entry *entry, *newentry;
+		struct rb_node *new, *parent = NULL;
+		int existing_polid;
+
+		entry = ext2fs_rb_entry(src_policies->rb_node,
+					struct policy_map_entry, node);
+		existing_polid = search_policy(ctx, dest,
+					       entry->policy, &parent);
+		if (existing_polid >= 0) {
+			/* The policy in src is already recorded in dest,
+			 * so just update its id.
+			 */
+			policy_trans[entry->policy_id] = existing_polid;
+		} else {
+			/* The policy in src is new to dest, so insert it
+			 * with the next available id (its original id could
+			 * be already used in dest).
+			 */
+			rc = ext2fs_get_mem(sizeof(*newentry), &newentry);
+			if (rc)
+				goto out_merge;
+			newentry->policy_id = dest->next_policy_id++;
+			newentry->policy = entry->policy;
+			ext2fs_rb_link_node(&newentry->node, parent, &new);
+			ext2fs_rb_insert_color(&newentry->node,
+					       &dest->policies);
+			policy_trans[entry->policy_id] = newentry->policy_id;
+		}
+		ext2fs_rb_erase(&entry->node, src_policies);
+		ext2fs_free_mem(&entry);
+	}
+
+	/* Second, deal with the inode number => encryption policy ID map. */
+	if (dest->file_ranges_capacity <
+	    dest->file_ranges_count + src->file_ranges_count) {
+		/* dest->file_ranges is too short, increase its capacity. */
+		size_t new_capacity = dest->file_ranges_count +
+			src->file_ranges_count;
+
+		/* Make sure we at least double the capacity. */
+		if (new_capacity < (dest->file_ranges_capacity * 2))
+			new_capacity = dest->file_ranges_capacity * 2;
+
+		/* We won't need more than the filesystem's inode count. */
+		if (new_capacity > ctx->fs->super->s_inodes_count)
+			new_capacity = ctx->fs->super->s_inodes_count;
+
+		rc = ext2fs_resize_mem(dest->file_ranges_capacity *
+				       sizeof(struct encrypted_file_range),
+				       new_capacity *
+				       sizeof(struct encrypted_file_range),
+				       &dest->file_ranges);
+		if (rc) {
+			fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_INODE_LIST,
+				    NULL);
+			/* Should never get here */
+			ctx->flags |= E2F_FLAG_ABORT;
+			goto out_merge;
+		}
+
+		dest->file_ranges_capacity = new_capacity;
+	}
+	/* Copy file ranges from src to dest. */
+	for (i = 0; i < src->file_ranges_count; i++) {
+		/* Make sure to convert policy ids in src. */
+		src->file_ranges[i].policy_id =
+			policy_trans[src->file_ranges[i].policy_id];
+		dest->file_ranges[dest->file_ranges_count++] =
+			src->file_ranges[i];
+	}
+
+out_merge:
+	ext2fs_free_mem(&policy_trans);
+	return rc;
+}
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 7345c96d..e7dc017c 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -2411,9 +2411,6 @@ void e2fsck_pass1_run(e2fsck_t ctx)
 		ctx->ea_block_quota_inodes = 0;
 	}
 
-	/* We don't need the encryption policy => ID map any more */
-	destroy_encryption_policy_map(ctx);
-
 	if (ctx->flags & E2F_FLAG_RESTART) {
 		/*
 		 * Only the master copy of the superblock and block
@@ -2703,6 +2700,23 @@ static void e2fsck_pass1_merge_dx_dir(e2fsck_t global_ctx, e2fsck_t thread_ctx)
 	e2fsck_merge_dx_dir(global_ctx, thread_ctx);
 }
 
+static int e2fsck_pass1_merge_encrypted_info(e2fsck_t global_ctx,
+					      e2fsck_t thread_ctx)
+{
+	if (thread_ctx->encrypted_files == NULL)
+		return 0;
+
+	if (global_ctx->encrypted_files == NULL) {
+		global_ctx->encrypted_files = thread_ctx->encrypted_files;
+		thread_ctx->encrypted_files = NULL;
+		return 0;
+	}
+
+	return e2fsck_merge_encrypted_info(global_ctx,
+					   thread_ctx->encrypted_files,
+					   global_ctx->encrypted_files);
+}
+
 static inline errcode_t
 e2fsck_pass1_merge_icount(ext2_icount_t *dest_icount,
 			  ext2_icount_t *src_icount)
@@ -2963,6 +2977,12 @@ static errcode_t e2fsck_pass1_merge_context(e2fsck_t global_ctx,
 
 	e2fsck_pass1_merge_dir_info(global_ctx, thread_ctx);
 	e2fsck_pass1_merge_dx_dir(global_ctx, thread_ctx);
+	retval = e2fsck_pass1_merge_encrypted_info(global_ctx, thread_ctx);
+	if (retval) {
+		com_err(global_ctx->program_name, 0,
+			_("while merging encrypted info\n"));
+		return retval;
+	}
 
 	retval = ext2fs_merge_fs(&(thread_ctx->fs));
 	if (retval) {
-- 
2.37.3




[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux