On 8/31/22 12:37 PM, xiubli@xxxxxxxxxx wrote:
From: Xiubo Li <xiubli@xxxxxxxxxx>
We should set the 'stat->size' to the real number of snapshots for
snapdirs.
URL: https://tracker.ceph.com/issues/57342
Signed-off-by: Xiubo Li <xiubli@xxxxxxxxxx>
---
fs/ceph/inode.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 4db4394912e7..fafdeb169b22 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -2705,6 +2705,52 @@ static int statx_to_caps(u32 want, umode_t mode)
return mask;
}
+static struct inode *ceph_get_snap_parent(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(sb);
+ struct ceph_mds_request *req;
+ struct ceph_vino vino = {
+ .ino = ceph_ino(inode),
+ .snap = CEPH_NOSNAP,
+ };
+ struct inode *parent;
+ int mask;
+ int err;
+
+ if (ceph_vino_is_reserved(vino))
+ return ERR_PTR(-ESTALE);
+
+ parent = ceph_find_inode(sb, vino);
+ if (likely(parent)) {
+ if (ceph_inode_is_shutdown(parent)) {
+ iput(parent);
+ return ERR_PTR(-ESTALE);
+ }
+ return parent;
+ }
+
+ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
+ USE_ANY_MDS);
+ if (IS_ERR(req))
+ return ERR_CAST(req);
+
+ mask = CEPH_STAT_CAP_INODE;
+ if (ceph_security_xattr_wanted(d_inode(sb->s_root)))
+ mask |= CEPH_CAP_XATTR_SHARED;
+ req->r_args.lookupino.mask = cpu_to_le32(mask);
+ req->r_ino1 = vino;
+ req->r_num_caps = 1;
+ err = ceph_mdsc_do_request(mdsc, NULL, req);
+ if (err < 0)
+ return ERR_PTR(err);
+ parent = req->r_target_inode;
+ if (!parent)
+ return ERR_PTR(-ESTALE);
+ ihold(parent);
+ return parent;
+}
+
/*
* Get all the attributes. If we have sufficient caps for the requested attrs,
* then we can avoid talking to the MDS at all.
@@ -2748,10 +2794,17 @@ int ceph_getattr(struct user_namespace *mnt_userns, const struct path *path,
if (S_ISDIR(inode->i_mode)) {
if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb),
- RBYTES))
+ RBYTES)) {
stat->size = ci->i_rbytes;
- else
+ } else if (ceph_snap(inode) == CEPH_SNAPDIR) {
+ struct inode *parent = ceph_get_snap_parent(inode);
+ struct ceph_inode_info *pci = ceph_inode(parent);
+
+ stat->size = pci->i_rsnaps;
This seems incorrect. i_rsnaps will be the total number of all the snaps
including the descendants.
I will switch to use the snamrealm instead.
+ iput(parent);
+ } else {
stat->size = ci->i_files + ci->i_subdirs;
+ }
stat->blocks = 0;
stat->blksize = 65536;
/*