]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
ceph: send altname in MClientRequest
authorJeff Layton <jlayton@kernel.org>
Thu, 14 Jan 2021 15:39:22 +0000 (10:39 -0500)
committerJeff Layton <jlayton@kernel.org>
Tue, 31 May 2022 15:49:59 +0000 (11:49 -0400)
In the event that we have a filename longer than CEPH_NOHASH_NAME_MAX,
we'll need to hash the tail of the filename. The client however will
still need to know the full name of the file if it has a key.

To support this, the MClientRequest field has grown a new alternate_name
field that we populate with the full (binary) crypttext of the filename.
This is then transmitted to the clients in readdir or traces as part of
the dentry lease.

Add support for populating this field when the filenames are very long.

Reviewed-by: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
fs/ceph/mds_client.c
fs/ceph/mds_client.h

index 226af10fd1c6497e08b8ea10e39a81eb8ae0cbf9..1711c85317fbc43d261f074e980bd966491fccab 100644 (file)
@@ -1045,6 +1045,7 @@ void ceph_mdsc_release_request(struct kref *kref)
        if (req->r_pagelist)
                ceph_pagelist_release(req->r_pagelist);
        kfree(req->r_fscrypt_auth);
+       kfree(req->r_altname);
        put_request_session(req);
        ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation);
        WARN_ON_ONCE(!list_empty(&req->r_wait));
@@ -2463,6 +2464,63 @@ static inline  u64 __get_oldest_tid(struct ceph_mds_client *mdsc)
        return mdsc->oldest_tid;
 }
 
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen)
+{
+       struct inode *dir = req->r_parent;
+       struct dentry *dentry = req->r_dentry;
+       u8 *cryptbuf = NULL;
+       u32 len = 0;
+       int ret = 0;
+
+       /* only encode if we have parent and dentry */
+       if (!dir || !dentry)
+               goto success;
+
+       /* No-op unless this is encrypted */
+       if (!IS_ENCRYPTED(dir))
+               goto success;
+
+       ret = __fscrypt_prepare_readdir(dir);
+       if (ret)
+               return ERR_PTR(ret);
+
+       /* No key? Just ignore it. */
+       if (!fscrypt_has_encryption_key(dir))
+               goto success;
+
+       if (!fscrypt_fname_encrypted_size(dir, dentry->d_name.len, NAME_MAX, &len)) {
+               WARN_ON_ONCE(1);
+               return ERR_PTR(-ENAMETOOLONG);
+       }
+
+       /* No need to append altname if name is short enough */
+       if (len <= CEPH_NOHASH_NAME_MAX) {
+               len = 0;
+               goto success;
+       }
+
+       cryptbuf = kmalloc(len, GFP_KERNEL);
+       if (!cryptbuf)
+               return ERR_PTR(-ENOMEM);
+
+       ret = fscrypt_fname_encrypt(dir, &dentry->d_name, cryptbuf, len);
+       if (ret) {
+               kfree(cryptbuf);
+               return ERR_PTR(ret);
+       }
+success:
+       *plen = len;
+       return cryptbuf;
+}
+#else
+static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen)
+{
+       *plen = 0;
+       return NULL;
+}
+#endif
+
 /**
  * ceph_mdsc_build_path - build a path string to a given dentry
  * @dentry: dentry to which path should be built
@@ -2683,14 +2741,15 @@ static void encode_mclientrequest_tail(void **p, const struct ceph_mds_request *
        ceph_encode_timespec64(&ts, &req->r_stamp);
        ceph_encode_copy(p, &ts, sizeof(ts));
 
-       /* gid_list */
+       /* v4: 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]));
 
-       /* v5: altname (TODO: skip for now) */
-       ceph_encode_32(p, 0);
+       /* v5: altname */
+       ceph_encode_32(p, req->r_altname_len);
+       ceph_encode_copy(p, req->r_altname, req->r_altname_len);
 
        /* v6: fscrypt_auth and fscrypt_file */
        if (req->r_fscrypt_auth) {
@@ -2746,7 +2805,13 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
                goto out_free1;
        }
 
-       /* head */
+       req->r_altname = get_fscrypt_altname(req, &req->r_altname_len);
+       if (IS_ERR(req->r_altname)) {
+               msg = ERR_CAST(req->r_altname);
+               req->r_altname = NULL;
+               goto out_free2;
+       }
+
        len = legacy ? sizeof(*head) : sizeof(struct ceph_mds_request_head);
 
        /* filepaths */
@@ -2772,7 +2837,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_session *session,
        len += sizeof(u32) + (sizeof(u64) * req->r_cred->group_info->ngroups);
 
        /* alternate name */
-       len += sizeof(u32);     // TODO
+       len += sizeof(u32) + req->r_altname_len;
 
        /* fscrypt_auth */
        len += sizeof(u32); // fscrypt_auth
index 46e33320a70d7db1ce055f0922e4d9fc52639802..57e6fc7d00e141116326f97495ced58c7fe324ed 100644 (file)
@@ -288,6 +288,9 @@ struct ceph_mds_request {
 
        struct ceph_fscrypt_auth *r_fscrypt_auth;
 
+       u8 *r_altname;              /* fscrypt binary crypttext for long filenames */
+       u32 r_altname_len;          /* length of r_altname */
+
        int r_fmode;        /* file mode, if expecting cap */
        int r_request_release_offset;
        const struct cred *r_cred;