Whamcloud - gitweb
AOSP: e2fsck: Add an extended option for unsharing blocks.
authorDavid Anderson <dvander@google.com>
Mon, 5 Mar 2018 20:52:13 +0000 (12:52 -0800)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 21 Jun 2018 13:56:30 +0000 (09:56 -0400)
Add an -E unshare_blocks flag for unsharing blocks that were created for
a filesystem with block sharing enabled. If the filesystem does not have
this feature enabled, the flag has no effect. If the filesystem does not
have free space, e2fsck will error.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Google-Bug-Id: 64109868
Test: f_unshare_blocks_no_space, f_unshare_blocks_ok
Change-Id: I8821353e9e6200c6c0c71dd22f4f43d796fc720c
From AOSP commit: 8ba190e3135d61501d3a694b6960c2fbee98e7a6

15 files changed:
e2fsck/e2fsck.8.in
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/pass1b.c
e2fsck/unix.c
tests/f_unshare_blocks_no_space/expect.1 [new file with mode: 0644]
tests/f_unshare_blocks_no_space/expect.2 [new file with mode: 0644]
tests/f_unshare_blocks_no_space/image.gz [new file with mode: 0644]
tests/f_unshare_blocks_no_space/name [new file with mode: 0644]
tests/f_unshare_blocks_no_space/script [new file with mode: 0644]
tests/f_unshare_blocks_ok/expect.1 [new file with mode: 0644]
tests/f_unshare_blocks_ok/expect.2 [new file with mode: 0644]
tests/f_unshare_blocks_ok/image.gz [new file with mode: 0644]
tests/f_unshare_blocks_ok/name [new file with mode: 0644]
tests/f_unshare_blocks_ok/script [new file with mode: 0644]

index 1a3bd46..8b43c9c 100644 (file)
@@ -266,6 +266,15 @@ Convert block-mapped files to extent-mapped files.
 Only fix damaged metadata; do not optimize htree directories or compress
 extent trees.  This option is incompatible with the -D and -E bmap2extent
 options.
+.TP
+.BI unshare_blocks
+If the filesystem has shared blocks, with the shared blocks read-only feature
+enabled, then this will unshare all shared blocks and unset the read-only
+feature bit. If there is not enough free space then the operation will fail.
+If the filesystem does not have the read-only feature bit, but has shared
+blocks anyway, then this option will have no effect. Note when using this
+option, if there is no free space to clone blocks, there is no prompt to
+delete files and instead the operation will fail.
 .RE
 .TP
 .B \-f
index 5269650..d1ee367 100644 (file)
@@ -172,6 +172,7 @@ struct resource_track {
 #define E2F_OPT_FIXES_ONLY     0x8000 /* skip all optimizations */
 #define E2F_OPT_NOOPT_EXTENTS  0x10000 /* don't optimize extents */
 #define E2F_OPT_ICOUNT_FULLMAP 0x20000 /* use an array for inode counts */
+#define E2F_OPT_UNSHARE_BLOCKS  0x40000
 
 /*
  * E2fsck flags
index 35a0503..c5149e5 100644 (file)
@@ -2261,8 +2261,10 @@ static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block)
        clear_problem_context(&pctx);
 
        if (ext2fs_fast_test_block_bitmap2(ctx->block_found_map, block)) {
-               if (ext2fs_has_feature_shared_blocks(ctx->fs->super))
+               if (ext2fs_has_feature_shared_blocks(ctx->fs->super) &&
+                   !(ctx->options & E2F_OPT_UNSHARE_BLOCKS)) {
                        return;
+               }
                if (!ctx->block_dup_map) {
                        pctx.errcode = e2fsck_allocate_block_bitmap(ctx->fs,
                                        _("multiply claimed block map"),
index 392ff2c..241669c 100644 (file)
@@ -245,6 +245,24 @@ void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf)
        pass1d(ctx, block_buf);
        print_resource_track(ctx, "Pass 1d", &rtrack, ctx->fs->io);
 
+       if (ext2fs_has_feature_shared_blocks(ctx->fs->super) &&
+           (ctx->options & E2F_OPT_UNSHARE_BLOCKS)) {
+               /*
+                * If we successfully managed to unshare all blocks, unset the
+                * shared block feature.
+                */
+               blk64_t next;
+               int result = ext2fs_find_first_set_block_bitmap2(
+                       ctx->block_dup_map,
+                       ctx->fs->super->s_first_data_block,
+                       ext2fs_blocks_count(ctx->fs->super) - 1,
+                       &next);
+               if (result == ENOENT) {
+                       ext2fs_clear_feature_shared_blocks(ctx->fs->super);
+                       ext2fs_mark_super_dirty(ctx->fs);
+               }
+       }
+
        /*
         * Time to free all of the accumulated data structures that we
         * don't need anymore.
@@ -582,14 +600,21 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
                        fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
                        continue;
                }
-               if (fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
+               if ((ctx->options & E2F_OPT_UNSHARE_BLOCKS) ||
+                    fix_problem(ctx, PR_1D_CLONE_QUESTION, &pctx)) {
                        pctx.errcode = clone_file(ctx, ino, p, block_buf);
                        if (pctx.errcode)
                                fix_problem(ctx, PR_1D_CLONE_ERROR, &pctx);
                        else
                                continue;
                }
-               if (fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
+               /*
+                * Note: When unsharing blocks, we don't prompt to delete
+                * files. If the clone operation fails than the unshare
+                * operation should fail too.
+                */
+               if (!(ctx->options & E2F_OPT_UNSHARE_BLOCKS) &&
+                    fix_problem(ctx, PR_1D_DELETE_QUESTION, &pctx))
                        delete_file(ctx, ino, p, block_buf);
                else
                        ext2fs_unmark_valid(fs);
@@ -820,6 +845,13 @@ static int clone_file_block(ext2_filsys fs,
                        cs->errcode = retval;
                        return BLOCK_ABORT;
                }
+               if (ext2fs_has_feature_shared_blocks(fs->super)) {
+                       /*
+                        * Update the block stats so we don't get a prompt to fix block
+                        * counts in the final pass.
+                        */
+                       ext2fs_block_alloc_stats2(fs, new_block, +1);
+               }
 cluster_alloc_ok:
                cs->alloc_block = new_block;
 
index 55e21ea..b369c1e 100644 (file)
@@ -740,6 +740,9 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                } else if (strcmp(token, "fixes_only") == 0) {
                        ctx->options |= E2F_OPT_FIXES_ONLY;
                        continue;
+               } else if (strcmp(token, "unshare_blocks") == 0) {
+                       ctx->options |= E2F_OPT_UNSHARE_BLOCKS;
+                       continue;
                } else {
                        fprintf(stderr, _("Unknown extended option: %s\n"),
                                token);
@@ -764,6 +767,7 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                fputs("\tno_inode_count_fullmap\n", stderr);
                fputs(_("\treadahead_kb=<buffer size>\n"), stderr);
                fputs("\tbmap2extent\n", stderr);
+               fputs("\tunshare_blocks\n", stderr);
                fputs("\tfixes_only\n", stderr);
                fputc('\n', stderr);
                exit(1);
diff --git a/tests/f_unshare_blocks_no_space/expect.1 b/tests/f_unshare_blocks_no_space/expect.1
new file mode 100644 (file)
index 0000000..b2f6ab1
--- /dev/null
@@ -0,0 +1,136 @@
+Pass 1: Checking inodes, blocks, and sizes
+
+Running additional passes to resolve blocks claimed by more than one inode...
+Pass 1B: Rescanning for multiply-claimed blocks
+Multiply-claimed block(s) in inode 24: 10
+Multiply-claimed block(s) in inode 25: 9 9 9--10
+Multiply-claimed block(s) in inode 26: 9 9 9--10
+Multiply-claimed block(s) in inode 27: 9 9 9--10
+Multiply-claimed block(s) in inode 28: 9 9 9--10
+Multiply-claimed block(s) in inode 29: 9 9 9--10
+Multiply-claimed block(s) in inode 30: 9 9 9--10
+Multiply-claimed block(s) in inode 31: 9 9 9--10
+Multiply-claimed block(s) in inode 32: 9 9 9--10
+Pass 1C: Scanning directories for inodes with multiply-claimed blocks
+Pass 1D: Reconciling multiply-claimed blocks
+(There are 9 inodes containing multiply-claimed blocks.)
+
+File /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018) 
+  has 1 multiply-claimed block(s), shared with 8 file(s):
+       /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018)
+       /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018)
+       /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018)
+       /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018)
+       /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018)
+       /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018)
+       /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018)
+       /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+File /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018) 
+  has 4 multiply-claimed block(s), shared with 8 file(s):
+       /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018)
+       /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018)
+       /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018)
+       /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018)
+       /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018)
+       /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018)
+       /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018)
+       /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+File /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018) 
+  has 4 multiply-claimed block(s), shared with 8 file(s):
+       /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018)
+       /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018)
+       /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018)
+       /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018)
+       /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018)
+       /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018)
+       /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018)
+       /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+File /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018) 
+  has 4 multiply-claimed block(s), shared with 8 file(s):
+       /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018)
+       /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018)
+       /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018)
+       /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018)
+       /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018)
+       /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018)
+       /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018)
+       /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+File /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018) 
+  has 4 multiply-claimed block(s), shared with 8 file(s):
+       /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018)
+       /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018)
+       /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018)
+       /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018)
+       /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018)
+       /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018)
+       /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018)
+       /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+File /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018) 
+  has 4 multiply-claimed block(s), shared with 8 file(s):
+       /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018)
+       /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018)
+       /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018)
+       /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018)
+       /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018)
+       /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018)
+       /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018)
+       /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+File /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018) 
+  has 4 multiply-claimed block(s), shared with 8 file(s):
+       /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018)
+       /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018)
+       /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018)
+       /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018)
+       /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018)
+       /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018)
+       /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018)
+       /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+File /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018) 
+  has 4 multiply-claimed block(s), shared with 8 file(s):
+       /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018)
+       /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018)
+       /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018)
+       /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018)
+       /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018)
+       /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018)
+       /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018)
+       /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+File /file18.txt (inode #32, mod time Mon Mar  5 20:30:04 2018) 
+  has 4 multiply-claimed block(s), shared with 8 file(s):
+       /file6.txt (inode #31, mod time Mon Mar  5 20:30:04 2018)
+       /file12.txt (inode #30, mod time Mon Mar  5 20:30:04 2018)
+       /file3.txt (inode #29, mod time Mon Mar  5 20:30:04 2018)
+       /file9.txt (inode #28, mod time Mon Mar  5 20:30:04 2018)
+       /file8.txt (inode #27, mod time Mon Mar  5 20:30:04 2018)
+       /file15.txt (inode #26, mod time Mon Mar  5 20:30:04 2018)
+       /file20.txt (inode #25, mod time Mon Mar  5 20:30:04 2018)
+       /file4.txt (inode #24, mod time Mon Mar  5 20:30:04 2018)
+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block
+Couldn't clone file: Could not allocate block in ext2 filesystem
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+
+test_filesys: ********** WARNING: Filesystem still has errors **********
+
+test_filesys: 32/32 files (34.4% non-contiguous), 64/64 blocks
+Exit status is 4
diff --git a/tests/f_unshare_blocks_no_space/expect.2 b/tests/f_unshare_blocks_no_space/expect.2
new file mode 100644 (file)
index 0000000..8137dc7
--- /dev/null
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 32/32 files (34.4% non-contiguous), 64/64 blocks
+Exit status is 1
diff --git a/tests/f_unshare_blocks_no_space/image.gz b/tests/f_unshare_blocks_no_space/image.gz
new file mode 100644 (file)
index 0000000..8fff6d4
Binary files /dev/null and b/tests/f_unshare_blocks_no_space/image.gz differ
diff --git a/tests/f_unshare_blocks_no_space/name b/tests/f_unshare_blocks_no_space/name
new file mode 100644 (file)
index 0000000..ca323a6
--- /dev/null
@@ -0,0 +1 @@
+unshare blocks should fail with no free space
diff --git a/tests/f_unshare_blocks_no_space/script b/tests/f_unshare_blocks_no_space/script
new file mode 100644 (file)
index 0000000..bc44354
--- /dev/null
@@ -0,0 +1,2 @@
+FSCK_OPT="-yf -E unshare_blocks"
+. $cmd_dir/run_e2fsck
diff --git a/tests/f_unshare_blocks_ok/expect.1 b/tests/f_unshare_blocks_ok/expect.1
new file mode 100644 (file)
index 0000000..e0ea764
--- /dev/null
@@ -0,0 +1,26 @@
+Pass 1: Checking inodes, blocks, and sizes
+
+Running additional passes to resolve blocks claimed by more than one inode...
+Pass 1B: Rescanning for multiply-claimed blocks
+Multiply-claimed block(s) in inode 12: 9
+Multiply-claimed block(s) in inode 13: 9
+Pass 1C: Scanning directories for inodes with multiply-claimed blocks
+Pass 1D: Reconciling multiply-claimed blocks
+(There are 2 inodes containing multiply-claimed blocks.)
+
+File /file2.txt (inode #12, mod time Sat Mar  3 02:12:33 2018) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+       /file1.txt (inode #13, mod time Sat Mar  3 02:12:15 2018)
+File /file1.txt (inode #13, mod time Sat Mar  3 02:12:15 2018) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+       /file2.txt (inode #12, mod time Sat Mar  3 02:12:33 2018)
+Multiply-claimed blocks already reassigned or cloned.
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 13/32 files (0.0% non-contiguous), 13/64 blocks
+Exit status is 0
diff --git a/tests/f_unshare_blocks_ok/expect.2 b/tests/f_unshare_blocks_ok/expect.2
new file mode 100644 (file)
index 0000000..b215382
--- /dev/null
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 13/32 files (0.0% non-contiguous), 13/64 blocks
+Exit status is 0
diff --git a/tests/f_unshare_blocks_ok/image.gz b/tests/f_unshare_blocks_ok/image.gz
new file mode 100644 (file)
index 0000000..db747e2
Binary files /dev/null and b/tests/f_unshare_blocks_ok/image.gz differ
diff --git a/tests/f_unshare_blocks_ok/name b/tests/f_unshare_blocks_ok/name
new file mode 100644 (file)
index 0000000..e051a62
--- /dev/null
@@ -0,0 +1 @@
+unshare blocks successfully
diff --git a/tests/f_unshare_blocks_ok/script b/tests/f_unshare_blocks_ok/script
new file mode 100644 (file)
index 0000000..bc44354
--- /dev/null
@@ -0,0 +1,2 @@
+FSCK_OPT="-yf -E unshare_blocks"
+. $cmd_dir/run_e2fsck