diff mbox series

[RFC,v7,07/24] ceph: add fscrypt_* handling to caps.c

Message ID 20210625135834.12934-8-jlayton@kernel.org (mailing list archive)
State Not Applicable
Headers show
Series ceph+fscrypt: context, filename and symlink support | expand

Commit Message

Jeff Layton June 25, 2021, 1:58 p.m. UTC
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/ceph/caps.c | 62 +++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 49 insertions(+), 13 deletions(-)

Comments

Xiubo Li July 7, 2021, 7:20 a.m. UTC | #1
Hi Jeff,

There has some following patches in your "fscrypt" branch, which is not 
posted yet, the commit is:

"3161d2f549db ceph: size handling for encrypted inodes in cap updates"

It seems buggy.

In the encode_cap_msg() you have removed the 'fscrypt_file_len' and and 
added a new 8 bytes' data encoding:

         ceph_encode_32(&p, arg->fscrypt_auth_len);
         ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len);
-       ceph_encode_32(&p, arg->fscrypt_file_len);
-       ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len);
+       ceph_encode_32(&p, sizeof(__le64));
+       ceph_encode_64(&p, fc->size);

That means no matter the 'arg->encrypted' is true or not, here it will 
always encode extra 8 bytes' data ?


But in cap_msg_size(), you are making it optional:


  static inline int cap_msg_size(struct cap_msg_args *arg)
  {
         return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len +
-                       arg->fscrypt_file_len;
+                       arg->encrypted ? sizeof(__le64) : 0;
  }


Have I missed something important here ?

Thanks


On 6/25/21 9:58 PM, Jeff Layton wrote:
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>   fs/ceph/caps.c | 62 +++++++++++++++++++++++++++++++++++++++-----------
>   1 file changed, 49 insertions(+), 13 deletions(-)
>
> diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
> index 038f59cc4250..1be6c5148700 100644
> --- a/fs/ceph/caps.c
> +++ b/fs/ceph/caps.c
> @@ -13,6 +13,7 @@
>   #include "super.h"
>   #include "mds_client.h"
>   #include "cache.h"
> +#include "crypto.h"
>   #include <linux/ceph/decode.h>
>   #include <linux/ceph/messenger.h>
>   
> @@ -1229,15 +1230,12 @@ struct cap_msg_args {
>   	umode_t			mode;
>   	bool			inline_data;
>   	bool			wake;
> +	u32			fscrypt_auth_len;
> +	u32			fscrypt_file_len;
> +	u8			fscrypt_auth[sizeof(struct ceph_fscrypt_auth)]; // for context
> +	u8			fscrypt_file[sizeof(u64)]; // for size
>   };
>   
> -/*
> - * cap struct size + flock buffer size + inline version + inline data size +
> - * osd_epoch_barrier + oldest_flush_tid
> - */
> -#define CAP_MSG_SIZE (sizeof(struct ceph_mds_caps) + \
> -		      4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4)
> -
>   /* Marshal up the cap msg to the MDS */
>   static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
>   {
> @@ -1253,7 +1251,7 @@ static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
>   	     arg->size, arg->max_size, arg->xattr_version,
>   	     arg->xattr_buf ? (int)arg->xattr_buf->vec.iov_len : 0);
>   
> -	msg->hdr.version = cpu_to_le16(10);
> +	msg->hdr.version = cpu_to_le16(12);
>   	msg->hdr.tid = cpu_to_le64(arg->flush_tid);
>   
>   	fc = msg->front.iov_base;
> @@ -1324,6 +1322,16 @@ static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
>   
>   	/* Advisory flags (version 10) */
>   	ceph_encode_32(&p, arg->flags);
> +
> +	/* dirstats (version 11) - these are r/o on the client */
> +	ceph_encode_64(&p, 0);
> +	ceph_encode_64(&p, 0);
> +
> +	/* fscrypt_auth and fscrypt_file (version 12) */
> +	ceph_encode_32(&p, arg->fscrypt_auth_len);
> +	ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len);
> +	ceph_encode_32(&p, arg->fscrypt_file_len);
> +	ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len);
>   }
>   
>   /*
> @@ -1445,6 +1453,26 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
>   		}
>   	}
>   	arg->flags = flags;
> +	if (ci->fscrypt_auth_len &&
> +	    WARN_ON_ONCE(ci->fscrypt_auth_len != sizeof(struct ceph_fscrypt_auth))) {
> +		/* Don't set this if it isn't right size */
> +		arg->fscrypt_auth_len = 0;
> +	} else {
> +		arg->fscrypt_auth_len = ci->fscrypt_auth_len;
> +		memcpy(arg->fscrypt_auth, ci->fscrypt_auth,
> +			min_t(size_t, ci->fscrypt_auth_len, sizeof(arg->fscrypt_auth)));
> +	}
> +	/* FIXME: use this to track "real" size */
> +	arg->fscrypt_file_len = 0;
> +}
> +
> +#define CAP_MSG_FIXED_FIELDS (sizeof(struct ceph_mds_caps) + \
> +		      4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + 8 + 4 + 4)
> +
> +static inline int cap_msg_size(struct cap_msg_args *arg)
> +{
> +	return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len +
> +			arg->fscrypt_file_len;
>   }
>   
>   /*
> @@ -1457,7 +1485,7 @@ static void __send_cap(struct cap_msg_args *arg, struct ceph_inode_info *ci)
>   	struct ceph_msg *msg;
>   	struct inode *inode = &ci->vfs_inode;
>   
> -	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false);
> +	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(arg), GFP_NOFS, false);
>   	if (!msg) {
>   		pr_err("error allocating cap msg: ino (%llx.%llx) flushing %s tid %llu, requeuing cap.\n",
>   		       ceph_vinop(inode), ceph_cap_string(arg->dirty),
> @@ -1483,10 +1511,6 @@ static inline int __send_flush_snap(struct inode *inode,
>   	struct cap_msg_args	arg;
>   	struct ceph_msg		*msg;
>   
> -	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false);
> -	if (!msg)
> -		return -ENOMEM;
> -
>   	arg.session = session;
>   	arg.ino = ceph_vino(inode).ino;
>   	arg.cid = 0;
> @@ -1524,6 +1548,18 @@ static inline int __send_flush_snap(struct inode *inode,
>   	arg.flags = 0;
>   	arg.wake = false;
>   
> +	/*
> +	 * No fscrypt_auth changes from a capsnap. It will need
> +	 * to update fscrypt_file on size changes (TODO).
> +	 */
> +	arg.fscrypt_auth_len = 0;
> +	arg.fscrypt_file_len = 0;
> +
> +	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(&arg),
> +			   GFP_NOFS, false);
> +	if (!msg)
> +		return -ENOMEM;
> +
>   	encode_cap_msg(msg, &arg);
>   	ceph_con_send(&arg.session->s_con, msg);
>   	return 0;
Jeff Layton July 7, 2021, 12:02 p.m. UTC | #2
On Wed, 2021-07-07 at 15:20 +0800, Xiubo Li wrote:
> Hi Jeff,
> 
> There has some following patches in your "fscrypt" branch, which is not 
> posted yet, the commit is:
> 
> "3161d2f549db ceph: size handling for encrypted inodes in cap updates"
> 
> It seems buggy.
> 

Yes. Those are still quite rough. If I haven't posted them, then YMMV. I
often push them to -experimental branches just for backup purposes. You
may want to wait on reviewing those until I've had a chance to clean
them up and post them.

> In the encode_cap_msg() you have removed the 'fscrypt_file_len' and and 
> added a new 8 bytes' data encoding:
> 
>          ceph_encode_32(&p, arg->fscrypt_auth_len);
>          ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len);
> -       ceph_encode_32(&p, arg->fscrypt_file_len);
> -       ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len);
> +       ceph_encode_32(&p, sizeof(__le64));
> +       ceph_encode_64(&p, fc->size);
> 
> That means no matter the 'arg->encrypted' is true or not, here it will 
> always encode extra 8 bytes' data ?
> 
> 
> But in cap_msg_size(), you are making it optional:
> 
> 
>   static inline int cap_msg_size(struct cap_msg_args *arg)
>   {
>          return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len +
> -                       arg->fscrypt_file_len;
> +                       arg->encrypted ? sizeof(__le64) : 0;
>   }
> 
> 
> Have I missed something important here ?
> 
> Thanks
> 

Nope, you're right. I had fixed that one in my local branch already, and
just hadn't yet pushed it to the repo. I'll plan to clean this up a bit
later today and push an updated branch.

> 
> On 6/25/21 9:58 PM, Jeff Layton wrote:
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> >   fs/ceph/caps.c | 62 +++++++++++++++++++++++++++++++++++++++-----------
> >   1 file changed, 49 insertions(+), 13 deletions(-)
> > 
> > diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
> > index 038f59cc4250..1be6c5148700 100644
> > --- a/fs/ceph/caps.c
> > +++ b/fs/ceph/caps.c
> > @@ -13,6 +13,7 @@
> >   #include "super.h"
> >   #include "mds_client.h"
> >   #include "cache.h"
> > +#include "crypto.h"
> >   #include <linux/ceph/decode.h>
> >   #include <linux/ceph/messenger.h>
> >   
> > @@ -1229,15 +1230,12 @@ struct cap_msg_args {
> >   	umode_t			mode;
> >   	bool			inline_data;
> >   	bool			wake;
> > +	u32			fscrypt_auth_len;
> > +	u32			fscrypt_file_len;
> > +	u8			fscrypt_auth[sizeof(struct ceph_fscrypt_auth)]; // for context
> > +	u8			fscrypt_file[sizeof(u64)]; // for size
> >   };
> >   
> > -/*
> > - * cap struct size + flock buffer size + inline version + inline data size +
> > - * osd_epoch_barrier + oldest_flush_tid
> > - */
> > -#define CAP_MSG_SIZE (sizeof(struct ceph_mds_caps) + \
> > -		      4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4)
> > -
> >   /* Marshal up the cap msg to the MDS */
> >   static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
> >   {
> > @@ -1253,7 +1251,7 @@ static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
> >   	     arg->size, arg->max_size, arg->xattr_version,
> >   	     arg->xattr_buf ? (int)arg->xattr_buf->vec.iov_len : 0);
> >   
> > -	msg->hdr.version = cpu_to_le16(10);
> > +	msg->hdr.version = cpu_to_le16(12);
> >   	msg->hdr.tid = cpu_to_le64(arg->flush_tid);
> >   
> >   	fc = msg->front.iov_base;
> > @@ -1324,6 +1322,16 @@ static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
> >   
> >   	/* Advisory flags (version 10) */
> >   	ceph_encode_32(&p, arg->flags);
> > +
> > +	/* dirstats (version 11) - these are r/o on the client */
> > +	ceph_encode_64(&p, 0);
> > +	ceph_encode_64(&p, 0);
> > +
> > +	/* fscrypt_auth and fscrypt_file (version 12) */
> > +	ceph_encode_32(&p, arg->fscrypt_auth_len);
> > +	ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len);
> > +	ceph_encode_32(&p, arg->fscrypt_file_len);
> > +	ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len);
> >   }
> >   
> >   /*
> > @@ -1445,6 +1453,26 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
> >   		}
> >   	}
> >   	arg->flags = flags;
> > +	if (ci->fscrypt_auth_len &&
> > +	    WARN_ON_ONCE(ci->fscrypt_auth_len != sizeof(struct ceph_fscrypt_auth))) {
> > +		/* Don't set this if it isn't right size */
> > +		arg->fscrypt_auth_len = 0;
> > +	} else {
> > +		arg->fscrypt_auth_len = ci->fscrypt_auth_len;
> > +		memcpy(arg->fscrypt_auth, ci->fscrypt_auth,
> > +			min_t(size_t, ci->fscrypt_auth_len, sizeof(arg->fscrypt_auth)));
> > +	}
> > +	/* FIXME: use this to track "real" size */
> > +	arg->fscrypt_file_len = 0;
> > +}
> > +
> > +#define CAP_MSG_FIXED_FIELDS (sizeof(struct ceph_mds_caps) + \
> > +		      4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + 8 + 4 + 4)
> > +
> > +static inline int cap_msg_size(struct cap_msg_args *arg)
> > +{
> > +	return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len +
> > +			arg->fscrypt_file_len;
> >   }
> >   
> >   /*
> > @@ -1457,7 +1485,7 @@ static void __send_cap(struct cap_msg_args *arg, struct ceph_inode_info *ci)
> >   	struct ceph_msg *msg;
> >   	struct inode *inode = &ci->vfs_inode;
> >   
> > -	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false);
> > +	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(arg), GFP_NOFS, false);
> >   	if (!msg) {
> >   		pr_err("error allocating cap msg: ino (%llx.%llx) flushing %s tid %llu, requeuing cap.\n",
> >   		       ceph_vinop(inode), ceph_cap_string(arg->dirty),
> > @@ -1483,10 +1511,6 @@ static inline int __send_flush_snap(struct inode *inode,
> >   	struct cap_msg_args	arg;
> >   	struct ceph_msg		*msg;
> >   
> > -	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false);
> > -	if (!msg)
> > -		return -ENOMEM;
> > -
> >   	arg.session = session;
> >   	arg.ino = ceph_vino(inode).ino;
> >   	arg.cid = 0;
> > @@ -1524,6 +1548,18 @@ static inline int __send_flush_snap(struct inode *inode,
> >   	arg.flags = 0;
> >   	arg.wake = false;
> >   
> > +	/*
> > +	 * No fscrypt_auth changes from a capsnap. It will need
> > +	 * to update fscrypt_file on size changes (TODO).
> > +	 */
> > +	arg.fscrypt_auth_len = 0;
> > +	arg.fscrypt_file_len = 0;
> > +
> > +	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(&arg),
> > +			   GFP_NOFS, false);
> > +	if (!msg)
> > +		return -ENOMEM;
> > +
> >   	encode_cap_msg(msg, &arg);
> >   	ceph_con_send(&arg.session->s_con, msg);
> >   	return 0;
>
Xiubo Li July 7, 2021, 12:47 p.m. UTC | #3
On 7/7/21 8:02 PM, Jeff Layton wrote:
> On Wed, 2021-07-07 at 15:20 +0800, Xiubo Li wrote:
>> Hi Jeff,
>>
>> There has some following patches in your "fscrypt" branch, which is not
>> posted yet, the commit is:
>>
>> "3161d2f549db ceph: size handling for encrypted inodes in cap updates"
>>
>> It seems buggy.
>>
> Yes. Those are still quite rough. If I haven't posted them, then YMMV. I
> often push them to -experimental branches just for backup purposes. You
> may want to wait on reviewing those until I've had a chance to clean
> them up and post them.

Yeah, sure.

I am reviewing the code from you experimental branch.


>> In the encode_cap_msg() you have removed the 'fscrypt_file_len' and and
>> added a new 8 bytes' data encoding:
>>
>>           ceph_encode_32(&p, arg->fscrypt_auth_len);
>>           ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len);
>> -       ceph_encode_32(&p, arg->fscrypt_file_len);
>> -       ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len);
>> +       ceph_encode_32(&p, sizeof(__le64));
>> +       ceph_encode_64(&p, fc->size);
>>
>> That means no matter the 'arg->encrypted' is true or not, here it will
>> always encode extra 8 bytes' data ?
>>
>>
>> But in cap_msg_size(), you are making it optional:
>>
>>
>>    static inline int cap_msg_size(struct cap_msg_args *arg)
>>    {
>>           return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len +
>> -                       arg->fscrypt_file_len;
>> +                       arg->encrypted ? sizeof(__le64) : 0;
>>    }
>>
>>
>> Have I missed something important here ?
>>
>> Thanks
>>
> Nope, you're right. I had fixed that one in my local branch already, and
> just hadn't yet pushed it to the repo. I'll plan to clean this up a bit
> later today and push an updated branch.

Cool.

Thanks.


>
>> On 6/25/21 9:58 PM, Jeff Layton wrote:
>>> Signed-off-by: Jeff Layton <jlayton@kernel.org>
>>> ---
>>>    fs/ceph/caps.c | 62 +++++++++++++++++++++++++++++++++++++++-----------
>>>    1 file changed, 49 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
>>> index 038f59cc4250..1be6c5148700 100644
>>> --- a/fs/ceph/caps.c
>>> +++ b/fs/ceph/caps.c
>>> @@ -13,6 +13,7 @@
>>>    #include "super.h"
>>>    #include "mds_client.h"
>>>    #include "cache.h"
>>> +#include "crypto.h"
>>>    #include <linux/ceph/decode.h>
>>>    #include <linux/ceph/messenger.h>
>>>    
>>> @@ -1229,15 +1230,12 @@ struct cap_msg_args {
>>>    	umode_t			mode;
>>>    	bool			inline_data;
>>>    	bool			wake;
>>> +	u32			fscrypt_auth_len;
>>> +	u32			fscrypt_file_len;
>>> +	u8			fscrypt_auth[sizeof(struct ceph_fscrypt_auth)]; // for context
>>> +	u8			fscrypt_file[sizeof(u64)]; // for size
>>>    };
>>>    
>>> -/*
>>> - * cap struct size + flock buffer size + inline version + inline data size +
>>> - * osd_epoch_barrier + oldest_flush_tid
>>> - */
>>> -#define CAP_MSG_SIZE (sizeof(struct ceph_mds_caps) + \
>>> -		      4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4)
>>> -
>>>    /* Marshal up the cap msg to the MDS */
>>>    static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
>>>    {
>>> @@ -1253,7 +1251,7 @@ static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
>>>    	     arg->size, arg->max_size, arg->xattr_version,
>>>    	     arg->xattr_buf ? (int)arg->xattr_buf->vec.iov_len : 0);
>>>    
>>> -	msg->hdr.version = cpu_to_le16(10);
>>> +	msg->hdr.version = cpu_to_le16(12);
>>>    	msg->hdr.tid = cpu_to_le64(arg->flush_tid);
>>>    
>>>    	fc = msg->front.iov_base;
>>> @@ -1324,6 +1322,16 @@ static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
>>>    
>>>    	/* Advisory flags (version 10) */
>>>    	ceph_encode_32(&p, arg->flags);
>>> +
>>> +	/* dirstats (version 11) - these are r/o on the client */
>>> +	ceph_encode_64(&p, 0);
>>> +	ceph_encode_64(&p, 0);
>>> +
>>> +	/* fscrypt_auth and fscrypt_file (version 12) */
>>> +	ceph_encode_32(&p, arg->fscrypt_auth_len);
>>> +	ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len);
>>> +	ceph_encode_32(&p, arg->fscrypt_file_len);
>>> +	ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len);
>>>    }
>>>    
>>>    /*
>>> @@ -1445,6 +1453,26 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
>>>    		}
>>>    	}
>>>    	arg->flags = flags;
>>> +	if (ci->fscrypt_auth_len &&
>>> +	    WARN_ON_ONCE(ci->fscrypt_auth_len != sizeof(struct ceph_fscrypt_auth))) {
>>> +		/* Don't set this if it isn't right size */
>>> +		arg->fscrypt_auth_len = 0;
>>> +	} else {
>>> +		arg->fscrypt_auth_len = ci->fscrypt_auth_len;
>>> +		memcpy(arg->fscrypt_auth, ci->fscrypt_auth,
>>> +			min_t(size_t, ci->fscrypt_auth_len, sizeof(arg->fscrypt_auth)));
>>> +	}
>>> +	/* FIXME: use this to track "real" size */
>>> +	arg->fscrypt_file_len = 0;
>>> +}
>>> +
>>> +#define CAP_MSG_FIXED_FIELDS (sizeof(struct ceph_mds_caps) + \
>>> +		      4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + 8 + 4 + 4)
>>> +
>>> +static inline int cap_msg_size(struct cap_msg_args *arg)
>>> +{
>>> +	return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len +
>>> +			arg->fscrypt_file_len;
>>>    }
>>>    
>>>    /*
>>> @@ -1457,7 +1485,7 @@ static void __send_cap(struct cap_msg_args *arg, struct ceph_inode_info *ci)
>>>    	struct ceph_msg *msg;
>>>    	struct inode *inode = &ci->vfs_inode;
>>>    
>>> -	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false);
>>> +	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(arg), GFP_NOFS, false);
>>>    	if (!msg) {
>>>    		pr_err("error allocating cap msg: ino (%llx.%llx) flushing %s tid %llu, requeuing cap.\n",
>>>    		       ceph_vinop(inode), ceph_cap_string(arg->dirty),
>>> @@ -1483,10 +1511,6 @@ static inline int __send_flush_snap(struct inode *inode,
>>>    	struct cap_msg_args	arg;
>>>    	struct ceph_msg		*msg;
>>>    
>>> -	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false);
>>> -	if (!msg)
>>> -		return -ENOMEM;
>>> -
>>>    	arg.session = session;
>>>    	arg.ino = ceph_vino(inode).ino;
>>>    	arg.cid = 0;
>>> @@ -1524,6 +1548,18 @@ static inline int __send_flush_snap(struct inode *inode,
>>>    	arg.flags = 0;
>>>    	arg.wake = false;
>>>    
>>> +	/*
>>> +	 * No fscrypt_auth changes from a capsnap. It will need
>>> +	 * to update fscrypt_file on size changes (TODO).
>>> +	 */
>>> +	arg.fscrypt_auth_len = 0;
>>> +	arg.fscrypt_file_len = 0;
>>> +
>>> +	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(&arg),
>>> +			   GFP_NOFS, false);
>>> +	if (!msg)
>>> +		return -ENOMEM;
>>> +
>>>    	encode_cap_msg(msg, &arg);
>>>    	ceph_con_send(&arg.session->s_con, msg);
>>>    	return 0;
Eric Biggers July 11, 2021, 11 p.m. UTC | #4
On Fri, Jun 25, 2021 at 09:58:17AM -0400, Jeff Layton wrote:
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  fs/ceph/caps.c | 62 +++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 49 insertions(+), 13 deletions(-)
> 
> diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
> index 038f59cc4250..1be6c5148700 100644
> --- a/fs/ceph/caps.c
> +++ b/fs/ceph/caps.c
> @@ -13,6 +13,7 @@
>  #include "super.h"
>  #include "mds_client.h"
>  #include "cache.h"
> +#include "crypto.h"
>  #include <linux/ceph/decode.h>
>  #include <linux/ceph/messenger.h>
>  
> @@ -1229,15 +1230,12 @@ struct cap_msg_args {
>  	umode_t			mode;
>  	bool			inline_data;
>  	bool			wake;
> +	u32			fscrypt_auth_len;
> +	u32			fscrypt_file_len;
> +	u8			fscrypt_auth[sizeof(struct ceph_fscrypt_auth)]; // for context
> +	u8			fscrypt_file[sizeof(u64)]; // for size
>  };

The naming of these is confusing to me.  If these are the fscrypt context and
the original file size, why aren't they called something like fscrypt_context
and fscrypt_file_size?

Also does the file size really need to be variable-length, or could it just be a
64-bit integer?

- Eric
Jeff Layton July 12, 2021, 1:22 p.m. UTC | #5
On Sun, 2021-07-11 at 18:00 -0500, Eric Biggers wrote:
> On Fri, Jun 25, 2021 at 09:58:17AM -0400, Jeff Layton wrote:
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> >  fs/ceph/caps.c | 62 +++++++++++++++++++++++++++++++++++++++-----------
> >  1 file changed, 49 insertions(+), 13 deletions(-)
> > 
> > diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
> > index 038f59cc4250..1be6c5148700 100644
> > --- a/fs/ceph/caps.c
> > +++ b/fs/ceph/caps.c
> > @@ -13,6 +13,7 @@
> >  #include "super.h"
> >  #include "mds_client.h"
> >  #include "cache.h"
> > +#include "crypto.h"
> >  #include <linux/ceph/decode.h>
> >  #include <linux/ceph/messenger.h>
> >  
> > @@ -1229,15 +1230,12 @@ struct cap_msg_args {
> >  	umode_t			mode;
> >  	bool			inline_data;
> >  	bool			wake;
> > +	u32			fscrypt_auth_len;
> > +	u32			fscrypt_file_len;
> > +	u8			fscrypt_auth[sizeof(struct ceph_fscrypt_auth)]; // for context
> > +	u8			fscrypt_file[sizeof(u64)]; // for size
> >  };
> 
> The naming of these is confusing to me.  If these are the fscrypt context and
> the original file size, why aren't they called something like fscrypt_context
> and fscrypt_file_size?
> 
> Also does the file size really need to be variable-length, or could it just be a
> 64-bit integer?
> 

Fscrypt is really a kernel client-side feature. Both of these new fields
are treated as opaque by the MDS and are wholly managed by the client.

We need two fields because they are governed by different cephfs
capabilities (aka "caps"). AUTH caps for the context and FILE caps for
the size. So we have two new fields -- fscrypt_file and fscrypt_auth. 

The size could be a __le64 or something, but I think it makes sense to
allow it to be opaque as we aren't certain what other info we might want
to keep in there. We might also want to encrypt the fscrypt_file field
to cloak the true size of a file from anyone without the key.

Now, all that said, the fact that the MDS largely handles truncation
poses some special challenges for the content encryption piece. We may
ultimately end up making this more special-purpose than it is now.
diff mbox series

Patch

diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 038f59cc4250..1be6c5148700 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -13,6 +13,7 @@ 
 #include "super.h"
 #include "mds_client.h"
 #include "cache.h"
+#include "crypto.h"
 #include <linux/ceph/decode.h>
 #include <linux/ceph/messenger.h>
 
@@ -1229,15 +1230,12 @@  struct cap_msg_args {
 	umode_t			mode;
 	bool			inline_data;
 	bool			wake;
+	u32			fscrypt_auth_len;
+	u32			fscrypt_file_len;
+	u8			fscrypt_auth[sizeof(struct ceph_fscrypt_auth)]; // for context
+	u8			fscrypt_file[sizeof(u64)]; // for size
 };
 
-/*
- * cap struct size + flock buffer size + inline version + inline data size +
- * osd_epoch_barrier + oldest_flush_tid
- */
-#define CAP_MSG_SIZE (sizeof(struct ceph_mds_caps) + \
-		      4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4)
-
 /* Marshal up the cap msg to the MDS */
 static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
 {
@@ -1253,7 +1251,7 @@  static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
 	     arg->size, arg->max_size, arg->xattr_version,
 	     arg->xattr_buf ? (int)arg->xattr_buf->vec.iov_len : 0);
 
-	msg->hdr.version = cpu_to_le16(10);
+	msg->hdr.version = cpu_to_le16(12);
 	msg->hdr.tid = cpu_to_le64(arg->flush_tid);
 
 	fc = msg->front.iov_base;
@@ -1324,6 +1322,16 @@  static void encode_cap_msg(struct ceph_msg *msg, struct cap_msg_args *arg)
 
 	/* Advisory flags (version 10) */
 	ceph_encode_32(&p, arg->flags);
+
+	/* dirstats (version 11) - these are r/o on the client */
+	ceph_encode_64(&p, 0);
+	ceph_encode_64(&p, 0);
+
+	/* fscrypt_auth and fscrypt_file (version 12) */
+	ceph_encode_32(&p, arg->fscrypt_auth_len);
+	ceph_encode_copy(&p, arg->fscrypt_auth, arg->fscrypt_auth_len);
+	ceph_encode_32(&p, arg->fscrypt_file_len);
+	ceph_encode_copy(&p, arg->fscrypt_file, arg->fscrypt_file_len);
 }
 
 /*
@@ -1445,6 +1453,26 @@  static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
 		}
 	}
 	arg->flags = flags;
+	if (ci->fscrypt_auth_len &&
+	    WARN_ON_ONCE(ci->fscrypt_auth_len != sizeof(struct ceph_fscrypt_auth))) {
+		/* Don't set this if it isn't right size */
+		arg->fscrypt_auth_len = 0;
+	} else {
+		arg->fscrypt_auth_len = ci->fscrypt_auth_len;
+		memcpy(arg->fscrypt_auth, ci->fscrypt_auth,
+			min_t(size_t, ci->fscrypt_auth_len, sizeof(arg->fscrypt_auth)));
+	}
+	/* FIXME: use this to track "real" size */
+	arg->fscrypt_file_len = 0;
+}
+
+#define CAP_MSG_FIXED_FIELDS (sizeof(struct ceph_mds_caps) + \
+		      4 + 8 + 4 + 4 + 8 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + 8 + 4 + 4)
+
+static inline int cap_msg_size(struct cap_msg_args *arg)
+{
+	return CAP_MSG_FIXED_FIELDS + arg->fscrypt_auth_len +
+			arg->fscrypt_file_len;
 }
 
 /*
@@ -1457,7 +1485,7 @@  static void __send_cap(struct cap_msg_args *arg, struct ceph_inode_info *ci)
 	struct ceph_msg *msg;
 	struct inode *inode = &ci->vfs_inode;
 
-	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false);
+	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(arg), GFP_NOFS, false);
 	if (!msg) {
 		pr_err("error allocating cap msg: ino (%llx.%llx) flushing %s tid %llu, requeuing cap.\n",
 		       ceph_vinop(inode), ceph_cap_string(arg->dirty),
@@ -1483,10 +1511,6 @@  static inline int __send_flush_snap(struct inode *inode,
 	struct cap_msg_args	arg;
 	struct ceph_msg		*msg;
 
-	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, CAP_MSG_SIZE, GFP_NOFS, false);
-	if (!msg)
-		return -ENOMEM;
-
 	arg.session = session;
 	arg.ino = ceph_vino(inode).ino;
 	arg.cid = 0;
@@ -1524,6 +1548,18 @@  static inline int __send_flush_snap(struct inode *inode,
 	arg.flags = 0;
 	arg.wake = false;
 
+	/*
+	 * No fscrypt_auth changes from a capsnap. It will need
+	 * to update fscrypt_file on size changes (TODO).
+	 */
+	arg.fscrypt_auth_len = 0;
+	arg.fscrypt_file_len = 0;
+
+	msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, cap_msg_size(&arg),
+			   GFP_NOFS, false);
+	if (!msg)
+		return -ENOMEM;
+
 	encode_cap_msg(msg, &arg);
 	ceph_con_send(&arg.session->s_con, msg);
 	return 0;