[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