diff mbox series

ceph: reencode gid_list when reconnecting

Message ID 20201216213804.30419-1-idryomov@gmail.com (mailing list archive)
State New, archived
Headers show
Series ceph: reencode gid_list when reconnecting | expand

Commit Message

Ilya Dryomov Dec. 16, 2020, 9:38 p.m. UTC
On reconnect, cap and dentry releases are dropped and the fields
that follow must be reencoded into the freed space.  Currently these
are timestamp and gid_list, but gid_list isn't reencoded.  This
results in

  failed to decode message of type 24 v4: End of buffer

errors on the MDS.

While at it, make a change to encode gid_list unconditionally,
without regard to what head/which version was used as a result
of checking whether CEPH_FEATURE_FS_BTIME is supported or not.

URL: https://tracker.ceph.com/issues/48618
Fixes: 4f1ddb1ea874 ("ceph: implement updated ceph_mds_request_head structure")
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
 fs/ceph/mds_client.c | 53 ++++++++++++++++++--------------------------
 1 file changed, 22 insertions(+), 31 deletions(-)

Comments

Jeff Layton Dec. 16, 2020, 9:44 p.m. UTC | #1
On Wed, 2020-12-16 at 22:38 +0100, Ilya Dryomov wrote:
> On reconnect, cap and dentry releases are dropped and the fields
> that follow must be reencoded into the freed space.  Currently these
> are timestamp and gid_list, but gid_list isn't reencoded.  This
> results in
> 
>   failed to decode message of type 24 v4: End of buffer
> 
> errors on the MDS.
> 
> While at it, make a change to encode gid_list unconditionally,
> without regard to what head/which version was used as a result
> of checking whether CEPH_FEATURE_FS_BTIME is supported or not.
> 
> URL: https://tracker.ceph.com/issues/48618
> Fixes: 4f1ddb1ea874 ("ceph: implement updated ceph_mds_request_head structure")
> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
> ---
>  fs/ceph/mds_client.c | 53 ++++++++++++++++++--------------------------
>  1 file changed, 22 insertions(+), 31 deletions(-)
> 
> diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
> index 98c15ff2e599..840587037b59 100644
> --- a/fs/ceph/mds_client.c
> +++ b/fs/ceph/mds_client.c
> @@ -2475,6 +2475,22 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry,
>  	return r;
>  }
>  
> 
> +static void encode_timestamp_and_gids(void **p,
> +				      const struct ceph_mds_request *req)
> +{
> +	struct ceph_timespec ts;
> +	int i;
> +
> +	ceph_encode_timespec64(&ts, &req->r_stamp);
> +	ceph_encode_copy(p, &ts, sizeof(ts));
> +
> +	/* gid_list */
> +	ceph_encode_32(p, req->r_cred->group_info->ngroups);
> +	for (i = 0; i < req->r_cred->group_info->ngroups; i++)
> +		ceph_encode_64(p, from_kgid(&init_user_ns,
> +					    req->r_cred->group_info->gid[i]));
> +}
> +
>  /*
>   * called under mdsc->mutex
>   */
> @@ -2491,7 +2507,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
>  	u64 ino1 = 0, ino2 = 0;
>  	int pathlen1 = 0, pathlen2 = 0;
>  	bool freepath1 = false, freepath2 = false;
> -	int len, i;
> +	int len;
>  	u16 releases;
>  	void *p, *end;
>  	int ret;
> @@ -2517,17 +2533,10 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
>  		goto out_free1;
>  	}
>  
> 
> -	if (legacy) {
> -		/* Old style */
> -		len = sizeof(*head);
> -	} else {
> -		/* New style: add gid_list and any later fields */
> -		len = sizeof(struct ceph_mds_request_head) + sizeof(u32) +
> -		      (sizeof(u64) * req->r_cred->group_info->ngroups);
> -	}
> -
> +	len = legacy ? sizeof(*head) : sizeof(struct ceph_mds_request_head);
>  	len += pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)) +
>  		sizeof(struct ceph_timespec);
> +	len += sizeof(u32) + (sizeof(u64) * req->r_cred->group_info->ngroups);
>  
> 
>  	/* calculate (max) length for cap releases */
>  	len += sizeof(struct ceph_mds_request_release) *
> @@ -2548,7 +2557,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
>  	msg->hdr.tid = cpu_to_le64(req->r_tid);
>  
> 
>  	/*
> -	 * The old ceph_mds_request_header didn't contain a version field, and
> +	 * The old ceph_mds_request_head didn't contain a version field, and
>  	 * one was added when we moved the message version from 3->4.
>  	 */
>  	if (legacy) {
> @@ -2609,20 +2618,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
>  
> 
>  	head->num_releases = cpu_to_le16(releases);
>  
> 
> -	/* time stamp */
> -	{
> -		struct ceph_timespec ts;
> -		ceph_encode_timespec64(&ts, &req->r_stamp);
> -		ceph_encode_copy(&p, &ts, sizeof(ts));
> -	}
> -
> -	/* gid list */
> -	if (!legacy) {
> -		ceph_encode_32(&p, req->r_cred->group_info->ngroups);
> -		for (i = 0; i < req->r_cred->group_info->ngroups; i++)
> -			ceph_encode_64(&p, from_kgid(&init_user_ns,
> -				       req->r_cred->group_info->gid[i]));
> -	}
> +	encode_timestamp_and_gids(&p, req);
>  
> 
>  	if (WARN_ON_ONCE(p > end)) {
>  		ceph_msg_put(msg);
> @@ -2730,13 +2726,8 @@ static int __prepare_send_request(struct ceph_mds_session *session,
>  		/* remove cap/dentry releases from message */
>  		rhead->num_releases = 0;
>  
> 
> -		/* time stamp */
>  		p = msg->front.iov_base + req->r_request_release_offset;
> -		{
> -			struct ceph_timespec ts;
> -			ceph_encode_timespec64(&ts, &req->r_stamp);
> -			ceph_encode_copy(&p, &ts, sizeof(ts));
> -		}
> +		encode_timestamp_and_gids(&p, req);
>  
> 
>  		msg->front.iov_len = p - msg->front.iov_base;
>  		msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);

Reviewed-by: Jeff Layton <jlayton@kernel.org>
diff mbox series

Patch

diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 98c15ff2e599..840587037b59 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -2475,6 +2475,22 @@  static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry,
 	return r;
 }
 
+static void encode_timestamp_and_gids(void **p,
+				      const struct ceph_mds_request *req)
+{
+	struct ceph_timespec ts;
+	int i;
+
+	ceph_encode_timespec64(&ts, &req->r_stamp);
+	ceph_encode_copy(p, &ts, sizeof(ts));
+
+	/* gid_list */
+	ceph_encode_32(p, req->r_cred->group_info->ngroups);
+	for (i = 0; i < req->r_cred->group_info->ngroups; i++)
+		ceph_encode_64(p, from_kgid(&init_user_ns,
+					    req->r_cred->group_info->gid[i]));
+}
+
 /*
  * called under mdsc->mutex
  */
@@ -2491,7 +2507,7 @@  static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
 	u64 ino1 = 0, ino2 = 0;
 	int pathlen1 = 0, pathlen2 = 0;
 	bool freepath1 = false, freepath2 = false;
-	int len, i;
+	int len;
 	u16 releases;
 	void *p, *end;
 	int ret;
@@ -2517,17 +2533,10 @@  static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
 		goto out_free1;
 	}
 
-	if (legacy) {
-		/* Old style */
-		len = sizeof(*head);
-	} else {
-		/* New style: add gid_list and any later fields */
-		len = sizeof(struct ceph_mds_request_head) + sizeof(u32) +
-		      (sizeof(u64) * req->r_cred->group_info->ngroups);
-	}
-
+	len = legacy ? sizeof(*head) : sizeof(struct ceph_mds_request_head);
 	len += pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)) +
 		sizeof(struct ceph_timespec);
+	len += sizeof(u32) + (sizeof(u64) * req->r_cred->group_info->ngroups);
 
 	/* calculate (max) length for cap releases */
 	len += sizeof(struct ceph_mds_request_release) *
@@ -2548,7 +2557,7 @@  static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
 	msg->hdr.tid = cpu_to_le64(req->r_tid);
 
 	/*
-	 * The old ceph_mds_request_header didn't contain a version field, and
+	 * The old ceph_mds_request_head didn't contain a version field, and
 	 * one was added when we moved the message version from 3->4.
 	 */
 	if (legacy) {
@@ -2609,20 +2618,7 @@  static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
 
 	head->num_releases = cpu_to_le16(releases);
 
-	/* time stamp */
-	{
-		struct ceph_timespec ts;
-		ceph_encode_timespec64(&ts, &req->r_stamp);
-		ceph_encode_copy(&p, &ts, sizeof(ts));
-	}
-
-	/* gid list */
-	if (!legacy) {
-		ceph_encode_32(&p, req->r_cred->group_info->ngroups);
-		for (i = 0; i < req->r_cred->group_info->ngroups; i++)
-			ceph_encode_64(&p, from_kgid(&init_user_ns,
-				       req->r_cred->group_info->gid[i]));
-	}
+	encode_timestamp_and_gids(&p, req);
 
 	if (WARN_ON_ONCE(p > end)) {
 		ceph_msg_put(msg);
@@ -2730,13 +2726,8 @@  static int __prepare_send_request(struct ceph_mds_session *session,
 		/* remove cap/dentry releases from message */
 		rhead->num_releases = 0;
 
-		/* time stamp */
 		p = msg->front.iov_base + req->r_request_release_offset;
-		{
-			struct ceph_timespec ts;
-			ceph_encode_timespec64(&ts, &req->r_stamp);
-			ceph_encode_copy(&p, &ts, sizeof(ts));
-		}
+		encode_timestamp_and_gids(&p, req);
 
 		msg->front.iov_len = p - msg->front.iov_base;
 		msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);