summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorXiubo Li <xiubli@redhat.com>2022-08-31 12:13:28 +0800
committerIlya Dryomov <idryomov@gmail.com>2022-10-04 19:18:08 +0200
commitaa87052dd965a6094355fcc13d5abc3f5bebfbe4 (patch)
tree7e39eb55593ab7a5d55884b9b09ec7817d6a97b2 /fs
parentbd04b9192e1ff6859d6b3906e91cfd5c9b0ad55b (diff)
downloadlinux-stable-aa87052dd965a6094355fcc13d5abc3f5bebfbe4.tar.gz
linux-stable-aa87052dd965a6094355fcc13d5abc3f5bebfbe4.tar.bz2
linux-stable-aa87052dd965a6094355fcc13d5abc3f5bebfbe4.zip
ceph: fix incorrectly showing the .snap size for stat
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/ceph/inode.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index a5e2eb5704c9..9ebb7cee7978 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -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;
/*