Whamcloud - gitweb
e2fsck: update quota accounting after directory optimization
authorLuis Henriques (SUSE) <luis.henriques@linux.dev>
Fri, 5 Apr 2024 14:24:02 +0000 (15:24 +0100)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 16 Apr 2024 03:59:35 +0000 (23:59 -0400)
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) <luis.henriques@linux.dev>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Link: https://lore.kernel.org/r/20240405142405.12312-2-luis.henriques@linux.dev
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/rehash.c

index c1da7d5..4847d17 100644 (file)
@@ -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,25 @@ 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 != fs->super->s_orphan_file_inum) &&
+           (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);