ceph: fix incorrectly showing the .snap size for stat
authorXiubo Li <xiubli@redhat.com>
Wed, 31 Aug 2022 04:13:28 +0000 (12:13 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Tue, 4 Oct 2022 17:18:08 +0000 (19:18 +0200)
We should set the 'stat->size' to the real number of snapshots for
snapdirs.

Link: https://tracker.ceph.com/issues/57342
Signed-off-by: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/inode.c

index a5e2eb5..9ebb7ce 100644 (file)
@@ -2449,6 +2449,7 @@ int ceph_getattr(struct user_namespace *mnt_userns, const struct path *path,
                 struct kstat *stat, u32 request_mask, unsigned int flags)
 {
        struct inode *inode = d_inode(path->dentry);
+       struct super_block *sb = inode->i_sb;
        struct ceph_inode_info *ci = ceph_inode(inode);
        u32 valid_mask = STATX_BASIC_STATS;
        int err = 0;
@@ -2478,16 +2479,34 @@ int ceph_getattr(struct user_namespace *mnt_userns, const struct path *path,
        }
 
        if (ceph_snap(inode) == CEPH_NOSNAP)
-               stat->dev = inode->i_sb->s_dev;
+               stat->dev = sb->s_dev;
        else
                stat->dev = ci->i_snapid_map ? ci->i_snapid_map->dev : 0;
 
        if (S_ISDIR(inode->i_mode)) {
-               if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb),
-                                       RBYTES))
+               if (ceph_test_mount_opt(ceph_sb_to_client(sb), RBYTES)) {
                        stat->size = ci->i_rbytes;
-               else
+               } else if (ceph_snap(inode) == CEPH_SNAPDIR) {
+                       struct ceph_inode_info *pci;
+                       struct ceph_snap_realm *realm;
+                       struct inode *parent;
+
+                       parent = ceph_lookup_inode(sb, ceph_ino(inode));
+                       if (!parent)
+                               return PTR_ERR(parent);
+
+                       pci = ceph_inode(parent);
+                       spin_lock(&pci->i_ceph_lock);
+                       realm = pci->i_snap_realm;
+                       if (realm)
+                               stat->size = realm->num_snaps;
+                       else
+                               stat->size = 0;
+                       spin_unlock(&pci->i_ceph_lock);
+                       iput(parent);
+               } else {
                        stat->size = ci->i_files + ci->i_subdirs;
+               }
                stat->blocks = 0;
                stat->blksize = 65536;
                /*