diff mbox series

ceph: fix incorrectly showing the .snap size for stat

Message ID 20220831043759.94724-1-xiubli@redhat.com (mailing list archive)
State New, archived
Headers show
Series ceph: fix incorrectly showing the .snap size for stat | expand

Commit Message

Xiubo Li Aug. 31, 2022, 4:37 a.m. UTC
From: Xiubo Li <xiubli@redhat.com>

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@redhat.com>
---
 fs/ceph/inode.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 55 insertions(+), 2 deletions(-)

Comments

Xiubo Li Aug. 31, 2022, 7:34 a.m. UTC | #1
On 8/31/22 12:37 PM, xiubli@redhat.com wrote:
> From: Xiubo Li <xiubli@redhat.com>
>
> 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@redhat.com>
> ---
>   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;
>   		/*
diff mbox series

Patch

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;
+			iput(parent);
+		} else {
 			stat->size = ci->i_files + ci->i_subdirs;
+		}
 		stat->blocks = 0;
 		stat->blksize = 65536;
 		/*