Whamcloud - gitweb
LU-16771 llite: statfs on regular files is OK 98/59898/8
authorAndreas Dilger <adilger@whamcloud.com>
Mon, 23 Jun 2025 19:21:23 +0000 (13:21 -0600)
committerOleg Drokin <green@whamcloud.com>
Tue, 8 Jul 2025 03:59:26 +0000 (03:59 +0000)
It shouldn't be considered a bug to statfs() a regular file.
There doesn't appear to be anything directory-specific in
ll_statfs_project() that would warrant this LASSERT(), and
it can be trivially triggered from userspace.

Fixes: 2354f2f040 ("LU-16771 llite: cache statfs data for projects")
Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Change-Id: I3cf6b123e7ff40d233b4bb247935835a582b4a8f
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/59898
Reviewed-by: Timothy Day <timday@amazon.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Li Dongyang <dongyangli@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/llite/llite_lib.c
lustre/tests/sanity-quota.sh

index 5771bfd..092d42b 100644 (file)
@@ -2659,7 +2659,7 @@ static int ll_statfs_project(struct inode *inode, struct kstatfs *sfs)
        u64 limit, curblock;
        int ret;
 
-       LASSERT(S_ISDIR(inode->i_mode));
+       ENTRY;
 
        ps = rhashtable_lookup_fast(&sbi->ll_proj_sfs_htable,
                                    &lli->lli_projid,
@@ -2667,7 +2667,7 @@ static int ll_statfs_project(struct inode *inode, struct kstatfs *sfs)
        if (!ps) {
                OBD_ALLOC_PTR(ps);
                if (!ps)
-                       return -ENOMEM;
+                       RETURN(-ENOMEM);
                ps->psc_id = lli->lli_projid;
                mutex_init(&ps->psc_mutex);
                orig = rhashtable_lookup_get_insert_fast(&sbi->ll_proj_sfs_htable,
@@ -2676,14 +2676,14 @@ static int ll_statfs_project(struct inode *inode, struct kstatfs *sfs)
                if (orig) {
                        OBD_FREE_PTR(ps);
                        if (IS_ERR(orig))
-                               return PTR_ERR(orig);
+                               RETURN(PTR_ERR(orig));
                        ps = orig;
                }
        }
 
        if (ktime_get_seconds() - ps->psc_age < sbi->ll_statfs_max_age) {
                *sfs = ps->psc_sfs;
-               return 0;
+               RETURN(0);
        }
 
        mutex_lock(&ps->psc_mutex);
@@ -2731,7 +2731,7 @@ static int ll_statfs_project(struct inode *inode, struct kstatfs *sfs)
 out:
        mutex_unlock(&ps->psc_mutex);
 
-       return ret;
+       RETURN(ret);
 }
 
 int ll_statfs(struct dentry *de, struct kstatfs *sfs)
@@ -2743,7 +2743,8 @@ int ll_statfs(struct dentry *de, struct kstatfs *sfs)
        ktime_t kstart = ktime_get();
        int rc;
 
-       CDEBUG(D_VFSTRACE, "VFS Op:sb=%s (%p)\n", sb->s_id, sb);
+       CDEBUG(D_VFSTRACE, "VFS Op:sb=%s (%p) "DNAME" proj=%u\n", sb->s_id, sb,
+              encode_fn_dentry(de), ll_i2info(de->d_inode)->lli_projid);
 
        /* Some amount of caching on the client is allowed */
        rc = ll_statfs_internal(sbi, &osfs, OBD_STATFS_SUM);
index 498d651..4a59233 100755 (executable)
@@ -3921,6 +3921,7 @@ test_41() {
                skip "Project quota is not supported"
        setup_quota_test || error "setup quota failed with $?"
        local dir="$DIR/$tdir/dir"
+       local file="$dir/$tfile"
        local blimit=102400
        local ilimit=4096
        local projid=$((testnum * 1000))
@@ -3939,6 +3940,10 @@ test_41() {
        test_mkdir -p $dir && change_project -sp $projid $dir
        $LFS setquota -p $projid -b 0 -B ${blimit}K -i 0 -I $ilimit $dir ||
                error "set project quota failed"
+       touch $file || error "touch $file failed"
+       $LFS project $file
+       local file_proj=($($LFS project $file))
+       [[ ${file_proj[0]} == $projid ]] || error "project not set on $file"
 
        sync; sync_all_data
        sleep_maxage
@@ -3953,9 +3958,8 @@ test_41() {
        local iused=$(getquota -p $projid global curinodes)
        local expected="$ilimit$iused"
 
-       wait_update $HOSTNAME \
-               "df -iP $dir | awk \\\"/$FSNAME/\\\"'{print \\\$2 \\\$3}'" \
-               "$expected" ||
+       wait_update $HOSTNAME "df -iP $dir |
+               awk \\\"/$FSNAME/\\\"'{print \\\$2 \\\$3}'" "$expected" ||
                error "failed to get correct statfs for project quota"
 
        expected=$(df -kP $dir | awk "/$FSNAME/"' {print $2}')
@@ -3967,16 +3971,26 @@ test_41() {
        expected=$(df -kP $dir | awk "/$FSNAME/"' {print $3}')
        (( expected - bused < 4)) || error "bused mismatch: $expected != $bused"
 
+       # check if df output on regular file works as expected
+       echo "== project statfs on file (prjid=$projid): $file =="
+       df -kP $file; df -iP $file; $LFS quota -p $projid $dir
+       local bused=$(getquota -p $projid global curspace)
+       local iused=$(getquota -p $projid global curinodes)
+       local expected="$ilimit$iused"
+
+       wait_update $HOSTNAME "df -iP $dir |
+               awk \\\"/$FSNAME/\\\"'{print \\\$2 \\\$3}'" "$expected" ||
+               error "failed to get correct statfs for project quota"
+
        # disable statfs_project and check again
        $LCTL set_param llite.*.statfs_project=0
 
        expected=$({ df -kP $MOUNT; df -iP $MOUNT; } | \
                awk '/'$FSNAME'/ { printf "%d %d ", $2,$3 }')
 
-       wait_update $HOSTNAME \
-               "{ df -kP $dir; df -iP $dir; } |
-                awk '/$FSNAME/ { printf \\\"%d %d \\\", \\\$2,\\\$3 }'" \
-               "$expected" ||
+       wait_update $HOSTNAME "{ df -kP $dir; df -iP $dir; } |
+               awk '/$FSNAME/ { printf \\\"%d %d \\\", \\\$2,\\\$3 }'" \
+                       "$expected" ||
                error "failed to get correct statfs when statfs_project=0"
 }
 run_test 41 "df should return projid-specific values"