From: Boaz Harrosh <boazh@xxxxxxxxxx> We establish the usual dispatch to user-mode. For get and set. Since the buffers are variable length we utilize the zdo->overflow_handler for the extra copy from Server. (see also zuf-core.c) Signed-off-by: Boaz Harrosh <boazh@xxxxxxxxxx> --- fs/zuf/Makefile | 1 + fs/zuf/_extern.h | 10 ++ fs/zuf/_pr.h | 1 + fs/zuf/file.c | 1 + fs/zuf/inode.c | 3 +- fs/zuf/namei.c | 2 + fs/zuf/super.c | 1 + fs/zuf/symlink.c | 1 + fs/zuf/xattr.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++ fs/zuf/zuf-core.c | 3 + fs/zuf/zuf.h | 7 ++ fs/zuf/zus_api.h | 22 ++++ 12 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 fs/zuf/xattr.c diff --git a/fs/zuf/Makefile b/fs/zuf/Makefile index 5304aba901b2..5d638760a82f 100644 --- a/fs/zuf/Makefile +++ b/fs/zuf/Makefile @@ -17,6 +17,7 @@ zuf-y += md.o t1.o t2.o zuf-y += zuf-core.o zuf-root.o # Main FS +zuf-y += xattr.o zuf-y += rw.o mmap.o ioctl.o zuf-y += super.o inode.o directory.o namei.o file.o symlink.o zuf-y += module.o diff --git a/fs/zuf/_extern.h b/fs/zuf/_extern.h index b8e24c6a66d9..1f4b39911a5d 100644 --- a/fs/zuf/_extern.h +++ b/fs/zuf/_extern.h @@ -73,6 +73,16 @@ int zuf_iom_execute_async(struct super_block *sb, struct zus_iomap_build *iomb, /* file.c */ int zuf_isync(struct inode *inode, loff_t start, loff_t end, int datasync); +/* xattr.c */ +int zuf_initxattrs(struct inode *inode, const struct xattr *xattr_array, + void *fs_info); +ssize_t __zuf_getxattr(struct inode *inode, int type, const char *name, + void *buffer, size_t size); +int __zuf_setxattr(struct inode *inode, int type, const char *name, + const void *value, size_t size, int flags); +ssize_t zuf_listxattr(struct dentry *dentry, char *buffer, size_t size); +extern const struct xattr_handler *zuf_xattr_handlers[]; + /* super.c */ int zuf_init_inodecache(void); diff --git a/fs/zuf/_pr.h b/fs/zuf/_pr.h index a1ceab2abce2..04b99f57f2b5 100644 --- a/fs/zuf/_pr.h +++ b/fs/zuf/_pr.h @@ -42,6 +42,7 @@ #define zuf_dbg_vfs(s, args ...) zuf_chan_debug("vfs ", s, ##args) #define zuf_dbg_rw(s, args ...) zuf_chan_debug("rw ", s, ##args) #define zuf_dbg_t1(s, args ...) zuf_chan_debug("t1 ", s, ##args) +#define zuf_dbg_xattr(s, args ...) zuf_chan_debug("xattr", s, ##args) #define zuf_dbg_t2(s, args ...) zuf_chan_debug("t2dbg", s, ##args) #define zuf_dbg_t2_rw(s, args ...) zuf_chan_debug("t2grw", s, ##args) #define zuf_dbg_core(s, args ...) zuf_chan_debug("core ", s, ##args) diff --git a/fs/zuf/file.c b/fs/zuf/file.c index 48b339cb5f8f..814a75105321 100644 --- a/fs/zuf/file.c +++ b/fs/zuf/file.c @@ -521,4 +521,5 @@ const struct inode_operations zuf_file_inode_operations = { .getattr = zuf_getattr, .update_time = zuf_update_time, .fiemap = tozu_fiemap, + .listxattr = zuf_listxattr, }; diff --git a/fs/zuf/inode.c b/fs/zuf/inode.c index 8f9b4f28c556..73f94e7062e5 100644 --- a/fs/zuf/inode.c +++ b/fs/zuf/inode.c @@ -361,7 +361,8 @@ struct inode *zuf_new_inode(struct inode *dir, umode_t mode, zuf_dbg_verbose("inode=%p name=%s\n", inode, qstr->name); - err = security_inode_init_security(inode, dir, qstr, NULL, NULL); + err = security_inode_init_security(inode, dir, qstr, zuf_initxattrs, + NULL); if (err && err != -EOPNOTSUPP) goto fail; diff --git a/fs/zuf/namei.c b/fs/zuf/namei.c index e78aa04f10d5..803069423674 100644 --- a/fs/zuf/namei.c +++ b/fs/zuf/namei.c @@ -420,10 +420,12 @@ const struct inode_operations zuf_dir_inode_operations = { .setattr = zuf_setattr, .getattr = zuf_getattr, .update_time = zuf_update_time, + .listxattr = zuf_listxattr, }; const struct inode_operations zuf_special_inode_operations = { .setattr = zuf_setattr, .getattr = zuf_getattr, .update_time = zuf_update_time, + .listxattr = zuf_listxattr, }; diff --git a/fs/zuf/super.c b/fs/zuf/super.c index 2f1dd44290a2..588558066333 100644 --- a/fs/zuf/super.c +++ b/fs/zuf/super.c @@ -414,6 +414,7 @@ static int zuf_fill_super(struct super_block *sb, void *data, int silent) sb->s_flags |= MS_NOSEC | (ioc_mount->zmi.acl_on ? SB_POSIXACL : 0); sb->s_op = &zuf_sops; + sb->s_xattr = zuf_xattr_handlers; root_i = zuf_iget(sb, ioc_mount->zmi.zus_ii, ioc_mount->zmi._zi, &exist); diff --git a/fs/zuf/symlink.c b/fs/zuf/symlink.c index 1446bdf60cb9..5e9115ba4cbd 100644 --- a/fs/zuf/symlink.c +++ b/fs/zuf/symlink.c @@ -70,4 +70,5 @@ const struct inode_operations zuf_symlink_inode_operations = { .update_time = zuf_update_time, .setattr = zuf_setattr, .getattr = zuf_getattr, + .listxattr = zuf_listxattr, }; diff --git a/fs/zuf/xattr.c b/fs/zuf/xattr.c new file mode 100644 index 000000000000..6aae297c09e3 --- /dev/null +++ b/fs/zuf/xattr.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Extended Attributes + * + * Copyright (c) 2018 NetApp Inc. All rights reserved. + * + * ZUFS-License: GPL-2.0. See module.c for LICENSE details. + * + * Authors: + * Boaz Harrosh <boazh@xxxxxxxxxx> + */ + +#include <linux/fs.h> +#include <linux/posix_acl_xattr.h> +#include <linux/xattr.h> + +#include "zuf.h" + +/* ~~~~~~~~~~~~~~~ xattr get ~~~~~~~~~~~~~~~ */ + +struct _xxxattr { + void *user_buffer; + union { + struct zufs_ioc_xattr ioc_xattr; + char buf[512]; + } d; +}; + +static inline uint _XXXATTR_SIZE(uint ioc_size) +{ + struct _xxxattr *_xxxattr; + + return ioc_size + (sizeof(*_xxxattr) - sizeof(_xxxattr->d)); +} + +static int _xattr_oh(struct zuf_dispatch_op *zdo, void *parg, ulong max_bytes) +{ + struct zufs_ioc_hdr *hdr = zdo->hdr; + struct zufs_ioc_xattr *ioc_xattr = + container_of(hdr, typeof(*ioc_xattr), hdr); + struct _xxxattr *_xxattr = + container_of(ioc_xattr, typeof(*_xxattr), d.ioc_xattr); + struct zufs_ioc_xattr *user_ioc_xattr = parg; + + if (hdr->err) + return 0; + + ioc_xattr->user_buf_size = user_ioc_xattr->user_buf_size; + + hdr->out_len -= sizeof(ioc_xattr->user_buf_size); + memcpy(_xxattr->user_buffer, user_ioc_xattr->buf, hdr->out_len); + return 0; +} + +ssize_t __zuf_getxattr(struct inode *inode, int type, const char *name, + void *buffer, size_t size) +{ + size_t name_len = strlen(name) + 1; /* plus \NUL */ + struct _xxxattr *p_xattr; + struct _xxxattr s_xattr; + enum big_alloc_type bat; + struct zufs_ioc_xattr *ioc_xattr; + size_t ioc_size = sizeof(*ioc_xattr) + name_len; + struct zuf_dispatch_op zdo; + int err; + ssize_t ret; + + zuf_dbg_vfs("[%ld] type=%d name=%s size=%lu ioc_size=%lu\n", + inode->i_ino, type, name, size, ioc_size); + + p_xattr = big_alloc(_XXXATTR_SIZE(ioc_size), sizeof(s_xattr), &s_xattr, + GFP_KERNEL, &bat); + if (unlikely(!p_xattr)) + return -ENOMEM; + + ioc_xattr = &p_xattr->d.ioc_xattr; + memset(ioc_xattr, 0, sizeof(*ioc_xattr)); + p_xattr->user_buffer = buffer; + + ioc_xattr->hdr.in_len = ioc_size; + ioc_xattr->hdr.out_start = + offsetof(struct zufs_ioc_xattr, user_buf_size); + /* out_len updated by zus */ + ioc_xattr->hdr.out_len = sizeof(ioc_xattr->user_buf_size); + ioc_xattr->hdr.out_max = 0; + ioc_xattr->hdr.operation = ZUFS_OP_XATTR_GET; + ioc_xattr->zus_ii = ZUII(inode)->zus_ii; + ioc_xattr->type = type; + ioc_xattr->name_len = name_len; + ioc_xattr->user_buf_size = size; + + strcpy(ioc_xattr->buf, name); + + zuf_dispatch_init(&zdo, &ioc_xattr->hdr, NULL, 0); + zdo.oh = _xattr_oh; + err = __zufc_dispatch(ZUF_ROOT(SBI(inode->i_sb)), &zdo); + ret = ioc_xattr->user_buf_size; + + big_free(p_xattr, bat); + + if (unlikely(err)) + return err; + + return ret; +} + +/* ~~~~~~~~~~~~~~~ xattr set ~~~~~~~~~~~~~~~ */ + +int __zuf_setxattr(struct inode *inode, int type, const char *name, + const void *value, size_t size, int flags) +{ + size_t name_len = strlen(name) + 1; + struct _xxxattr *p_xattr; + struct _xxxattr s_xattr; + enum big_alloc_type bat; + struct zufs_ioc_xattr *ioc_xattr; + size_t ioc_size = sizeof(*ioc_xattr) + name_len + size; + int err; + + zuf_dbg_vfs("[%ld] type=%d name=%s size=%lu ioc_size=%lu\n", + inode->i_ino, type, name, size, ioc_size); + + p_xattr = big_alloc(_XXXATTR_SIZE(ioc_size), sizeof(s_xattr), &s_xattr, + GFP_KERNEL, &bat); + if (unlikely(!p_xattr)) + return -ENOMEM; + + ioc_xattr = &p_xattr->d.ioc_xattr; + memset(ioc_xattr, 0, sizeof(*ioc_xattr)); + + ioc_xattr->hdr.in_len = ioc_size; + ioc_xattr->hdr.out_len = 0; + ioc_xattr->hdr.operation = ZUFS_OP_XATTR_SET; + ioc_xattr->zus_ii = ZUII(inode)->zus_ii; + ioc_xattr->type = type; + ioc_xattr->name_len = name_len; + ioc_xattr->user_buf_size = size; + ioc_xattr->flags = flags; + + if (value && !size) + ioc_xattr->ioc_flags = ZUFS_XATTR_SET_EMPTY; + + strcpy(ioc_xattr->buf, name); + if (value) + memcpy(ioc_xattr->buf + name_len, value, size); + + err = zufc_dispatch(ZUF_ROOT(SBI(inode->i_sb)), &ioc_xattr->hdr, + NULL, 0); + + big_free(p_xattr, bat); + + return err; +} + +/* ~~~~~~~~~~~~~~~ xattr list ~~~~~~~~~~~~~~~ */ + +static ssize_t __zuf_listxattr(struct inode *inode, char *buffer, size_t size) +{ + struct zuf_inode_info *zii = ZUII(inode); + struct _xxxattr s_xattr; + struct zufs_ioc_xattr *ioc_xattr; + struct zuf_dispatch_op zdo; + + int err; + + zuf_dbg_vfs("[%ld] size=%lu\n", inode->i_ino, size); + + ioc_xattr = &s_xattr.d.ioc_xattr; + memset(ioc_xattr, 0, sizeof(*ioc_xattr)); + s_xattr.user_buffer = buffer; + + ioc_xattr->hdr.in_len = sizeof(*ioc_xattr); + ioc_xattr->hdr.out_start = + offsetof(struct zufs_ioc_xattr, user_buf_size); + /* out_len updated by zus */ + ioc_xattr->hdr.out_len = sizeof(ioc_xattr->user_buf_size); + ioc_xattr->hdr.out_max = 0; + ioc_xattr->hdr.operation = ZUFS_OP_XATTR_LIST; + ioc_xattr->zus_ii = zii->zus_ii; + ioc_xattr->name_len = 0; + ioc_xattr->user_buf_size = size; + ioc_xattr->ioc_flags = capable(CAP_SYS_ADMIN) ? ZUFS_XATTR_TRUSTED : 0; + + zuf_dispatch_init(&zdo, &ioc_xattr->hdr, NULL, 0); + zdo.oh = _xattr_oh; + err = __zufc_dispatch(ZUF_ROOT(SBI(inode->i_sb)), &zdo); + if (unlikely(err)) + return err; + + return ioc_xattr->user_buf_size; +} + +ssize_t zuf_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + struct inode *inode = dentry->d_inode; + struct zuf_inode_info *zii = ZUII(inode); + ssize_t ret; + + zuf_smr_lock(zii); + + ret = __zuf_listxattr(inode, buffer, size); + + zuf_smr_unlock(zii); + + return ret; +} + +/* ~~~~~~~~~~~~~~~ xattr sb handlers ~~~~~~~~~~~~~~~ */ +static bool zuf_xattr_handler_list(struct dentry *dentry) +{ + return true; +} + +static +int zuf_xattr_handler_get(const struct xattr_handler *handler, + struct dentry *dentry, struct inode *inode, + const char *name, void *value, size_t size) +{ + struct zuf_inode_info *zii = ZUII(inode); + int ret; + + zuf_dbg_xattr("[%ld] name=%s\n", inode->i_ino, name); + + zuf_smr_lock(zii); + + ret = __zuf_getxattr(inode, handler->flags, name, value, size); + + zuf_smr_unlock(zii); + + return ret; +} + +static +int zuf_xattr_handler_set(const struct xattr_handler *handler, + struct dentry *d_notused, struct inode *inode, + const char *name, const void *value, size_t size, + int flags) +{ + struct zuf_inode_info *zii = ZUII(inode); + int err; + + zuf_dbg_xattr("[%ld] name=%s size=0x%lx flags=0x%x\n", + inode->i_ino, name, size, flags); + + zuf_smw_lock(zii); + + err = __zuf_setxattr(inode, handler->flags, name, value, size, flags); + + zuf_smw_unlock(zii); + + return err; +} + +const struct xattr_handler zuf_xattr_security_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .flags = ZUF_XF_SECURITY, + .list = zuf_xattr_handler_list, + .get = zuf_xattr_handler_get, + .set = zuf_xattr_handler_set, +}; + +const struct xattr_handler zuf_xattr_trusted_handler = { + .prefix = XATTR_TRUSTED_PREFIX, + .flags = ZUF_XF_TRUSTED, + .list = zuf_xattr_handler_list, + .get = zuf_xattr_handler_get, + .set = zuf_xattr_handler_set, +}; + +const struct xattr_handler zuf_xattr_user_handler = { + .prefix = XATTR_USER_PREFIX, + .flags = ZUF_XF_USER, + .list = zuf_xattr_handler_list, + .get = zuf_xattr_handler_get, + .set = zuf_xattr_handler_set, +}; + +const struct xattr_handler *zuf_xattr_handlers[] = { + &zuf_xattr_user_handler, + &zuf_xattr_trusted_handler, + &zuf_xattr_security_handler, + &posix_acl_access_xattr_handler, + &posix_acl_default_xattr_handler, + NULL +}; + +/* + * Callback for security_inode_init_security() for acquiring xattrs. + */ +int zuf_initxattrs(struct inode *inode, const struct xattr *xattr_array, + void *fs_info) +{ + const struct xattr *xattr; + + for (xattr = xattr_array; xattr->name != NULL; xattr++) { + int err; + + /* REMOVEME: We had a BUG here for a long time that never + * crashed, I want to see this is called, please. + */ + zuf_warn("Yes it is name=%s value-size=%zd\n", + xattr->name, xattr->value_len); + + err = zuf_xattr_handler_set(&zuf_xattr_security_handler, NULL, + inode, xattr->name, xattr->value, + xattr->value_len, 0); + if (unlikely(err)) { + zuf_err("[%ld] failed to init xattrs err=%d\n", + inode->i_ino, err); + return err; + } + } + return 0; +} diff --git a/fs/zuf/zuf-core.c b/fs/zuf/zuf-core.c index 09ad210318f8..c6b614465ab3 100644 --- a/fs/zuf/zuf-core.c +++ b/fs/zuf/zuf-core.c @@ -788,6 +788,9 @@ const char *zuf_op_name(enum e_zufs_operation op) CASE_ENUM_NAME(ZUFS_OP_FALLOCATE ); CASE_ENUM_NAME(ZUFS_OP_LLSEEK ); CASE_ENUM_NAME(ZUFS_OP_IOCTL ); + CASE_ENUM_NAME(ZUFS_OP_XATTR_GET ); + CASE_ENUM_NAME(ZUFS_OP_XATTR_SET ); + CASE_ENUM_NAME(ZUFS_OP_XATTR_LIST ); CASE_ENUM_NAME(ZUFS_OP_BREAK ); default: return "UNKNOWN"; diff --git a/fs/zuf/zuf.h b/fs/zuf/zuf.h index 98f4ea088671..13b246189d8b 100644 --- a/fs/zuf/zuf.h +++ b/fs/zuf/zuf.h @@ -328,6 +328,13 @@ static inline void *zuf_dpp_t_addr(struct super_block *sb, zu_dpp_t v) return md_addr_verify(SBI(sb)->md, zu_dpp_t_val(v)); } +/* xattr types */ +enum { ZUF_XF_SECURITY = 1, + ZUF_XF_SYSTEM = 2, + ZUF_XF_TRUSTED = 3, + ZUF_XF_USER = 4, +}; + enum big_alloc_type { ba_stack, ba_kmalloc, ba_vmalloc }; static inline diff --git a/fs/zuf/zus_api.h b/fs/zuf/zus_api.h index f32ee615b937..40f369d20306 100644 --- a/fs/zuf/zus_api.h +++ b/fs/zuf/zus_api.h @@ -351,6 +351,9 @@ enum e_zufs_operation { ZUFS_OP_FALLOCATE, ZUFS_OP_LLSEEK, ZUFS_OP_IOCTL, + ZUFS_OP_XATTR_GET, + ZUFS_OP_XATTR_SET, + ZUFS_OP_XATTR_LIST, ZUFS_OP_BREAK, /* Kernel telling Server to exit */ ZUFS_OP_MAX_OPT, @@ -602,6 +605,25 @@ struct zufs_ioc_ioctl { }; }; +/* xattr ioc_flags */ +#define ZUFS_XATTR_SET_EMPTY (1 << 0) +#define ZUFS_XATTR_TRUSTED (1 << 1) + +/* ZUFS_OP_XATTR */ +struct zufs_ioc_xattr { + struct zufs_ioc_hdr hdr; + /* IN */ + struct zus_inode_info *zus_ii; + __u32 flags; + __u32 type; + __u16 name_len; + __u16 ioc_flags; + + /* OUT */ + __u32 user_buf_size; + char buf[0]; +} __packed; + /* ~~~~ io_map structures && IOCTL(s) ~~~~ */ /* * These set of structures and helpers are used in return of zufs_ioc_IO and -- 2.20.1