Whamcloud - gitweb
LU-13717 sec: support encrypted files handling in pfsck mode
authorSebastien Buisson <sbuisson@ddn.com>
Tue, 19 Oct 2021 11:02:12 +0000 (13:02 +0200)
committerLi Dongyang <dongyangli@ddn.com>
Fri, 28 Apr 2023 00:47:13 +0000 (10:47 +1000)
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@ddn.com>
Change-Id: Iaf495f399e38e3ca7914b92059607d4babc1ad44
Reviewed-on: https://review.whamcloud.com/45289
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Li Dongyang <dongyangli@ddn.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
e2fsck/e2fsck.h
e2fsck/encrypted_files.c
e2fsck/pass1.c

index 3749b68..9ec7683 100644 (file)
@@ -636,6 +636,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);
index 16be2d6..53e03a6 100644 (file)
@@ -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;
+}
index d6c2e12..8fd40bc 100644 (file)
@@ -2410,9 +2410,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
@@ -2837,6 +2834,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)
@@ -3097,6 +3111,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 = e2fsck_pass1_merge_fs(global_ctx->fs, thread_ctx->fs);
        if (retval) {