This patch adds a helper function ext2fs_xattrs_release_all() which removes all extended attributes and updates the quota accordingly. The main purpose of this is to handle ea_inode xattrs in e2fsck when deleting orphan inodes: # e2fsck -yf /tmp/ext4 e2fsck 1.47.3-wc2 (11-Nov-2025) Clearing orphaned inode 12 (uid=0, gid=0, mode=0100644, size=0) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Regular filesystem inode 13 has EA_INODE flag set. Clear? yes Unattached inode 13 Connect to /lost+found? yes Inode 13 ref count is 2, should be 1. Fix? yes fuse2fs, debugfs and mke2fs are updated to use this function and handle ea_inode on inode deletion. Update d_xattr_ea_inode to check for the inode deletion case. Add a regression test: f_orphan_ea_inode Signed-off-by: Etienne AUJAMES Change-Id: I4a84a50d43b8b9aab2dfc352a92256c710a3659e Lustre-bug-id: https://jira.whamcloud.com/browse/LU-20049 --- debugfs/debugfs.c | 33 +++++++-- e2fsck/super.c | 67 +++++++++++------- lib/ext2fs/ext2fs.h | 3 + lib/ext2fs/ext_attr.c | 41 +++++++++++ misc/create_inode_libarchive.c | 35 ++++----- misc/fuse2fs.c | 117 +++++++++++-------------------- tests/d_xattr_ea_inode/expect | 51 ++++++++++++++ tests/d_xattr_ea_inode/script | 55 ++++++++++----- tests/f_orphan_ea_inode/expect.1 | 6 ++ tests/f_orphan_ea_inode/expect.2 | 7 ++ tests/f_orphan_ea_inode/image.gz | Bin 0 -> 2139 bytes tests/f_orphan_ea_inode/name | 1 + tests/f_orphan_ea_inode/script | 3 + 13 files changed, 277 insertions(+), 142 deletions(-) create mode 100644 tests/f_orphan_ea_inode/expect.1 create mode 100644 tests/f_orphan_ea_inode/expect.2 create mode 100644 tests/f_orphan_ea_inode/image.gz create mode 100644 tests/f_orphan_ea_inode/name create mode 100644 tests/f_orphan_ea_inode/script diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index b9f248be2..d316293d2 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -1861,21 +1861,40 @@ static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr, static void kill_file_by_inode(ext2_ino_t inode) { - struct ext2_inode inode_buf; + struct ext2_inode_large *inode_buf; + size_t inode_size = EXT2_INODE_SIZE(current_fs->super); + errcode_t err; - if (debugfs_read_inode(inode, &inode_buf, 0)) - return; - ext2fs_set_dtime(current_fs, &inode_buf); - if (debugfs_write_inode(inode, &inode_buf, 0)) + err = ext2fs_get_memzero(inode_size, &inode_buf); + if (err) return; - if (ext2fs_inode_has_valid_blocks2(current_fs, &inode_buf)) { + + err = ext2fs_read_inode_full(current_fs, inode, EXT2_INODE(inode_buf), + inode_size); + if (err) { + com_err(__func__, err, "while reading inode %u", inode); + goto out; + } + + ext2fs_set_dtime(current_fs, EXT2_INODE(inode_buf)); + ext2fs_xattrs_release_all(current_fs, inode, inode_buf, inode_size, + NULL); + if (ext2fs_inode_has_valid_blocks2(current_fs, EXT2_INODE(inode_buf))) { blk64_t last_cluster = 0; ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL, release_blocks_proc, &last_cluster); } printf("\n"); ext2fs_inode_alloc_stats2(current_fs, inode, -1, - LINUX_S_ISDIR(inode_buf.i_mode)); + LINUX_S_ISDIR(inode_buf->i_mode)); + + err = ext2fs_write_inode_full(current_fs, inode, EXT2_INODE(inode_buf), + inode_size); + if (err) + com_err(__func__, err, "while writing inode %u", inode); + +out: + ext2fs_free_mem(&inode_buf); } diff --git a/e2fsck/super.c b/e2fsck/super.c index c2ccefd54..1a94ba567 100644 --- a/e2fsck/super.c +++ b/e2fsck/super.c @@ -156,13 +156,14 @@ static errcode_t truncate_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, struct process_block_struct pb = { 0 }; e2_blkcnt_t truncate_block = 0; __u32 truncate_offset = 0; - blk64_t blk; + blk64_t blk, iblks; int ret_flags; errcode_t retval = 0; if (!ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(inode))) return 0; + iblks = ext2fs_get_stat_i_blocks(fs, EXT2_INODE(inode)); if (inode->i_links_count) { truncate_offset = inode->i_size % fs->blocksize; truncate_block = (e2_blkcnt_t) @@ -190,6 +191,10 @@ static errcode_t truncate_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, "release_inode_blocks"); ext2fs_iblk_sub_blocks(fs, EXT2_INODE(inode), pb.truncated_blocks); + iblks -= ext2fs_get_stat_i_blocks(fs, EXT2_INODE(inode)); + if (ctx->qctx) + quota_data_sub(ctx->qctx, inode, ino, iblks * 512); + if (!truncate_offset) return 0; @@ -217,17 +222,19 @@ static errcode_t truncate_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, * not deleted. */ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, - struct ext2_inode_large *inode, char *block_buf, + struct ext2_inode_large *inode, + size_t inode_size, char *block_buf, struct problem_context *pctx) { ext2_filsys fs = ctx->fs; - blk64_t free_blks, ino_blks; + blk64_t free_blks; + __u32 free_inodes; char *buf; errcode_t err; int rc = 0; + free_inodes = fs->super->s_free_inodes_count; free_blks = ext2fs_free_blocks_count(fs->super); - ino_blks = ext2fs_get_stat_i_blocks(fs, EXT2_INODE(inode)); buf = block_buf + 3 * ctx->fs->blocksize; if (truncate_inode_blocks(ctx, ino, inode, buf, pctx)) { rc = 1; @@ -236,7 +243,7 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, if (inode->i_links_count) goto update_counts; - err = ext2fs_free_ext_attr(fs, ino, inode); + err = ext2fs_xattrs_release_all(fs, ino, inode, inode_size, ctx->qctx); if (err) { com_err(__func__, err, _("while calling ext2fs_free_ext_attr for inode %u"), @@ -249,9 +256,8 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, update_counts: ctx->free_blocks += ext2fs_free_blocks_count(fs->super) - free_blks; - ino_blks -= ext2fs_get_stat_i_blocks(fs, EXT2_INODE(inode)); - if (ctx->qctx) - quota_data_sub(ctx->qctx, inode, 0, ino_blks << 9); + free_inodes = fs->super->s_free_inodes_count - free_inodes; + ctx->free_inodes += free_inodes; return rc; } @@ -312,44 +318,55 @@ static int release_orphan_inode(e2fsck_t ctx, ext2_ino_t *ino, char *block_buf) { ext2_filsys fs = ctx->fs; struct problem_context pctx; - struct ext2_inode_large inode; + struct ext2_inode_large *inode; + size_t inode_size = EXT2_INODE_SIZE(fs->super); ext2_ino_t next_ino; + int rc = 1; + + if (ext2fs_get_memzero(inode_size, &inode)) + return 1; - e2fsck_read_inode_full(ctx, *ino, EXT2_INODE(&inode), - sizeof(inode), "release_orphan_inode"); + e2fsck_read_inode_full(ctx, *ino, EXT2_INODE(inode), + inode_size, __func__); clear_problem_context(&pctx); pctx.ino = *ino; - pctx.inode = EXT2_INODE(&inode); - pctx.str = inode.i_links_count ? _("Truncating") : _("Clearing"); + pctx.inode = EXT2_INODE(inode); + pctx.str = inode->i_links_count ? _("Truncating") : _("Clearing"); fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx); - next_ino = inode.i_dtime; + next_ino = inode->i_dtime; if (next_ino && ((next_ino < EXT2_FIRST_INODE(fs->super)) || (next_ino > fs->super->s_inodes_count))) { pctx.ino = next_ino; fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx); - return 1; + goto out; } - if (release_inode_blocks(ctx, *ino, &inode, block_buf, &pctx)) - return 1; + if (release_inode_blocks(ctx, *ino, inode, inode_size, block_buf, + &pctx)) + goto out; - if (!inode.i_links_count) { + if (!inode->i_links_count) { if (ctx->qctx) - quota_data_inodes(ctx->qctx, &inode, *ino, -1); + quota_data_inodes(ctx->qctx, inode, *ino, -1); ext2fs_inode_alloc_stats2(fs, *ino, -1, - LINUX_S_ISDIR(inode.i_mode)); + LINUX_S_ISDIR(inode->i_mode)); ctx->free_inodes++; - ext2fs_set_dtime(fs, EXT2_INODE(&inode)); + ext2fs_set_dtime(fs, EXT2_INODE(inode)); } else { - inode.i_dtime = 0; + inode->i_dtime = 0; } - e2fsck_write_inode_full(ctx, *ino, EXT2_INODE(&inode), - sizeof(inode), "delete_file"); + e2fsck_write_inode_full(ctx, *ino, EXT2_INODE(inode), + inode_size, __func__); *ino = next_ino; - return 0; + rc = 0; + +out: + ext2fs_free_mem(&inode); + + return rc; } struct process_orphan_block_data { diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 56de5ea50..cb3f1a3a1 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -1425,6 +1425,9 @@ errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino, #define XATTR_HANDLE_FLAG_RAW 0x0001 errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle, unsigned int *new_flags, unsigned int *old_flags); +errcode_t ext2fs_xattrs_release_all(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode, + size_t inode_size, quota_ctx_t qctx); extern void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header, struct ext2_ext_attr_entry *end); extern __u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode); diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c index 3b90b70bb..2a2e79acd 100644 --- a/lib/ext2fs/ext_attr.c +++ b/lib/ext2fs/ext_attr.c @@ -1868,3 +1868,44 @@ errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle, handle->flags = *new_flags; return 0; } + +errcode_t ext2fs_xattrs_release_all(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode, + size_t inode_size, quota_ctx_t qctx) +{ + struct ext2_xattr_handle *h; + errcode_t err = 0; + + if (!ext2fs_has_feature_ea_inode(fs->super)) { + blk64_t blk = ext2fs_file_acl_block(fs, EXT2_INODE(inode)); + + if (!blk) + return 0; + + err = ext2fs_free_ext_attr(fs, ino, inode); + if (err || !qctx) + return err; + + quota_data_sub(qctx, inode, ino, + EXT2FS_C2B(fs, 1) * fs->blocksize); + return 0; + } + + err = ext2fs_xattrs_open_inode(fs, ino, EXT2_INODE(inode), inode_size, + qctx, &h); + if (err) + return err; + + err = ext2fs_xattrs_read(h); + if (err) + goto out_close; + + err = ext2fs_xattr_remove_all(h); + if (err) + goto out_close; + +out_close: + ext2fs_xattrs_close(&h); + + return err; +} diff --git a/misc/create_inode_libarchive.c b/misc/create_inode_libarchive.c index fadf0721f..4736e8c22 100644 --- a/misc/create_inode_libarchive.c +++ b/misc/create_inode_libarchive.c @@ -261,46 +261,49 @@ static inline unsigned int __round_up(unsigned int quantity, unsigned int size) static int remove_inode(ext2_filsys fs, ext2_ino_t ino) { errcode_t ret = 0; - struct ext2_inode_large inode; + struct ext2_inode_large *inode; + size_t inode_size = EXT2_INODE_SIZE(fs->super); - memset(&inode, 0, sizeof(inode)); - ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, - sizeof(inode)); + ret = ext2fs_get_memzero(inode_size, &inode); + if (ret) + return ret; + + ret = ext2fs_read_inode_full(fs, ino, EXT2_INODE(inode), inode_size); if (ret) goto out; - switch (inode.i_links_count) { + switch (inode->i_links_count) { case 0: return 0; /* XXX: already done? */ case 1: - inode.i_links_count--; - ext2fs_set_dtime(fs, EXT2_INODE(&inode)); + inode->i_links_count--; + ext2fs_set_dtime(fs, EXT2_INODE(inode)); break; default: - inode.i_links_count--; + inode->i_links_count--; } - if (inode.i_links_count) + if (inode->i_links_count) goto write_out; /* Nobody holds this file; free its blocks! */ - ret = ext2fs_free_ext_attr(fs, ino, &inode); + ret = ext2fs_xattrs_release_all(fs, ino, inode, inode_size, NULL); if (ret) goto write_out; - if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) { - ret = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL, - 0, ~0ULL); + if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(inode))) { + ret = ext2fs_punch(fs, ino, EXT2_INODE(inode), NULL, 0, ~0ULL); if (ret) goto write_out; } - ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); + ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode->i_mode)); write_out: - ret = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, - sizeof(inode)); + ret = ext2fs_write_inode_full(fs, ino, EXT2_INODE(inode), inode_size); out: + ext2fs_free_mem(&inode); + return ret; } diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c index 94e289fab..11141f645 100644 --- a/misc/fuse2fs.c +++ b/misc/fuse2fs.c @@ -2274,123 +2274,88 @@ static int fuse2fs_unlink(struct fuse2fs *ff, const char *path, return 0; } -static int remove_ea_inodes(struct fuse2fs *ff, ext2_ino_t ino, - struct ext2_inode_large *inode) +static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino) { ext2_filsys fs = ff->fs; - struct ext2_xattr_handle *h; errcode_t err; + struct ext2_inode_large *inode; + size_t inode_size = EXT2_INODE_SIZE(fs->super); int ret = 0; - /* - * The xattr handle maintains its own private copy of the inode, so - * write ours to disk so that we can read it. - */ - err = fuse2fs_write_inode(fs, ino, inode); + err = ext2fs_get_memzero(inode_size, &inode); if (err) return translate_error(fs, ino, err); - err = ext2fs_xattrs_open(fs, ino, &h); - if (err) - return translate_error(fs, ino, err); - - err = ext2fs_xattrs_read(h); + err = ext2fs_read_inode_full(fs, ino, EXT2_INODE(inode), inode_size); if (err) { ret = translate_error(fs, ino, err); - goto out_close; - } - - err = ext2fs_xattr_remove_all(h); - if (err) { - ret = translate_error(fs, ino, err); - goto out_close; + goto out; } - -out_close: - ext2fs_xattrs_close(&h); - if (ret) - return ret; - - /* Now read the inode back in. */ - err = fuse2fs_read_inode(fs, ino, inode); - if (err) - return translate_error(fs, ino, err); - - return 0; -} - -static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino) -{ - ext2_filsys fs = ff->fs; - errcode_t err; - struct ext2_inode_large inode; - int ret = 0; - - err = fuse2fs_read_inode(fs, ino, &inode); - if (err) - return translate_error(fs, ino, err); - dbg_printf(ff, "%s: put ino=%d links=%d\n", __func__, ino, - inode.i_links_count); + inode->i_links_count); - if (S_ISDIR(inode.i_mode)) { + if (S_ISDIR(inode->i_mode)) { /* * Caller should have checked that this is an empty directory * before starting the unlink process. nlink is usually 2, but * it could be 1 if this dir ever had more than 65000 subdirs. * Zero the link count. */ - if (!ext2fs_dir_link_empty(EXT2_INODE(&inode))) - return translate_error(fs, ino, EXT2_ET_INODE_CORRUPTED); - inode.i_links_count = 0; - ext2fs_set_dtime(fs, EXT2_INODE(&inode)); + if (!ext2fs_dir_link_empty(EXT2_INODE(inode))) { + ret = translate_error(fs, ino, EXT2_ET_INODE_CORRUPTED); + goto out; + } + inode->i_links_count = 0; + ext2fs_set_dtime(fs, EXT2_INODE(inode)); } else { /* * Any other file type can be hardlinked, so all we need to do * is decrement the nlink. */ - if (inode.i_links_count == 0) - return translate_error(fs, ino, EXT2_ET_INODE_CORRUPTED); - inode.i_links_count--; - if (!inode.i_links_count) - ext2fs_set_dtime(fs, EXT2_INODE(&inode)); + if (inode->i_links_count == 0) { + ret = translate_error(fs, ino, EXT2_ET_INODE_CORRUPTED); + goto out; + } + inode->i_links_count--; + if (!inode->i_links_count) + ext2fs_set_dtime(fs, EXT2_INODE(inode)); } - ret = update_ctime(fs, ino, &inode); + ret = update_ctime(fs, ino, inode); if (ret) - return ret; + goto out; /* Still linked? Leave it be. */ - if (inode.i_links_count) + if (inode->i_links_count) goto write_out; - if (ext2fs_has_feature_ea_inode(fs->super)) { - ret = remove_ea_inodes(ff, ino, &inode); - if (ret) - return ret; - } - /* Nobody holds this file; free its blocks! */ - err = ext2fs_free_ext_attr(fs, ino, &inode); - if (err) - return translate_error(fs, ino, err); + err = ext2fs_xattrs_release_all(fs, ino, inode, inode_size, NULL); + if (err) { + ret = translate_error(fs, ino, err); + goto out; + } - if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&inode))) { - err = ext2fs_punch(fs, ino, EXT2_INODE(&inode), NULL, + if (ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(inode))) { + err = ext2fs_punch(fs, ino, EXT2_INODE(inode), NULL, 0, ~0ULL); - if (err) - return translate_error(fs, ino, err); + if (err) { + ret = translate_error(fs, ino, err); + goto out; + } } ext2fs_inode_alloc_stats2(fs, ino, -1, - LINUX_S_ISDIR(inode.i_mode)); + LINUX_S_ISDIR(inode->i_mode)); write_out: - err = fuse2fs_write_inode(fs, ino, &inode); + err = ext2fs_write_inode_full(fs, ino, EXT2_INODE(inode), inode_size); if (err) - return translate_error(fs, ino, err); + ret = translate_error(fs, ino, err); +out: + ext2fs_free_mem(&inode); - return 0; + return ret; } static int __op_unlink(struct fuse2fs *ff, const char *path) diff --git a/tests/d_xattr_ea_inode/expect b/tests/d_xattr_ea_inode/expect index aaad9c5b3..e1878c3dc 100644 --- a/tests/d_xattr_ea_inode/expect +++ b/tests/d_xattr_ea_inode/expect @@ -135,3 +135,54 @@ Pass 5: Checking group summary information test_filesys: 11/128 files (0.0% non-contiguous), 18/256 blocks Exit status is 0 +write d_xattr_ea_inode.tmp test_file +Allocated inode: 12 +Exit status is 0 + +Generate xattr value (1024 bytes) +ea_set -f d_xattr_ea_inode.tmp test_file user.test1 +Exit status is 0 +ea_get -f d_xattr_ea_inode.ver.tmp test_file user.test1 +Exit status is 0 +Compare xattr values (1024 bytes) +stat test_file +Blockcount: 16 +Exit status is 0 +e2fsck -yf -N test_filesys +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: 12/128 files (0.0% non-contiguous), 20/256 blocks +Exit status is 0 + +Generate xattr value (16384 bytes) +ea_set -f d_xattr_ea_inode.tmp test_file user.test2 +Exit status is 0 +ea_get -f d_xattr_ea_inode.ver.tmp test_file user.test2 +Exit status is 0 +Compare xattr values (16384 bytes) +stat test_file +Blockcount: 48 +Exit status is 0 +e2fsck -yf -N test_filesys +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/128 files (0.0% non-contiguous), 24/256 blocks +Exit status is 0 + +rm test_file + +Exit status is 0 +e2fsck -yf -N test_filesys +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: 11/128 files (0.0% non-contiguous), 18/256 blocks +Exit status is 0 diff --git a/tests/d_xattr_ea_inode/script b/tests/d_xattr_ea_inode/script index 84104549c..c24eb6cd5 100644 --- a/tests/d_xattr_ea_inode/script +++ b/tests/d_xattr_ea_inode/script @@ -15,32 +15,33 @@ VERIFY_DATA=$test_name.ver.tmp echo "debugfs edit extended attributes with ea_inode feature" > $OUT.new d_xattr_ea_inode_check() { - local xattr_size=$1 - local xattr_name=$2 - local ea_rm=$3 + local path=$1 + local xattr_size=$2 + local xattr_name=$3 + local ea_rm=$4 echo "Generate xattr value ($xattr_size bytes)" >> $OUT.new echo $xattr_size | awk '{srand();for(i=0;i<$1;i++) printf("%c",97+int(rand()*26));}' > $TEST_DATA - echo "ea_set -f $TEST_DATA / $xattr_name" >> $OUT.new - $DEBUGFS -w -R "ea_set -f $TEST_DATA / $xattr_name" $TMPFILE >> $OUT.new 2>&1 + echo "ea_set -f $TEST_DATA $path $xattr_name" >> $OUT.new + $DEBUGFS -w -R "ea_set -f $TEST_DATA $path $xattr_name" $TMPFILE >> $OUT.new 2>&1 echo Exit status is $? >> $OUT.new - echo "ea_get -f $VERIFY_DATA / $xattr_name" >> $OUT.new - $DEBUGFS -w -R "ea_get -f $VERIFY_DATA / $xattr_name" $TMPFILE >> $OUT.new 2>&1 + echo "ea_get -f $VERIFY_DATA $path $xattr_name" >> $OUT.new + $DEBUGFS -w -R "ea_get -f $VERIFY_DATA $path $xattr_name" $TMPFILE >> $OUT.new 2>&1 echo Exit status is $? >> $OUT.new echo "Compare xattr values ($xattr_size bytes)" >> $OUT.new diff -u $TEST_DATA $VERIFY_DATA >> $OUT.new - echo "stat /" >> $OUT.new - ($DEBUGFS -c -R "stat /" $TMPFILE | grep -Eo "Blockcount: [0-9]+") >> $OUT.new 2>&1 + echo "stat $path" >> $OUT.new + ($DEBUGFS -c -R "stat $path" $TMPFILE | grep -Eo "Blockcount: [0-9]+") >> $OUT.new 2>&1 echo Exit status is $? >> $OUT.new if $ea_rm; then - echo "ea_rm / $xattr_name" >> $OUT.new - $DEBUGFS -w -R "ea_rm / $xattr_name" $TMPFILE >> $OUT.new 2>&1 + echo "ea_rm $path $xattr_name" >> $OUT.new + $DEBUGFS -w -R "ea_rm $path $xattr_name" $TMPFILE >> $OUT.new 2>&1 echo Exit status is $? >> $OUT.new fi @@ -56,15 +57,33 @@ echo "mke2fs -Fq -b 4096 -O ea_inode test.img 1m" >> $OUT.new $MKE2FS -Fq -b 4096 -O ea_inode $TMPFILE 1m > /dev/null 2>&1 echo Exit status is $? >> $OUT.new -d_xattr_ea_inode_check 8292 user.test1 true +d_xattr_ea_inode_check / 8292 user.test1 true -d_xattr_ea_inode_check 4097 user.test1 false -d_xattr_ea_inode_check 102 user.test2 false -d_xattr_ea_inode_check 5005 user.test2 true -d_xattr_ea_inode_check 512 user.test1 true +d_xattr_ea_inode_check / 4097 user.test1 false +d_xattr_ea_inode_check / 102 user.test2 false +d_xattr_ea_inode_check / 5005 user.test2 true +d_xattr_ea_inode_check / 512 user.test1 true -d_xattr_ea_inode_check 1024 user.test1 false -d_xattr_ea_inode_check 5000 user.test1 true +d_xattr_ea_inode_check / 1024 user.test1 false +d_xattr_ea_inode_check / 5000 user.test1 true + +# Create and remove a file with ea_inode +echo "test_file_content" > $TEST_DATA +echo "write $TEST_DATA test_file" >> $OUT.new +$DEBUGFS -w -R "write $TEST_DATA test_file" $TMPFILE >> $OUT.new 2>&1 +echo Exit status is $? >> $OUT.new +echo >> $OUT.new + +d_xattr_ea_inode_check test_file 1024 user.test1 false +d_xattr_ea_inode_check test_file 16384 user.test2 false + +echo "rm test_file" >> $OUT.new +$DEBUGFS -w -R "rm test_file" $TMPFILE >> $OUT.new 2>&1 +echo Exit status is $? >> $OUT.new + +echo e2fsck $VERIFY_FSCK_OPT -N test_filesys >> $OUT.new +$FSCK $VERIFY_FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1 +echo Exit status is $? >> $OUT.new sed -f $cmd_dir/filter.sed $OUT.new > $OUT diff --git a/tests/f_orphan_ea_inode/expect.1 b/tests/f_orphan_ea_inode/expect.1 new file mode 100644 index 000000000..3eba3d718 --- /dev/null +++ b/tests/f_orphan_ea_inode/expect.1 @@ -0,0 +1,6 @@ +test_filesys: Clearing orphaned inode 12 (uid=0, gid=0, mode=0100644, size=0) +test_filesys: Clearing orphaned inode 13 (uid=1000, gid=1000, mode=0100644, size=6) +test_filesys: Clearing orphaned inode 14 (uid=1001, gid=1001, mode=0100644, size=0) +test_filesys: Clearing orphaned inode 15 (uid=1002, gid=1002, mode=0100644, size=6) +test_filesys: clean, 13/128 files, 23/256 blocks +Exit status is 0 diff --git a/tests/f_orphan_ea_inode/expect.2 b/tests/f_orphan_ea_inode/expect.2 new file mode 100644 index 000000000..bf76a5c25 --- /dev/null +++ b/tests/f_orphan_ea_inode/expect.2 @@ -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/128 files (0.0% non-contiguous), 23/256 blocks +Exit status is 0 diff --git a/tests/f_orphan_ea_inode/image.gz b/tests/f_orphan_ea_inode/image.gz new file mode 100644 index 0000000000000000000000000000000000000000..95f0e53aebd45e041b4b1f53be7c374c8144c1b7 GIT binary patch literal 2139 zcmeH`ZB){C6vzM8Hrp}7g@%~MtYvweYvyWYCGO-yK4OW}V*_*xGyS^{(x%d9g@7#Mo=U!CN zx^;`kZBo{(O(w?UlOWkxD8Vt(5&DxMNiEw;EPH7y+Ew~8s5^)kG8_|gs>t&FoaZqP zhX^f4FF$nsWQ%V%)-Su+(l6Bj)v?|nzO6mdz3EPOer?uZ1ll)s&Ai{i%Nu890TO2K zshf0{b{)fKnfhQuM3 ztE3o$LWqHZD0#-n3TAl%tf_w_xidVV}P2DUekE)eD zT(0*hq{s=2DLZ|=cfjpP$NK%@=c#ATI5bt|@jRbe)6n{i=2q(KOUp^UXH_U#Uun@v zibGUrxGp$!cgIAYUPiAMJD3-(ra9L!`-503X& zkE^6#8;v0xBSQ8}OeIL;lcoEH!L8Ob?!DL*>IBEr%AXAqYhC(lf@~D* z0Vc{mZQ6tXP$#y`cS52**Q|e%QQ8=WpBK$J4K_}_l~<2P(lgK;5~jzBUMu8J=*SB{ zu6o87DJL#ukb`Hs$o89qW=2h^DO_^T0O|gm1q7WOdI3WMASpos)5bw|%t04(St-?I zI<+XXZ&F+7Op7CM4HI=7$IonKxlbh#x3CCTLZL{v1h~&|gDaytp6nCp!M9BLOtX(e z)ppMY*hgR0Ug#Q`KxpXdycinpUuJ! zB?fibNabru0;9?UEe*0yT@Se{ymzx_(1Yw1fztv6+{ z&4>Pe{l|1(NBH&nZ1g*N%U^UYwDJ`y93DU>!vnq1xwwn%W;V>4G3=h2i~ss#c00=v i9Rno8r?2x(P~Yhtfp-M{Zvr7`V4?Up>pcjvf&Kz@_kh^| literal 0 HcmV?d00001 diff --git a/tests/f_orphan_ea_inode/name b/tests/f_orphan_ea_inode/name new file mode 100644 index 000000000..b892ff960 --- /dev/null +++ b/tests/f_orphan_ea_inode/name @@ -0,0 +1 @@ +clearing orphan inodes with ea_inode and quota features diff --git a/tests/f_orphan_ea_inode/script b/tests/f_orphan_ea_inode/script new file mode 100644 index 000000000..9650d07d0 --- /dev/null +++ b/tests/f_orphan_ea_inode/script @@ -0,0 +1,3 @@ +FSCK_OPT=-p +SECOND_FSCK_OPT="-yf" +. $cmd_dir/run_e2fsck -- 2.43.7