[PATCH 2/2] vfs_ceph: implement ACL callbacks

Ira Cooper ira at wakeful.net
Tue Feb 16 08:09:35 UTC 2016


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 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