diff --git a/0050-e2fsck-update-quota-accounting-after-directory-optim.patch b/0050-e2fsck-update-quota-accounting-after-directory-optim.patch new file mode 100644 index 0000000000000000000000000000000000000000..b22ae6a51b57f21e06716fa3b0312cbcf825c39e --- /dev/null +++ b/0050-e2fsck-update-quota-accounting-after-directory-optim.patch @@ -0,0 +1,87 @@ +From eb782652045e67a5379dd319613b0d3d924901dd Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Fri, 5 Apr 2024 15:24:02 +0100 +Subject: [PATCH] e2fsck: update quota accounting after directory optimization + +In "Pass 3A: Optimizing directories", a directory may have it's size reduced. +If that happens and quota is enabled in the filesystem, the quota information +will be incorrect because it doesn't take the rehash into account. This issue +was detected by running fstest ext4/014. + +This patch simply updates the quota data accordingly, after the directory is +written and it's size has been updated. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=218626 +Signed-off-by: Luis Henriques (SUSE) +Reviewed-by: Andreas Dilger +Link: https://lore.kernel.org/r/20240405142405.12312-2-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +--- + e2fsck/rehash.c | 27 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c +index c1da7d52..4847d172 100644 +--- a/e2fsck/rehash.c ++++ b/e2fsck/rehash.c +@@ -987,14 +987,18 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, + { + ext2_filsys fs = ctx->fs; + errcode_t retval; +- struct ext2_inode inode; ++ struct ext2_inode_large inode; + char *dir_buf = 0; + struct fill_dir_struct fd = { NULL, NULL, 0, 0, 0, NULL, + 0, 0, 0, 0, 0, 0 }; + struct out_dir outdir = { 0, 0, 0, 0 }; +- struct name_cmp_ctx name_cmp_ctx = {0, NULL}; ++ struct name_cmp_ctx name_cmp_ctx = {0, NULL}; ++ __u64 osize; + +- e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); ++ e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode), ++ sizeof(inode), "rehash_dir"); ++ ++ osize = EXT2_I_SIZE(&inode); + + if (ext2fs_has_feature_inline_data(fs->super) && + (inode.i_flags & EXT4_INLINE_DATA_FL)) +@@ -1013,7 +1017,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, + fd.ino = ino; + fd.ctx = ctx; + fd.buf = dir_buf; +- fd.inode = &inode; ++ fd.inode = EXT2_INODE(&inode); + fd.dir = ino; + if (!ext2fs_has_feature_dir_index(fs->super) || + (inode.i_size / fs->blocksize) < 2) +@@ -1092,14 +1096,24 @@ resort: + goto errout; + } + +- retval = write_directory(ctx, fs, &outdir, ino, &inode, fd.compress); ++ retval = write_directory(ctx, fs, &outdir, ino, EXT2_INODE(&inode), ++ fd.compress); + if (retval) + goto errout; + ++ if ((osize > EXT2_I_SIZE(&inode)) && ++ (ino != quota_type2inum(PRJQUOTA, fs->super)) && ++ (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) && ++ !(inode.i_flags & EXT4_EA_INODE_FL)) { ++ quota_data_sub(ctx->qctx, &inode, ++ ino, osize - EXT2_I_SIZE(&inode)); ++ } ++ + if (ctx->options & E2F_OPT_CONVERT_BMAP) + retval = e2fsck_rebuild_extents_later(ctx, ino); + else +- retval = e2fsck_check_rebuild_extents(ctx, ino, &inode, pctx); ++ retval = e2fsck_check_rebuild_extents(ctx, ino, ++ EXT2_INODE(&inode), pctx); + errout: + ext2fs_free_mem(&dir_buf); + ext2fs_free_mem(&fd.harray); +-- +2.33.0 + diff --git a/0051-e2fsck-update-quota-when-deallocating-a-bad-inode.patch b/0051-e2fsck-update-quota-when-deallocating-a-bad-inode.patch new file mode 100644 index 0000000000000000000000000000000000000000..7938d36a927c0c93308e079837dd9042c00558e1 --- /dev/null +++ b/0051-e2fsck-update-quota-when-deallocating-a-bad-inode.patch @@ -0,0 +1,120 @@ +From eb0680deb908d7da399dd331b7aa35cc1a4dfa2d Mon Sep 17 00:00:00 2001 +From: "Luis Henriques (SUSE)" +Date: Fri, 5 Apr 2024 15:24:03 +0100 +Subject: [PATCH] e2fsck: update quota when deallocating a bad inode + +If a bad inode is found it will be deallocated. However, if the filesystem has +quota enabled, the quota information isn't being updated accordingly. This +issue was detected by running fstest ext4/019. + +This patch fixes the issue by decreasing the inode count from the +quota and, if blocks are also being released, also subtract them as well. + +While there, and as suggested by Andreas Dilger, the deallocate_inode() +function documentation is also updated by this patch to make it clear what +that function really does. + +Signed-off-by: Luis Henriques (SUSE) +Link: https://lore.kernel.org/r/20240405142405.12312-3-luis.henriques@linux.dev +Signed-off-by: Theodore Ts'o +--- + e2fsck/pass2.c | 43 +++++++++++++++++++++++++++++++----------- + 1 file changed, 31 insertions(+), 11 deletions(-) + +diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c +index b9162856..08ab40fa 100644 +--- a/e2fsck/pass2.c ++++ b/e2fsck/pass2.c +@@ -1854,17 +1854,26 @@ static int deallocate_inode_block(ext2_filsys fs, + } + + /* +- * This function deallocates an inode ++ * This function reverts various counters and bitmaps incremented in ++ * pass1 for the inode, blocks, and quotas before it was decided the ++ * inode was corrupt and needed to be cleared. This avoids the need ++ * to run e2fsck a second time (or have it restart itself) to repair ++ * these counters. ++ * ++ * It does not modify any on-disk state, so even if the inode is bad ++ * it _should_ reset in-memory state to before the inode was first ++ * processed. + */ + static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) + { + ext2_filsys fs = ctx->fs; +- struct ext2_inode inode; ++ struct ext2_inode_large inode; + struct problem_context pctx; + __u32 count; + struct del_block del_block; + +- e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); ++ e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode), ++ sizeof(inode), "deallocate_inode"); + clear_problem_context(&pctx); + pctx.ino = ino; + +@@ -1874,29 +1883,29 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) + e2fsck_read_bitmaps(ctx); + ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode)); + +- if (ext2fs_file_acl_block(fs, &inode) && ++ if (ext2fs_file_acl_block(fs, EXT2_INODE(&inode)) && + ext2fs_has_feature_xattr(fs->super)) { + pctx.errcode = ext2fs_adjust_ea_refcount3(fs, +- ext2fs_file_acl_block(fs, &inode), ++ ext2fs_file_acl_block(fs, EXT2_INODE(&inode)), + block_buf, -1, &count, ino); + if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) { + pctx.errcode = 0; + count = 1; + } + if (pctx.errcode) { +- pctx.blk = ext2fs_file_acl_block(fs, &inode); ++ pctx.blk = ext2fs_file_acl_block(fs, EXT2_INODE(&inode)); + fix_problem(ctx, PR_2_ADJ_EA_REFCOUNT, &pctx); + ctx->flags |= E2F_FLAG_ABORT; + return; + } + if (count == 0) { + ext2fs_block_alloc_stats2(fs, +- ext2fs_file_acl_block(fs, &inode), -1); ++ ext2fs_file_acl_block(fs, EXT2_INODE(&inode)), -1); + } +- ext2fs_file_acl_block_set(fs, &inode, 0); ++ ext2fs_file_acl_block_set(fs, EXT2_INODE(&inode), 0); + } + +- if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) ++ if (!ext2fs_inode_has_valid_blocks2(fs, EXT2_INODE(&inode))) + goto clear_inode; + + /* Inline data inodes don't have blocks to iterate */ +@@ -1921,10 +1930,21 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf) + ctx->flags |= E2F_FLAG_ABORT; + return; + } ++ ++ if ((ino != quota_type2inum(PRJQUOTA, fs->super)) && ++ (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) && ++ !(inode.i_flags & EXT4_EA_INODE_FL)) { ++ if (del_block.num > 0) ++ quota_data_sub(ctx->qctx, &inode, ino, ++ del_block.num * EXT2_CLUSTER_SIZE(fs->super)); ++ quota_data_inodes(ctx->qctx, (struct ext2_inode_large *)&inode, ++ ino, -1); ++ } ++ + clear_inode: + /* Inode may have changed by block_iterate, so reread it */ +- e2fsck_read_inode(ctx, ino, &inode, "deallocate_inode"); +- e2fsck_clear_inode(ctx, ino, &inode, 0, "deallocate_inode"); ++ e2fsck_read_inode(ctx, ino, EXT2_INODE(&inode), "deallocate_inode"); ++ e2fsck_clear_inode(ctx, ino, EXT2_INODE(&inode), 0, "deallocate_inode"); + } + + /* +-- +2.33.0 + diff --git a/e2fsprogs.spec b/e2fsprogs.spec index 99586a23cab7091c70d811f70567bdfb027f96e6..e0e64c18f8c515ebe60d8b94815b536fdad2b733 100644 --- a/e2fsprogs.spec +++ b/e2fsprogs.spec @@ -1,6 +1,6 @@ Name: e2fsprogs Version: 1.46.4 -Release: 28 +Release: 29 Summary: Second extended file system management tools License: GPLv2+ and LGPLv2 and MIT URL: http://e2fsprogs.sourceforge.net/ @@ -56,7 +56,9 @@ Patch46: 0046-e2fsck-fix-acl-block-leak-when-process-orphan-list.patch Patch47: 0047-e2fsck-when-mutating-file-name-make-sure-its-length-.patch Patch48: 0048-reisze2fs-sanity-check-free-block-group-counts-when-.patch Patch49: 0049-fsck-fix-memory-leak-on-an-error-exit.patch - +Patch50: 0050-e2fsck-update-quota-accounting-after-directory-optim.patch +Patch51: 0051-e2fsck-update-quota-when-deallocating-a-bad-inode.patch + BuildRequires: gcc pkgconfig texinfo BuildRequires: fuse-devel libblkid-devel libuuid-devel BuildRequires: audit @@ -196,6 +198,9 @@ exit 0 %{_mandir}/man8/* %changelog +* Fri Jul 19 2024 zhangjian - 1.46.4-29 +- backport patches for fixing quota bugs + * Tue Jul 2 2024 cenhuilin - 1.46.4-28 - fsck: fix memory leak on an error exit