From d90c7666170a9a10b67d5649eb1d3f6cf0a00ff1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 27 Apr 2018 16:10:29 -0700 Subject: [PATCH] AOSP: e2fsck: allow read-only testing if -E unshare_blocks will succeed If -E unshare_blocks is used with -n, it will normally fail since the filesystem is read-only. For Android's "adb remount" it is more useful to report whether or not the unshare operation would succeed, were the filesystem writable. We do that here by ignoring certain write operations if -E unshare_blocks is specified with -n. It is not perfect, since the actual unshare operation could still fail (for example if new extents need to consume additional blocks). Signed-off-by: Theodore Ts'o Google-Bug-Id: 64109868 Test: e2fsck -f -n -E unshare_blocks on deduplicated image Change-Id: Ia50ceb7b3745fdf8766cff06c697818f07411635 From AOSP commit: 9e76dc0f65d8a8dec27f57b9020e81cbbbe12faf --- e2fsck/e2fsck.8.in | 5 +++++ e2fsck/pass1b.c | 25 ++++++++++++++++++++----- e2fsck/unix.c | 10 ++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in index 8b43c9c..da9f618 100644 --- a/e2fsck/e2fsck.8.in +++ b/e2fsck/e2fsck.8.in @@ -275,6 +275,11 @@ 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. +.IP +Note that unshare_blocks requires the "-f" option to ensure that all passes +are run. Additionally, if "-n" is also specified, e2fsck will simulate trying +to allocate enough space to deduplicate. If this fails, the exit code will +be non-zero. .RE .TP .B \-f diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c index 241669c..5693b9c 100644 --- a/e2fsck/pass1b.c +++ b/e2fsck/pass1b.c @@ -257,7 +257,7 @@ void e2fsck_pass1_dupblocks(e2fsck_t ctx, char *block_buf) ctx->fs->super->s_first_data_block, ext2fs_blocks_count(ctx->fs->super) - 1, &next); - if (result == ENOENT) { + if (result == ENOENT && !(ctx->options & E2F_OPT_NO)) { ext2fs_clear_feature_shared_blocks(ctx->fs->super); ext2fs_mark_super_dirty(ctx->fs); } @@ -796,6 +796,7 @@ static int clone_file_block(ext2_filsys fs, e2fsck_t ctx; blk64_t c; int is_meta = 0; + int should_write = 1; ctx = cs->ctx; deferred_dec_badcount(cs); @@ -803,6 +804,11 @@ static int clone_file_block(ext2_filsys fs, if (*block_nr == 0) return 0; + if (ext2fs_has_feature_shared_blocks(ctx->fs->super) && + (ctx->options & E2F_OPT_UNSHARE_BLOCKS) && + (ctx->options & E2F_OPT_NO)) + should_write = 0; + c = EXT2FS_B2C(fs, blockcnt); if (check_if_fs_cluster(ctx, EXT2FS_B2C(fs, *block_nr))) is_meta = 1; @@ -875,16 +881,25 @@ cluster_alloc_ok: cs->errcode = retval; return BLOCK_ABORT; } - retval = io_channel_write_blk64(fs->io, new_block, 1, cs->buf); - if (retval) { - cs->errcode = retval; - return BLOCK_ABORT; + if (should_write) { + retval = io_channel_write_blk64(fs->io, new_block, 1, cs->buf); + if (retval) { + cs->errcode = retval; + return BLOCK_ABORT; + } } cs->save_dup_cluster = (is_meta ? NULL : p); cs->save_blocknr = *block_nr; *block_nr = new_block; ext2fs_mark_block_bitmap2(ctx->block_found_map, new_block); ext2fs_mark_block_bitmap2(fs->block_map, new_block); + + if (!should_write) { + /* Don't try to change extent information; we want e2fsck to + * return success. + */ + return 0; + } return BLOCK_CHANGED; } return 0; diff --git a/e2fsck/unix.c b/e2fsck/unix.c index b369c1e..e604f42 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -1948,6 +1948,14 @@ no_journal: ext2fs_mark_super_dirty(fs); } + if (ext2fs_has_feature_shared_blocks(ctx->fs->super) && + (ctx->options & E2F_OPT_UNSHARE_BLOCKS) && + (ctx->options & E2F_OPT_NO)) + /* Don't try to write or flush I/O, we just wanted to know whether or + * not there were enough free blocks to undo deduplication. + */ + goto skip_write; + if (!(ctx->options & E2F_OPT_READONLY)) { e2fsck_write_bitmaps(ctx); if (fs->flags & EXT2_FLAG_DIRTY) { @@ -1984,6 +1992,8 @@ no_journal: exit_value |= FSCK_REBOOT; } } + +skip_write: if (!ext2fs_test_valid(fs) || ((exit_value & FSCK_CANCELED) && (sb->s_state & EXT2_ERROR_FS))) { -- 1.8.3.1