]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
libcephfs_proxy: extend the protocol to support embedded permissions
authorXavi Hernandez <xhernandez@gmail.com>
Sat, 26 Jul 2025 18:13:38 +0000 (20:13 +0200)
committerXavi Hernandez <xhernandez@gmail.com>
Thu, 31 Jul 2025 09:14:56 +0000 (11:14 +0200)
This patch adds the changes to the protocol definition to support
sending the user credentials along with the request that requires it.

Using protocol version 1, instead of sending a pointer to a previously
allocated UserPerm structure, the caller will embed the uid, gid and the
list of additional groups in the request itself.

Signed-off-by: Xavi Hernandez <xhernandez@gmail.com>
src/libcephfs_proxy/libcephfs_proxy.c
src/libcephfs_proxy/libcephfsd.c
src/libcephfs_proxy/proxy.h
src/libcephfs_proxy/proxy_link.h
src/libcephfs_proxy/proxy_requests.h

index 907161213a83742dd58f73d04644715de9f8076a..6b898d06dee6d7b09684248b1e3b777807c67640 100644 (file)
@@ -267,7 +267,7 @@ __public int ceph_ll_create(struct ceph_mount_info *cmount, Inode *parent,
        CEPH_REQ(ceph_ll_create, req, 1, ans, 1);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(parent);
        req.v0.mode = mode;
        req.v0.oflags = oflags;
@@ -316,7 +316,7 @@ __public int ceph_ll_getattr(struct ceph_mount_info *cmount, struct Inode *in,
 {
        CEPH_REQ(ceph_ll_getattr, req, 0, ans, 1);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.want = want;
        req.v0.flags = flags;
@@ -332,7 +332,7 @@ __public int ceph_ll_getxattr(struct ceph_mount_info *cmount, struct Inode *in,
 {
        CEPH_REQ(ceph_ll_getxattr, req, 1, ans, 1);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.size = size;
        CEPH_STR_ADD(req, v0.name, name);
@@ -348,7 +348,7 @@ __public int ceph_ll_link(struct ceph_mount_info *cmount, struct Inode *in,
 {
        CEPH_REQ(ceph_ll_link, req, 1, ans, 0);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.parent = ptr_value(newparent);
        CEPH_STR_ADD(req, v0.name, name);
@@ -363,7 +363,7 @@ __public int ceph_ll_listxattr(struct ceph_mount_info *cmount, struct Inode *in,
        CEPH_REQ(ceph_ll_listxattr, req, 0, ans, 1);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.size = buf_size;
 
@@ -385,7 +385,7 @@ __public int ceph_ll_lookup(struct ceph_mount_info *cmount, Inode *parent,
        CEPH_REQ(ceph_ll_lookup, req, 1, ans, 1);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(parent);
        req.v0.want = want;
        req.v0.flags = flags;
@@ -456,7 +456,7 @@ __public int ceph_ll_mkdir(struct ceph_mount_info *cmount, Inode *parent,
        CEPH_REQ(ceph_ll_mkdir, req, 1, ans, 1);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(parent);
        req.v0.mode = mode;
        req.v0.want = want;
@@ -481,7 +481,7 @@ __public int ceph_ll_mknod(struct ceph_mount_info *cmount, Inode *parent,
        CEPH_REQ(ceph_ll_mknod, req, 1, ans, 1);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(parent);
        req.v0.mode = mode;
        req.v0.rdev = rdev;
@@ -505,7 +505,7 @@ __public int ceph_ll_open(struct ceph_mount_info *cmount, struct Inode *in,
        CEPH_REQ(ceph_ll_open, req, 0, ans, 0);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.flags = flags;
 
@@ -524,7 +524,7 @@ __public int ceph_ll_opendir(struct ceph_mount_info *cmount, struct Inode *in,
        CEPH_REQ(ceph_ll_opendir, req, 0, ans, 0);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
 
        err = CEPH_PROCESS(cmount, LIBCEPHFSD_OP_LL_OPENDIR, req, ans);
@@ -563,7 +563,7 @@ __public int ceph_ll_readlink(struct ceph_mount_info *cmount, struct Inode *in,
 {
        CEPH_REQ(ceph_ll_readlink, req, 0, ans, 1);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.size = bufsize;
 
@@ -588,7 +588,7 @@ __public int ceph_ll_removexattr(struct ceph_mount_info *cmount,
 {
        CEPH_REQ(ceph_ll_removexattr, req, 1, ans, 0);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        CEPH_STR_ADD(req, v0.name, name);
 
@@ -602,7 +602,7 @@ __public int ceph_ll_rename(struct ceph_mount_info *cmount,
 {
        CEPH_REQ(ceph_ll_rename, req, 2, ans, 0);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.old_parent = ptr_value(parent);
        req.v0.new_parent = ptr_value(newparent);
        CEPH_STR_ADD(req, v0.old_name, name);
@@ -626,7 +626,7 @@ __public int ceph_ll_rmdir(struct ceph_mount_info *cmount, struct Inode *in,
 {
        CEPH_REQ(ceph_ll_rmdir, req, 1, ans, 0);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(in);
        CEPH_STR_ADD(req, v0.name, name);
 
@@ -639,7 +639,7 @@ __public int ceph_ll_setattr(struct ceph_mount_info *cmount, struct Inode *in,
 {
        CEPH_REQ(ceph_ll_setattr, req, 1, ans, 0);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.mask = mask;
        CEPH_BUFF_ADD(req, stx, sizeof(*stx));
@@ -653,7 +653,7 @@ __public int ceph_ll_setxattr(struct ceph_mount_info *cmount, struct Inode *in,
 {
        CEPH_REQ(ceph_ll_setxattr, req, 2, ans, 0);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.inode = ptr_value(in);
        req.v0.size = size;
        req.v0.flags = flags;
@@ -683,7 +683,7 @@ __public int ceph_ll_symlink(struct ceph_mount_info *cmount, Inode *in,
        CEPH_REQ(ceph_ll_symlink, req, 2, ans, 1);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(in);
        req.v0.want = want;
        req.v0.flags = flags;
@@ -705,7 +705,7 @@ __public int ceph_ll_unlink(struct ceph_mount_info *cmount, struct Inode *in,
 {
        CEPH_REQ(ceph_ll_unlink, req, 1, ans, 0);
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.parent = ptr_value(in);
        CEPH_STR_ADD(req, v0.name, name);
 
@@ -719,7 +719,7 @@ __public int ceph_ll_walk(struct ceph_mount_info *cmount, const char *name,
        CEPH_REQ(ceph_ll_walk, req, 1, ans, 1);
        int32_t err;
 
-       req.v0.userperm = ptr_value(perms);
+       req.v0.userperm.ptr = ptr_value(perms);
        req.v0.want = want;
        req.v0.flags = flags;
        CEPH_STR_ADD(req, v0.path, name);
index cc5a538fa73dfef4e453d66f76015ee6abd3088a..46b35d44e20f24f4834f84511cd42d0fbc658546 100644 (file)
@@ -81,6 +81,29 @@ static int32_t send_error(proxy_client_t *client, int32_t error)
 #define TRACE(_fmt, _args...) do { } while (0)
 #endif
 
+static int32_t validate_perms(proxy_client_t *client, embedded_perms_t *embed,
+                             uint32_t count, const gid_t *groups,
+                             UserPerm **pperms, bool *embedded)
+{
+       UserPerm *perms;
+
+       if ((client->neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) == 0) {
+               *embedded = false;
+               return ptr_check(&client->random, embed->ptr, (void **)pperms);
+       }
+
+       perms = ceph_userperm_new(embed->uid, embed->gid, count,
+                                 (gid_t *)groups);
+       if (perms == NULL) {
+               return -ENOMEM;
+       }
+
+       *embedded = true;
+       *pperms = perms;
+
+       return 0;
+}
+
 static int32_t libcephfsd_version(proxy_client_t *client, proxy_req_t *req,
                                  const void *data, int32_t data_size)
 {
@@ -107,6 +130,10 @@ static int32_t libcephfsd_userperm_new(proxy_client_t *client, proxy_req_t *req,
        UserPerm *userperm;
        int32_t err;
 
+       if ((client->neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) {
+               return -EOPNOTSUPP;
+       }
+
        userperm = ceph_userperm_new(req->userperm_new.v0.uid,
                                     req->userperm_new.v0.gid,
                                     req->userperm_new.v0.groups,
@@ -131,6 +158,10 @@ static int32_t libcephfsd_userperm_destroy(proxy_client_t *client,
        UserPerm *perms;
        int32_t err;
 
+       if ((client->neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) {
+               return -EOPNOTSUPP;
+       }
+
        err = ptr_check(&global_random, req->userperm_destroy.v0.userperm,
                        (void **)&perms);
 
@@ -367,6 +398,12 @@ static int32_t libcephfsd_ll_lookup(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        uint32_t want, flags;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_lookup, v0.name, data);
+       data = (const char *)data + req->ll_lookup.v0.name;
 
        err = ptr_check(&client->random, req->ll_lookup.v0.cmount,
                        (void **)&mount);
@@ -375,13 +412,13 @@ static int32_t libcephfsd_ll_lookup(proxy_client_t *client, proxy_req_t *req,
                                (void **)&parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_lookup.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_lookup.v0.userperm,
+                                    req->ll_lookup.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                want = req->ll_lookup.v0.want;
                flags = req->ll_lookup.v0.flags;
-               name = CEPH_STR_GET(req->ll_lookup, v0.name, data);
 
                CEPH_BUFF_ADD(ans, &stx, sizeof(stx));
 
@@ -407,6 +444,10 @@ static int32_t libcephfsd_ll_lookup(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -499,17 +540,23 @@ static int32_t libcephfsd_ll_walk(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        uint32_t want, flags;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       path = CEPH_STR_GET(req->ll_walk, v0.path, data);
+       data = (const char *)data + req->ll_walk.v0.path;
 
        err = ptr_check(&client->random, req->ll_walk.v0.cmount,
                        (void **)&mount);
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_walk.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_walk.v0.userperm,
+                                    req->ll_walk.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                want = req->ll_walk.v0.want;
                flags = req->ll_walk.v0.flags;
-               path = CEPH_STR_GET(req->ll_walk, v0.path, data);
 
                CEPH_BUFF_ADD(ans, &stx, sizeof(stx));
 
@@ -523,6 +570,10 @@ static int32_t libcephfsd_ll_walk(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -652,6 +703,9 @@ static int32_t libcephfsd_ll_open(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        struct Fh *fh;
        int32_t flags, err;
+       bool embedded;
+
+       embedded = false;
 
        err = ptr_check(&client->random, req->ll_open.v0.cmount,
                        (void **)&mount);
@@ -660,8 +714,9 @@ static int32_t libcephfsd_ll_open(proxy_client_t *client, proxy_req_t *req,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_open.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_open.v0.userperm,
+                                    req->ll_open.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                flags = req->ll_open.v0.flags;
@@ -676,6 +731,10 @@ static int32_t libcephfsd_ll_open(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -692,6 +751,12 @@ static int32_t libcephfsd_ll_create(proxy_client_t *client, proxy_req_t *req,
        mode_t mode;
        uint32_t want, flags;
        int32_t oflags, err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_create, v0.name, data);
+       data = (const char *)data + req->ll_create.v0.name;
 
        err = ptr_check(&client->random, req->ll_create.v0.cmount,
                        (void **)&mount);
@@ -700,15 +765,15 @@ static int32_t libcephfsd_ll_create(proxy_client_t *client, proxy_req_t *req,
                                (void **)&parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_create.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_create.v0.userperm,
+                                    req->ll_create.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                mode = req->ll_create.v0.mode;
                oflags = req->ll_create.v0.oflags;
                want = req->ll_create.v0.want;
                flags = req->ll_create.v0.flags;
-               name = CEPH_STR_GET(req->ll_create, v0.name, data);
 
                CEPH_BUFF_ADD(ans, &stx, sizeof(stx));
 
@@ -726,6 +791,10 @@ static int32_t libcephfsd_ll_create(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -742,6 +811,12 @@ static int32_t libcephfsd_ll_mknod(proxy_client_t *client, proxy_req_t *req,
        mode_t mode;
        uint32_t want, flags;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_mknod, v0.name, data);
+       data = (const char *)data + req->ll_mknod.v0.name;
 
        err = ptr_check(&client->random, req->ll_mknod.v0.cmount,
                        (void **)&mount);
@@ -750,15 +825,15 @@ static int32_t libcephfsd_ll_mknod(proxy_client_t *client, proxy_req_t *req,
                                (void **)&parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_mknod.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_mknod.v0.userperm,
+                                    req->ll_mknod.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                mode = req->ll_mknod.v0.mode;
                rdev = req->ll_mknod.v0.rdev;
                want = req->ll_mknod.v0.want;
                flags = req->ll_mknod.v0.flags;
-               name = CEPH_STR_GET(req->ll_mknod, v0.name, data);
 
                CEPH_BUFF_ADD(ans, &stx, sizeof(stx));
 
@@ -774,6 +849,10 @@ static int32_t libcephfsd_ll_mknod(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -809,6 +888,14 @@ static int32_t libcephfsd_ll_rename(proxy_client_t *client, proxy_req_t *req,
        const char *old_name, *new_name;
        UserPerm *perms;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       old_name = CEPH_STR_GET(req->ll_rename, v0.old_name, data);
+       data = (const char *)data + req->ll_rename.v0.old_name;
+       new_name = CEPH_STR_GET(req->ll_rename, v0.new_name, data);
+       data = (const char *)data + req->ll_rename.v0.new_name;
 
        err = ptr_check(&client->random, req->ll_rename.v0.cmount,
                        (void **)&mount);
@@ -821,20 +908,21 @@ static int32_t libcephfsd_ll_rename(proxy_client_t *client, proxy_req_t *req,
                                (void **)&new_parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_rename.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_rename.v0.userperm,
+                                    req->ll_rename.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
-               old_name = CEPH_STR_GET(req->ll_rename, v0.old_name, data);
-               new_name = CEPH_STR_GET(req->ll_rename, v0.new_name,
-                                       (const char *)data + req->ll_rename.v0.old_name);
-
                err = ceph_ll_rename(proxy_cmount(mount), old_parent, old_name,
                                     new_parent, new_name, perms);
                TRACE("ceph_ll_rename(%p, %p, '%s', %p, '%s', %p) -> %d", mount,
                      old_parent, old_name, new_parent, new_name, perms, err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -960,6 +1048,12 @@ static int32_t libcephfsd_ll_link(proxy_client_t *client, proxy_req_t *req,
        const char *name;
        UserPerm *perms;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_link, v0.name, data);
+       data = (const char *)data + req->ll_link.v0.name;
 
        err = ptr_check(&client->random, req->ll_link.v0.cmount,
                        (void **)&mount);
@@ -972,18 +1066,21 @@ static int32_t libcephfsd_ll_link(proxy_client_t *client, proxy_req_t *req,
                                (void **)&parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_link.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_link.v0.userperm,
+                                    req->ll_link.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
-               name = CEPH_STR_GET(req->ll_link, v0.name, data);
-
                err = ceph_ll_link(proxy_cmount(mount), inode, parent, name,
                                   perms);
                TRACE("ceph_ll_link(%p, %p, %p, '%s', %p) -> %d", mount, inode,
                      parent, name, perms, err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -996,6 +1093,12 @@ static int32_t libcephfsd_ll_unlink(proxy_client_t *client, proxy_req_t *req,
        const char *name;
        UserPerm *perms;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_unlink, v0.name, data);
+       data = (const char *)data + req->ll_unlink.v0.name;
 
        err = ptr_check(&client->random, req->ll_unlink.v0.cmount,
                        (void **)&mount);
@@ -1004,17 +1107,20 @@ static int32_t libcephfsd_ll_unlink(proxy_client_t *client, proxy_req_t *req,
                                (void **)&parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_unlink.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_unlink.v0.userperm,
+                                    req->ll_unlink.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
-               name = CEPH_STR_GET(req->ll_unlink, v0.name, data);
-
                err = ceph_ll_unlink(proxy_cmount(mount), parent, name, perms);
                TRACE("ceph_ll_unlink(%p, %p, '%s', %p) -> %d", mount, parent,
                      name, perms, err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1028,6 +1134,9 @@ static int32_t libcephfsd_ll_getattr(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        uint32_t want, flags;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
 
        err = ptr_check(&client->random, req->ll_getattr.v0.cmount,
                        (void **)&mount);
@@ -1036,8 +1145,9 @@ static int32_t libcephfsd_ll_getattr(proxy_client_t *client, proxy_req_t *req,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_getattr.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_getattr.v0.userperm,
+                                    req->ll_getattr.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                want = req->ll_getattr.v0.want;
@@ -1051,6 +1161,10 @@ static int32_t libcephfsd_ll_getattr(proxy_client_t *client, proxy_req_t *req,
                      want, flags, perms, err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1062,6 +1176,9 @@ static int32_t libcephfsd_ll_setattr(proxy_client_t *client, proxy_req_t *req,
        struct Inode *inode;
        UserPerm *perms;
        int32_t mask, err;
+       bool embedded;
+
+       embedded = false;
 
        err = ptr_check(&client->random, req->ll_setattr.v0.cmount,
                        (void **)&mount);
@@ -1070,8 +1187,9 @@ static int32_t libcephfsd_ll_setattr(proxy_client_t *client, proxy_req_t *req,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_setattr.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_setattr.v0.userperm,
+                                    req->ll_setattr.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                mask = req->ll_setattr.v0.mask;
@@ -1082,6 +1200,10 @@ static int32_t libcephfsd_ll_setattr(proxy_client_t *client, proxy_req_t *req,
                      mask, perms, err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1149,6 +1271,9 @@ static int32_t libcephfsd_ll_listxattr(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        size_t size;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
 
        err = ptr_check(&client->random, req->ll_listxattr.v0.cmount,
                        (void **)&mount);
@@ -1157,8 +1282,9 @@ static int32_t libcephfsd_ll_listxattr(proxy_client_t *client, proxy_req_t *req,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_listxattr.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_listxattr.v0.userperm,
+                                    req->ll_listxattr.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                size = req->ll_listxattr.v0.size;
@@ -1176,6 +1302,10 @@ static int32_t libcephfsd_ll_listxattr(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1189,6 +1319,12 @@ static int32_t libcephfsd_ll_getxattr(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        size_t size;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_getxattr, v0.name, data);
+       data = (const char *)data + req->ll_getxattr.v0.name;
 
        err = ptr_check(&client->random, req->ll_getxattr.v0.cmount,
                        (void **)&mount);
@@ -1197,12 +1333,12 @@ static int32_t libcephfsd_ll_getxattr(proxy_client_t *client, proxy_req_t *req,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_getxattr.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_getxattr.v0.userperm,
+                                    req->ll_getxattr.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                size = req->ll_getxattr.v0.size;
-               name = CEPH_STR_GET(req->ll_getxattr, v0.name, data);
 
                if (size > client->buffer_size) {
                        size = client->buffer_size;
@@ -1217,6 +1353,10 @@ static int32_t libcephfsd_ll_getxattr(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1230,6 +1370,15 @@ static int32_t libcephfsd_ll_setxattr(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        size_t size;
        int32_t flags, err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_setxattr, v0.name, data);
+       data = (const char *)data + req->ll_setxattr.v0.name;
+       value = data;
+       size = req->ll_setxattr.v0.size;
+       data = (const char *)data + size;
 
        err = ptr_check(&client->random, req->ll_setxattr.v0.cmount,
                        (void **)&mount);
@@ -1238,13 +1387,11 @@ static int32_t libcephfsd_ll_setxattr(proxy_client_t *client, proxy_req_t *req,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_setxattr.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_setxattr.v0.userperm,
+                                    req->ll_setxattr.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
-               name = CEPH_STR_GET(req->ll_setxattr, v0.name, data);
-               value = (const char *)data + req->ll_setxattr.v0.name;
-               size = req->ll_setxattr.v0.size;
                flags = req->ll_setxattr.v0.flags;
 
                err = ceph_ll_setxattr(proxy_cmount(mount), inode, name, value,
@@ -1253,6 +1400,10 @@ static int32_t libcephfsd_ll_setxattr(proxy_client_t *client, proxy_req_t *req,
                      inode, name, value, flags, perms, err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1266,6 +1417,12 @@ static int32_t libcephfsd_ll_removexattr(proxy_client_t *client,
        const char *name;
        UserPerm *perms;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_removexattr, v0.name, data);
+       data = (const char *)data + req->ll_removexattr.v0.name;
 
        err = ptr_check(&client->random, req->ll_removexattr.v0.cmount,
                        (void **)&mount);
@@ -1274,18 +1431,21 @@ static int32_t libcephfsd_ll_removexattr(proxy_client_t *client,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_removexattr.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_removexattr.v0.userperm,
+                                    req->ll_removexattr.v1.ngroups, data,
+                                    &perms, &embedded);
        }
        if (err >= 0) {
-               name = CEPH_STR_GET(req->ll_removexattr, v0.name, data);
-
                err = ceph_ll_removexattr(proxy_cmount(mount), inode, name,
                                          perms);
                TRACE("ceph_ll_removexattr(%p, %p, '%s', %p) -> %d", mount,
                      inode, name, perms, err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1298,6 +1458,9 @@ static int32_t libcephfsd_ll_readlink(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        size_t size;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
 
        err = ptr_check(&client->random, req->ll_readlink.v0.cmount,
                        (void **)&mount);
@@ -1306,8 +1469,9 @@ static int32_t libcephfsd_ll_readlink(proxy_client_t *client, proxy_req_t *req,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_readlink.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_readlink.v0.userperm,
+                                    req->ll_readlink.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                size = req->ll_readlink.v0.size;
@@ -1321,6 +1485,10 @@ static int32_t libcephfsd_ll_readlink(proxy_client_t *client, proxy_req_t *req,
                      err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1335,6 +1503,14 @@ static int32_t libcephfsd_ll_symlink(proxy_client_t *client, proxy_req_t *req,
        const char *name, *value;
        uint32_t want, flags;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_symlink, v0.name, data);
+       data = (const char *)data + req->ll_symlink.v0.name;
+       value = CEPH_STR_GET(req->ll_symlink, v0.target, data);
+       data = (const char *)data + req->ll_symlink.v0.target;
 
        err = ptr_check(&client->random, req->ll_symlink.v0.cmount,
                        (void **)&mount);
@@ -1343,13 +1519,11 @@ static int32_t libcephfsd_ll_symlink(proxy_client_t *client, proxy_req_t *req,
                                (void **)&parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_symlink.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_symlink.v0.userperm,
+                                    req->ll_symlink.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
-               name = CEPH_STR_GET(req->ll_symlink, v0.name, data);
-               value = CEPH_STR_GET(req->ll_symlink, v0.target,
-                                    (const char *)data + req->ll_symlink.v0.name);
                want = req->ll_symlink.v0.want;
                flags = req->ll_symlink.v0.flags;
 
@@ -1367,6 +1541,10 @@ static int32_t libcephfsd_ll_symlink(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1379,6 +1557,9 @@ static int32_t libcephfsd_ll_opendir(proxy_client_t *client, proxy_req_t *req,
        struct ceph_dir_result *dirp;
        UserPerm *perms;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
 
        err = ptr_check(&client->random, req->ll_opendir.v0.cmount,
                        (void **)&mount);
@@ -1387,8 +1568,9 @@ static int32_t libcephfsd_ll_opendir(proxy_client_t *client, proxy_req_t *req,
                                (void **)&inode);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_opendir.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_opendir.v0.userperm,
+                                    req->ll_opendir.v1.ngroups, data, &perms,
+                                    &embedded);
        }
 
        if (err >= 0) {
@@ -1401,6 +1583,10 @@ static int32_t libcephfsd_ll_opendir(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1416,6 +1602,12 @@ static int32_t libcephfsd_ll_mkdir(proxy_client_t *client, proxy_req_t *req,
        mode_t mode;
        uint32_t want, flags;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_mkdir, v0.name, data);
+       data = (const char *)data + req->ll_mkdir.v0.name;
 
        err = ptr_check(&client->random, req->ll_mkdir.v0.cmount, (void **)&mount);
        if (err >= 0) {
@@ -1423,14 +1615,14 @@ static int32_t libcephfsd_ll_mkdir(proxy_client_t *client, proxy_req_t *req,
                                (void **)&parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_mkdir.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_mkdir.v0.userperm,
+                                    req->ll_mkdir.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
                mode = req->ll_mkdir.v0.mode;
                want = req->ll_mkdir.v0.want;
                flags = req->ll_mkdir.v0.flags;
-               name = CEPH_STR_GET(req->ll_mkdir, v0.name, data);
 
                CEPH_BUFF_ADD(ans, &stx, sizeof(stx));
 
@@ -1445,6 +1637,10 @@ static int32_t libcephfsd_ll_mkdir(proxy_client_t *client, proxy_req_t *req,
                }
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1457,6 +1653,12 @@ static int32_t libcephfsd_ll_rmdir(proxy_client_t *client, proxy_req_t *req,
        const char *name;
        UserPerm *perms;
        int32_t err;
+       bool embedded;
+
+       embedded = false;
+
+       name = CEPH_STR_GET(req->ll_rmdir, v0.name, data);
+       data = (const char *)data + req->ll_rmdir.v0.name;
 
        err = ptr_check(&client->random, req->ll_rmdir.v0.cmount,
                        (void **)&mount);
@@ -1465,17 +1667,20 @@ static int32_t libcephfsd_ll_rmdir(proxy_client_t *client, proxy_req_t *req,
                                (void **)&parent);
        }
        if (err >= 0) {
-               err = ptr_check(&global_random, req->ll_rmdir.v0.userperm,
-                               (void **)&perms);
+               err = validate_perms(client, &req->ll_rmdir.v0.userperm,
+                                    req->ll_rmdir.v1.ngroups, data, &perms,
+                                    &embedded);
        }
        if (err >= 0) {
-               name = CEPH_STR_GET(req->ll_rmdir, v0.name, data);
-
                err = ceph_ll_rmdir(proxy_cmount(mount), parent, name, perms);
                TRACE("ceph_ll_rmdir(%p, %p, '%s', %p) -> %d", mount, parent,
                      name, perms, err);
        }
 
+       if (embedded) {
+               ceph_userperm_destroy(perms);
+       }
+
        return CEPH_COMPLETE(client, err, ans);
 }
 
@@ -1511,6 +1716,10 @@ static int32_t libcephfsd_mount_perms(proxy_client_t *client, proxy_req_t *req,
        UserPerm *perms;
        int32_t err;
 
+       if ((client->neg.v1.enabled & PROXY_FEAT_EMBEDDED_PERMS) != 0) {
+               return -EOPNOTSUPP;
+       }
+
        err = ptr_check(&client->random, req->mount_perms.v0.cmount,
                        (void **)&mount);
        if (err >= 0) {
index 8b2ea8abfcf5af1ae951da3b7081e4d3454bddd9..6cbfe2a98b9c6b6faad185427eb377f6a14768a3 100644 (file)
@@ -20,6 +20,8 @@
 #define PROXY_SOCKET "/run/libcephfsd.sock"
 #define PROXY_SOCKET_ENV "LIBCEPHFSD_SOCKET"
 
+#define field_size(_type, _field) sizeof(((_type *)0)->_field)
+
 #define offset_of(_type, _field) ((uintptr_t) & ((_type *)0)->_field)
 
 #define container_of(_ptr, _type, _field) \
@@ -29,11 +31,15 @@ enum {
        /* Support for ceph_ll_nonblocking_readv_writev */
        PROXY_FEAT_ASYNC_IO = 0x00000001,
 
+       /* Support for embedding the user credentials inside the request itself
+        * instead of using ceph_userperm_new/ceph_userperm_destroy */
+       PROXY_FEAT_EMBEDDED_PERMS = 0x00000002,
+
        /* Mask of all features requiring the asynchronous callback handling. */
        PROXY_FEAT_ASYNC_CBK = 0x00000001,
 
        /* Mask of all supported/known features. */
-       PROXY_FEAT_ALL = 0x00000001
+       PROXY_FEAT_ALL = 0x00000003
 };
 
 struct _list;
index ec7dbc2ecdab0652c49f4bbe305eeb9a61dcb964..2dd851c7f1577e38a9776896bb2949b7434c452d 100644 (file)
 
 /* Known versions for communication protocol. */
 #define PROXY_PROTOCOL_V0 0
+#define PROXY_PROTOCOL_V1 1
 
 /* The maximum supported protocol version. */
-#define PROXY_LINK_PROTOCOL_VERSION PROXY_PROTOCOL_V0
+#define PROXY_LINK_PROTOCOL_VERSION PROXY_PROTOCOL_V1
 
 /* Version 0 structure will be used to handle legacy clients that don't support
  * negotiation. */
index 293af4202c3558ebcefab93b6cfcc97b3ba7d865..44238f81b65f6f7a9f4fa30967bae3696a5fd154 100644 (file)
                __ptr;                      \
        })
 
-#define CEPH_DATA(_name, _data, _data_count)       \
-       proxy_##_name##_##_data##_t _data;         \
+#define PROTO_VERSION_SIZE_EXPAND(_data, _ver) \
+       (offset_of(__typeof__(_data), v##_ver) + \
+        field_size(__typeof__(_data), v##_ver))
+
+#define PROTO_VERSION_SIZE(_data, _ver) PROTO_VERSION_SIZE_EXPAND(_data, _ver)
+
+#define PROTO_VERSION(_neg, _data, _ver) \
+       do { \
+               if ((_neg)->v2.protocol >= (_ver)) { \
+                       _data##_iov[0].iov_len = PROTO_VERSION_SIZE(_data, \
+                                                                   _ver); \
+               } \
+       } while (false)
+
+#define CEPH_DATA(_name, _data, _data_count)         \
+       proxy_##_name##_##_data##_t _data;           \
        struct iovec _data##_iov[(_data_count) + 1]; \
-       int32_t _data##_count = 0;                 \
-       CEPH_BUFF_ADD(_data, &_data, sizeof(_data))
+       int32_t _data##_count = 0;                   \
+       CEPH_BUFF_ADD(_data, &_data,                 \
+                     PROTO_VERSION_SIZE(_data, PROXY_PROTOCOL_V0))
 
 #define CEPH_REQ(_name, _req, _req_count, _ans, _ans_count) \
        CEPH_DATA(_name, _req, _req_count);                 \
@@ -127,6 +142,14 @@ enum {
        LIBCEPHFSD_CBK_TOTAL_OPS
 };
 
+typedef union {
+       uint64_t ptr;
+       struct {
+               uint32_t uid;
+               uint32_t gid;
+       };
+} embedded_perms_t;
+
 #define PROTO_REQ(_fields...) _fields
 #define PROTO_ANS(_fields...) _fields
 #define PROTO_CBK(_fields...) _fields
@@ -320,12 +343,15 @@ PROTO_CALL(ceph_ll_lookup,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t parent;
                        uint32_t want;
                        uint32_t flags;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -378,11 +404,14 @@ PROTO_CALL(ceph_ll_walk,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint32_t want;
                        uint32_t flags;
                        uint16_t path;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -448,10 +477,13 @@ PROTO_CALL(ceph_ll_open,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        int32_t flags;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -464,7 +496,7 @@ PROTO_CALL(ceph_ll_create,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t parent;
                        mode_t mode;
                        int32_t oflags;
@@ -472,6 +504,9 @@ PROTO_CALL(ceph_ll_create,
                        uint32_t flags;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -485,7 +520,7 @@ PROTO_CALL(ceph_ll_mknod,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t parent;
                        mode_t mode;
                        dev_t rdev;
@@ -493,6 +528,9 @@ PROTO_CALL(ceph_ll_mknod,
                        uint32_t flags;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -518,12 +556,15 @@ PROTO_CALL(ceph_ll_rename,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t old_parent;
                        uint64_t new_parent;
                        uint16_t old_name;
                        uint16_t new_name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -581,11 +622,14 @@ PROTO_CALL(ceph_ll_link,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        uint64_t parent;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -597,10 +641,13 @@ PROTO_CALL(ceph_ll_unlink,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t parent;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -612,11 +659,14 @@ PROTO_CALL(ceph_ll_getattr,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        uint32_t want;
                        uint32_t flags;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -628,10 +678,13 @@ PROTO_CALL(ceph_ll_setattr,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        int32_t mask;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -673,10 +726,13 @@ PROTO_CALL(ceph_ll_listxattr,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        size_t size;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -689,11 +745,14 @@ PROTO_CALL(ceph_ll_getxattr,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        size_t size;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -705,12 +764,15 @@ PROTO_CALL(ceph_ll_setxattr,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        size_t size;
                        int32_t flags;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -722,10 +784,13 @@ PROTO_CALL(ceph_ll_removexattr,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -737,10 +802,13 @@ PROTO_CALL(ceph_ll_readlink,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                        size_t size;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -752,13 +820,16 @@ PROTO_CALL(ceph_ll_symlink,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t parent;
                        uint32_t want;
                        uint32_t flags;
                        uint16_t name;
                        uint16_t target;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -771,9 +842,12 @@ PROTO_CALL(ceph_ll_opendir,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t inode;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -786,13 +860,16 @@ PROTO_CALL(ceph_ll_mkdir,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t parent;
                        mode_t mode;
                        uint32_t want;
                        uint32_t flags;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,
@@ -805,10 +882,13 @@ PROTO_CALL(ceph_ll_rmdir,
        PROTO_REQ(
                PROTO_VER(v0,
                        uint64_t cmount;
-                       uint64_t userperm;
+                       embedded_perms_t userperm;
                        uint64_t parent;
                        uint16_t name;
                );
+               PROTO_VER(v1,
+                       uint32_t ngroups;
+               );
        ),
        PROTO_ANS(
                PROTO_VER(v0,