[PATCH 2/2] vfs_ceph: implement ACL callbacks

Yan, Zheng zyan at redhat.com
Tue Feb 16 09:15:41 UTC 2016


> On Feb 16, 2016, at 16:09, Ira Cooper <ira at wakeful.net> wrote:
> 
> 
> This code is awful in the gluster module, I've commented that we need to fix it and get rid of it.
> 
> The #defines, and the structure clearly belong in system or ceph/gluster headerfiles.
> 
> So I'm going to NAK this, unless I get strong objections.  We should discuss with the ceph community what the right thing to do is.  In this case: Copy gluster isn't it ;).

Yes, the code is ugly.

There is a module vfs_posixacl.cc , which gets acl xattr from local filesystem. How about updating that module, make it get acl xattr from vfs module below it. By this way, we don’t need to implement acl related functions in ceph vfs module.

Regards
Yan, Zheng 



> 
> Thanks,
> 
> -Ira
> 
> On Tue, Feb 16, 2016 at 3:08 AM, Ira Cooper <ira at samba.org> wrote:
> This code is awful in the gluster module, I've commented that we need to fix it and get rid of it.
> 
> The #defines, and the structure clearly belong in system or ceph/gluster headerfiles.
> 
> So I'm going to NAK this, unless I get strong objections.  We should discuss with the ceph community what the right thing to do is.  In this case: Copy gluster isn't it ;).
> 
> Thanks,
> 
> -Ira
> 
> On Tue, Feb 16, 2016 at 1:56 AM, Yan, Zheng <zyan at redhat.com> wrote:
> libcephfs will support posix ACL in jewel release. This patch adds posix
> ACL support to ceph vfs module. The code is based on corresponding code
> in gluster vfs module.
> 
> Signed-off-by: Yan, Zheng <zyan at redhat.com>
> ---
>  source3/modules/vfs_ceph.c | 516 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 516 insertions(+)
> 
> diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c
> index bbf7f32..31a9bfb 100644
> --- a/source3/modules/vfs_ceph.c
> +++ b/source3/modules/vfs_ceph.c
> @@ -1219,6 +1219,521 @@ static int cephwrap_set_offline(struct vfs_handle_struct *handle,
>         return -1;
>  }
> 
> +#if LIBCEPHFS_VERSION_CODE >= LIBCEPHFS_VERSION(10,0,2)
> +
> +/*
> +  Following ACL codes are copied from vfs_glusterfs.c
> +
> +  CEPH ACL Format (the same as posix xattr ACL format):
> +
> +  Size = 4 (header) + N * 8 (entry)
> +
> +  Offset  Size    Field (Little Endian)
> +  -------------------------------------
> +  0-3     4-byte  Version
> +
> +  4-5     2-byte  Entry-1 tag
> +  6-7     2-byte  Entry-1 perm
> +  8-11    4-byte  Entry-1 id
> +
> +  12-13   2-byte  Entry-2 tag
> +  14-15   2-byte  Entry-2 perm
> +  16-19   4-byte  Entry-2 id
> +
> +  ...
> + */
> +
> +/* header version */
> +#define CEPH_ACL_VERSION 2
> +
> +/* perm bits */
> +#define CEPH_ACL_READ    0x04
> +#define CEPH_ACL_WRITE   0x02
> +#define CEPH_ACL_EXECUTE 0x01
> +
> +/* tag values */
> +#define CEPH_ACL_USER_OBJ       0x01
> +#define CEPH_ACL_USER           0x02
> +#define CEPH_ACL_GROUP_OBJ      0x04
> +#define CEPH_ACL_GROUP          0x08
> +#define CEPH_ACL_MASK           0x10
> +#define CEPH_ACL_OTHER          0x20
> +
> +#define CEPH_ACL_UNDEFINED_ID  (-1)
> +
> +#define CEPH_ACL_HEADER_SIZE    4
> +#define CEPH_ACL_ENTRY_SIZE     8
> +
> +#define CEPH_ACL_SIZE(n)  (CEPH_ACL_HEADER_SIZE + (n * CEPH_ACL_ENTRY_SIZE))
> +
> +#define CEPH_ACL_XATTR_ACCESS  "system.posix_acl_access"
> +#define CEPH_ACL_XATTR_DEFAULT "system.posix_acl_default"
> +
> +static SMB_ACL_T mode_to_smb_acls(const struct stat *mode, TALLOC_CTX *mem_ctx)
> +{
> +       struct smb_acl_t *result;
> +       int count;
> +
> +       count = 3;
> +       result = sys_acl_init(mem_ctx);
> +       if (!result) {
> +               errno = ENOMEM;
> +               return NULL;
> +       }
> +
> +       result->acl = talloc_array(result, struct smb_acl_entry, count);
> +       if (!result->acl) {
> +               errno = ENOMEM;
> +               talloc_free(result);
> +               return NULL;
> +       }
> +
> +       result->count = count;
> +
> +       result->acl[0].a_type = SMB_ACL_USER_OBJ;
> +       result->acl[0].a_perm = (mode->st_mode & S_IRWXU) >> 6;
> +
> +       result->acl[1].a_type = SMB_ACL_GROUP_OBJ;
> +       result->acl[1].a_perm = (mode->st_mode & S_IRWXG) >> 3;
> +
> +       result->acl[2].a_type = SMB_ACL_OTHER;
> +       result->acl[2].a_perm = mode->st_mode & S_IRWXO;
> +
> +       return result;
> +}
> +
> +static SMB_ACL_T ceph_to_smb_acl(const char *buf, size_t xattr_size,
> +                                TALLOC_CTX *mem_ctx)
> +{
> +       int count;
> +       size_t size;
> +       struct smb_acl_entry *smb_ace;
> +       struct smb_acl_t *result;
> +       int i;
> +       int offset;
> +       uint16_t tag;
> +       uint16_t perm;
> +       uint32_t id;
> +
> +       size = xattr_size;
> +
> +       if (size < CEPH_ACL_HEADER_SIZE) {
> +               /* ACL should be at least as big as the header (4 bytes) */
> +               errno = EINVAL;
> +               return NULL;
> +       }
> +
> +       size -= CEPH_ACL_HEADER_SIZE; /* size of header = 4 bytes */
> +
> +       if (size % CEPH_ACL_ENTRY_SIZE) {
> +               /* Size of entries must strictly be a multiple of
> +                  size of an ACE (8 bytes)
> +               */
> +               errno = EINVAL;
> +               return NULL;
> +       }
> +
> +       count = size / CEPH_ACL_ENTRY_SIZE;
> +
> +       /* Version is the first 4 bytes of the ACL */
> +       if (IVAL(buf, 0) != CEPH_ACL_VERSION) {
> +               DEBUG(0, ("Unknown ceph ACL version: %d\n",
> +                         IVAL(buf, 0)));
> +               return NULL;
> +       }
> +       offset = CEPH_ACL_HEADER_SIZE;
> +
> +       result = sys_acl_init(mem_ctx);
> +       if (!result) {
> +               errno = ENOMEM;
> +               return NULL;
> +       }
> +
> +       result->acl = talloc_array(result, struct smb_acl_entry, count);
> +       if (!result->acl) {
> +               errno = ENOMEM;
> +               talloc_free(result);
> +               return NULL;
> +       }
> +
> +       result->count = count;
> +
> +       smb_ace = result->acl;
> +
> +       for (i = 0; i < count; i++) {
> +               /* TAG is the first 2 bytes of an entry */
> +               tag = SVAL(buf, offset);
> +               offset += 2;
> +
> +               /* PERM is the next 2 bytes of an entry */
> +               perm = SVAL(buf, offset);
> +               offset += 2;
> +
> +               /* ID is the last 4 bytes of an entry */
> +               id = IVAL(buf, offset);
> +               offset += 4;
> +
> +               switch(tag) {
> +               case CEPH_ACL_USER:
> +                       smb_ace->a_type = SMB_ACL_USER;
> +                       break;
> +               case CEPH_ACL_USER_OBJ:
> +                       smb_ace->a_type = SMB_ACL_USER_OBJ;
> +                       break;
> +               case CEPH_ACL_GROUP:
> +                       smb_ace->a_type = SMB_ACL_GROUP;
> +                       break;
> +               case CEPH_ACL_GROUP_OBJ:
> +                       smb_ace->a_type = SMB_ACL_GROUP_OBJ;
> +                       break;
> +               case CEPH_ACL_OTHER:
> +                       smb_ace->a_type = SMB_ACL_OTHER;
> +                       break;
> +               case CEPH_ACL_MASK:
> +                       smb_ace->a_type = SMB_ACL_MASK;
> +                       break;
> +               default:
> +                       DEBUG(0, ("unknown tag type %d\n", (unsigned int) tag));
> +                       return NULL;
> +               }
> +
> +
> +               switch(smb_ace->a_type) {
> +               case SMB_ACL_USER:
> +                       smb_ace->info.user.uid = id;
> +                       break;
> +               case SMB_ACL_GROUP:
> +                       smb_ace->info.group.gid = id;
> +                       break;
> +               default:
> +                       break;
> +               }
> +
> +               smb_ace->a_perm = 0;
> +               smb_ace->a_perm |=
> +                       ((perm & CEPH_ACL_READ) ? SMB_ACL_READ : 0);
> +               smb_ace->a_perm |=
> +                       ((perm & CEPH_ACL_WRITE) ? SMB_ACL_WRITE : 0);
> +               smb_ace->a_perm |=
> +                       ((perm & CEPH_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
> +
> +               smb_ace++;
> +       }
> +
> +       return result;
> +}
> +
> +
> +static int ceph_ace_cmp(const void *left, const void *right)
> +{
> +       int ret = 0;
> +       uint16_t tag_left, tag_right;
> +       uint32_t id_left, id_right;
> +
> +       /*
> +         Sorting precedence:
> +          - Smaller TAG values must be earlier.
> +          - Within same TAG, smaller identifiers must be earlier, E.g:
> +            UID 0 entry must be earlier than UID 200
> +            GID 17 entry must be earlier than GID 19
> +       */
> +
> +       /* TAG is the first element in the entry */
> +       tag_left = SVAL(left, 0);
> +       tag_right = SVAL(right, 0);
> +
> +       ret = (tag_left - tag_right);
> +       if (!ret) {
> +               /* ID is the third element in the entry, after two short
> +                  integers (tag and perm), i.e at offset 4.
> +               */
> +               id_left = IVAL(left, 4);
> +               id_right = IVAL(right, 4);
> +               ret = id_left - id_right;
> +       }
> +
> +       return ret;
> +}
> +
> +
> +static int smb_to_ceph_acl(SMB_ACL_T theacl, char *buf, size_t len)
> +{
> +       ssize_t size;
> +       struct smb_acl_entry *smb_ace;
> +       int i;
> +       int count;
> +       uint16_t tag;
> +       uint16_t perm;
> +       uint32_t id;
> +       int offset;
> +
> +       count = theacl->count;
> +
> +       size = CEPH_ACL_HEADER_SIZE + (count * CEPH_ACL_ENTRY_SIZE);
> +       if (!buf) {
> +               return size;
> +       }
> +       if (len < size) {
> +               return -ERANGE;
> +       }
> +       smb_ace = theacl->acl;
> +
> +       /* Version is the first 4 bytes of the ACL */
> +       SIVAL(buf, 0, CEPH_ACL_VERSION);
> +       offset = CEPH_ACL_HEADER_SIZE;
> +
> +       for (i = 0; i < count; i++) {
> +               /* Calculate tag */
> +               switch(smb_ace->a_type) {
> +               case SMB_ACL_USER:
> +                       tag = CEPH_ACL_USER;
> +                       break;
> +               case SMB_ACL_USER_OBJ:
> +                       tag = CEPH_ACL_USER_OBJ;
> +                       break;
> +               case SMB_ACL_GROUP:
> +                       tag = CEPH_ACL_GROUP;
> +                       break;
> +               case SMB_ACL_GROUP_OBJ:
> +                       tag = CEPH_ACL_GROUP_OBJ;
> +                       break;
> +               case SMB_ACL_OTHER:
> +                       tag = CEPH_ACL_OTHER;
> +                       break;
> +               case SMB_ACL_MASK:
> +                       tag = CEPH_ACL_MASK;
> +                       break;
> +               default:
> +                       DEBUG(0, ("Unknown tag value %d\n",
> +                                 smb_ace->a_type));
> +                       return -EINVAL;
> +               }
> +
> +
> +               /* Calculate id */
> +               switch(smb_ace->a_type) {
> +               case SMB_ACL_USER:
> +                       id = smb_ace->info.user.uid;
> +                       break;
> +               case SMB_ACL_GROUP:
> +                       id = smb_ace->info.group.gid;
> +                       break;
> +               default:
> +                       id = CEPH_ACL_UNDEFINED_ID;
> +                       break;
> +               }
> +
> +               /* Calculate perm */
> +               perm = 0;
> +               perm |= (smb_ace->a_perm & SMB_ACL_READ) ? CEPH_ACL_READ : 0;
> +               perm |= (smb_ace->a_perm & SMB_ACL_WRITE) ?
> +                                               CEPH_ACL_WRITE : 0;
> +               perm |= (smb_ace->a_perm & SMB_ACL_EXECUTE) ?
> +                                               CEPH_ACL_EXECUTE : 0;
> +
> +               /* TAG is the first 2 bytes of an entry */
> +               SSVAL(buf, offset, tag);
> +               offset += 2;
> +
> +               /* PERM is the next 2 bytes of an entry */
> +               SSVAL(buf, offset, perm);
> +               offset += 2;
> +
> +               /* ID is the last 4 bytes of an entry */
> +               SIVAL(buf, offset, id);
> +               offset += 4;
> +
> +               smb_ace++;
> +       }
> +
> +       /* Skip the header, sort @count number of 8-byte entries */
> +       qsort(buf+CEPH_ACL_HEADER_SIZE, count, CEPH_ACL_ENTRY_SIZE,
> +             ceph_ace_cmp);
> +
> +       return size;
> +}
> +
> +
> +static SMB_ACL_T cephwrap_sys_acl_get_file(struct vfs_handle_struct *handle,
> +                                          const char *path_p,
> +                                          SMB_ACL_TYPE_T acltype,
> +                                          TALLOC_CTX *mem_ctx)
> +{
> +       struct smb_acl_t *result;
> +       struct stat st;
> +       ssize_t ret, size = CEPH_ACL_SIZE(20);
> +       const char *key;
> +       char *buf;
> +
> +       switch (acltype) {
> +       case SMB_ACL_TYPE_ACCESS:
> +               key = CEPH_ACL_XATTR_ACCESS;
> +               break;
> +       case SMB_ACL_TYPE_DEFAULT:
> +               key = CEPH_ACL_XATTR_DEFAULT;
> +               break;
> +       default:
> +               errno = EINVAL;
> +               return NULL;
> +       }
> +
> +       buf = alloca(size);
> +       if (!buf) {
> +               return NULL;
> +       }
> +       ret = ceph_getxattr(handle->data, path_p, key, buf, size);
> +       if (ret == -1 && errno == ERANGE) {
> +               ret = ceph_getxattr(handle->data, path_p, key, 0, 0);
> +               if (ret > 0) {
> +                       buf = alloca(ret);
> +                       if (!buf) {
> +                               return NULL;
> +                       }
> +                       ret = ceph_getxattr(handle->data, path_p, key,
> +                                       buf, ret);
> +               }
> +       }
> +
> +       /* retrieving the ACL from the xattr has finally failed, do a
> +        * mode-to-acl mapping */
> +
> +       if (ret == -1 && errno == ENODATA) {
> +               ret = ceph_stat(handle->data, path_p, &st);
> +               if (ret == 0) {
> +                       result = mode_to_smb_acls(&st, mem_ctx);
> +                       return result;
> +               }
> +       }
> +
> +       if (ret <= 0) {
> +               return NULL;
> +       }
> +       result = ceph_to_smb_acl(buf, ret, mem_ctx);
> +       return result;
> +}
> +
> +static SMB_ACL_T cephwrap_sys_acl_get_fd(struct vfs_handle_struct *handle,
> +                                        struct files_struct *fsp,
> +                                        TALLOC_CTX *mem_ctx)
> +{
> +       struct smb_acl_t *result;
> +       struct stat st;
> +       ssize_t ret, size = CEPH_ACL_SIZE(20);
> +       char *buf;
> +
> +       buf = alloca(size);
> +       if (!buf) {
> +               return NULL;
> +       }
> +
> +       ret = __ceph_fgetxattr(handle, fsp, CEPH_ACL_XATTR_ACCESS, buf, size);
> +       if (ret == -1 && errno == ERANGE) {
> +               ret = __ceph_fgetxattr(handle, fsp, CEPH_ACL_XATTR_ACCESS,
> +                                       0, 0);
> +               if (ret > 0) {
> +                       buf = alloca(ret);
> +                       if (!buf) {
> +                               return NULL;
> +                       }
> +                       ret = __ceph_fgetxattr(handle, fsp,
> +                                               CEPH_ACL_XATTR_ACCESS,
> +                                               buf, ret);
> +               }
> +       }
> +
> +       /* retrieving the ACL from the xattr has finally failed, do a
> +        * mode-to-acl mapping */
> +
> +       if (ret == -1 && errno == ENODATA) {
> +               ret = ceph_fstat(handle->data, fsp->fh->fd, &st);
> +               if (ret == 0) {
> +                       result = mode_to_smb_acls(&st, mem_ctx);
> +                       return result;
> +               }
> +       }
> +
> +       if (ret <= 0) {
> +               return NULL;
> +       }
> +       result = ceph_to_smb_acl(buf, ret, mem_ctx);
> +       return result;
> +}
> +
> +static int cephwrap_sys_acl_set_file(struct vfs_handle_struct *handle,
> +                                    const char *name,
> +                                    SMB_ACL_TYPE_T acltype,
> +                                    SMB_ACL_T theacl)
> +{
> +       int ret;
> +       const char *key;
> +       char *buf;
> +       ssize_t size;
> +
> +       DEBUG(10, ("[CEPH] sys_acl_set_file(%p, %s)\n", handle, name));
> +
> +       switch (acltype) {
> +       case SMB_ACL_TYPE_ACCESS:
> +               key = CEPH_ACL_XATTR_ACCESS;
> +               break;
> +       case SMB_ACL_TYPE_DEFAULT:
> +               key = CEPH_ACL_XATTR_DEFAULT;
> +               break;
> +       default:
> +               ret = -EINVAL;
> +               goto out;
> +       }
> +
> +       size = smb_to_ceph_acl(theacl, 0, 0);
> +       buf = alloca(size);
> +
> +       ret = smb_to_ceph_acl(theacl, buf, size);
> +       if (ret < 0) {
> +               goto out;
> +       }
> +       size = ret;
> +       ret = ceph_setxattr(handle->data, name, key, buf, size, 0);
> +out:
> +       DEBUG(10, ("[CEPH] sys_acl_set_file(...) = %d\n", ret));
> +       WRAP_RETURN(ret);
> +}
> +
> +static int cephwrap_sys_acl_set_fd(struct vfs_handle_struct *handle,
> +                                  struct files_struct *fsp,
> +                                  SMB_ACL_T theacl)
> +{
> +       int ret;
> +       char *buf;
> +       ssize_t size;
> +
> +       DEBUG(10, ("[CEPH] sys_acl_set_fd(%p, %p)\n", handle, fsp));
> +
> +       size = smb_to_ceph_acl(theacl, 0, 0);
> +       buf = alloca(size);
> +
> +       ret = smb_to_ceph_acl(theacl, buf, size);
> +       if (ret < 0) {
> +               goto out;
> +       }
> +       size = ret;
> +       ret = __ceph_fsetxattr(handle, fsp, CEPH_ACL_XATTR_ACCESS,
> +                               buf, size, 0);
> +out:
> +       DEBUG(10, ("[CEPH] sys_acl_set_fd(...) = %d\n", ret));
> +       WRAP_RETURN(ret);
> +}
> +
> +static int cephwrap_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
> +                                           const char *path)
> +{
> +       int ret;
> +       DEBUG(10, ("[CEPH] sys_acl_delete_def_file(%p, %s)\n", handle, path));
> +       ret = ceph_removexattr(handle->data, path, CEPH_ACL_XATTR_DEFAULT);
> +       DEBUG(10, ("[CEPH] sys_acl_delete_def_file(...) = %d\n", ret));
> +       WRAP_RETURN(ret);
> +}
> +
> +#else
> +
>  static SMB_ACL_T cephwrap_sys_acl_get_file(struct vfs_handle_struct *handle,
>                                            const char *path_p,
>                                            SMB_ACL_TYPE_T type,
> @@ -1259,6 +1774,7 @@ static int cephwrap_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
>         errno = ENOTSUP;
>         return -1;
>  }
> +#endif
> 
>  static struct vfs_fn_pointers ceph_fns = {
>         /* Disk operations */
> --
> 2.5.0
> 
> 
> 
> 




More information about the samba-technical mailing list