diff mbox series

[RFC,15/17] zuf: ACL support

Message ID 20190219115136.29952-16-boaz@plexistor.com (mailing list archive)
State New, archived
Headers show
Series zuf: ZUFS Zero-copy User-mode FileSystem | expand

Commit Message

Boaz Harrosh Feb. 19, 2019, 11:51 a.m. UTC
From: Boaz Harrosh <boazh@netapp.com>

The ACL support is all in Kernel. There is no new API
with zusFS.
We define the internal structure of the ACL inside
an opec xattr and store via the xattr zus_api.

TODO:
  Future FSs that has their own ACL on-disk-format, Or
  Network zusFS that have their own verifiers for the ACL
  will need to establish an alternative API for the acl.

Signed-off-by: Boaz Harrosh <boazh@netapp.com>
---
 fs/zuf/Makefile  |   2 +-
 fs/zuf/_extern.h |   9 ++
 fs/zuf/_pr.h     |   1 +
 fs/zuf/acl.c     | 283 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/zuf/file.c    |   2 +
 fs/zuf/inode.c   |  11 ++
 fs/zuf/namei.c   |   4 +
 fs/zuf/zuf.h     |   6 +
 8 files changed, 317 insertions(+), 1 deletion(-)
 create mode 100644 fs/zuf/acl.c
diff mbox series

Patch

diff --git a/fs/zuf/Makefile b/fs/zuf/Makefile
index 5d638760a82f..f53504b47c2a 100644
--- a/fs/zuf/Makefile
+++ b/fs/zuf/Makefile
@@ -17,7 +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 += acl.o 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 1f4b39911a5d..2e515af0bb22 100644
--- a/fs/zuf/_extern.h
+++ b/fs/zuf/_extern.h
@@ -83,6 +83,15 @@  int __zuf_setxattr(struct inode *inode, int type, const char *name,
 ssize_t zuf_listxattr(struct dentry *dentry, char *buffer, size_t size);
 extern const struct xattr_handler *zuf_xattr_handlers[];
 
+/* acl.c */
+int zuf_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+struct posix_acl *zuf_get_acl(struct inode *inode, int type);
+int zuf_acls_create_pre(struct inode *dir, struct inode *inode,
+			struct posix_acl **user_acl);
+int zuf_acls_create_post(struct inode *dir, struct inode *inode,
+			 struct posix_acl *acl);
+extern const struct xattr_handler zuf_acl_access_xattr_handler;
+extern const struct xattr_handler zuf_acl_default_xattr_handler;
 
 /* super.c */
 int zuf_init_inodecache(void);
diff --git a/fs/zuf/_pr.h b/fs/zuf/_pr.h
index 04b99f57f2b5..7d7e4808dcf0 100644
--- a/fs/zuf/_pr.h
+++ b/fs/zuf/_pr.h
@@ -43,6 +43,7 @@ 
 #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_acl(s, args ...)	zuf_chan_debug("acl  ", 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/acl.c b/fs/zuf/acl.c
new file mode 100644
index 000000000000..ccea8ce455fb
--- /dev/null
+++ b/fs/zuf/acl.c
@@ -0,0 +1,283 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Access Control List
+ *
+ * Copyright (c) 2018 NetApp Inc. All rights reserved.
+ *
+ * ZUFS-License: GPL-2.0. See module.c for LICENSE details.
+ *
+ * Authors:
+ *	Boaz Harrosh <boazh@netapp.com>
+ */
+
+#include <linux/fs.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/xattr.h>
+#include "zuf.h"
+
+static void _acl_to_value(const struct posix_acl *acl, void *value)
+{
+	int n;
+	struct zuf_acl *macl = value;
+
+	zuf_dbg_acl("acl->count=%d\n", acl->a_count);
+
+	for (n = 0; n < acl->a_count; n++) {
+		const struct posix_acl_entry *entry = &acl->a_entries[n];
+
+		zuf_dbg_acl("aclno=%d tag=0x%x perm=0x%x\n",
+			     n, entry->e_tag, entry->e_perm);
+
+		macl->tag = cpu_to_le16(entry->e_tag);
+		macl->perm = cpu_to_le16(entry->e_perm);
+
+		switch (entry->e_tag) {
+		case ACL_USER:
+			macl->id = cpu_to_le32(__kuid_val(entry->e_uid));
+			break;
+		case ACL_GROUP:
+			macl->id = cpu_to_le32(__kgid_val(entry->e_gid));
+			break;
+		case ACL_USER_OBJ:
+		case ACL_GROUP_OBJ:
+		case ACL_MASK:
+		case ACL_OTHER:
+			break;
+		default:
+			zuf_dbg_err("e_tag=0x%x\n", entry->e_tag);
+			return;
+		}
+		macl++;
+	}
+}
+
+int zuf_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+	char *name = NULL;
+	void *buf;
+	int err;
+	size_t size;
+
+	zuf_dbg_acl("[%ld] acl=%p type=0x%x\n", inode->i_ino, acl, type);
+
+	switch (type) {
+	case ACL_TYPE_ACCESS: {
+		struct zus_inode *zi = ZUII(inode)->zi;
+
+		name = XATTR_POSIX_ACL_ACCESS;
+		if (acl) {
+			err = posix_acl_update_mode(inode, &inode->i_mode,
+						    &acl);
+			if (err < 0)
+				return err;
+
+			inode->i_ctime = current_time(inode);
+			timespec_to_mt(&zi->i_ctime, &inode->i_ctime);
+		}
+		zi->i_mode = cpu_to_le16(inode->i_mode);
+		break;
+	}
+	case ACL_TYPE_DEFAULT:
+		name = XATTR_POSIX_ACL_DEFAULT;
+		if (!S_ISDIR(inode->i_mode))
+			return acl ? -EACCES : 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	size = acl ? acl->a_count * sizeof(struct zuf_acl) : 0;
+	buf = kmalloc(size, GFP_KERNEL);
+	if (unlikely(!buf))
+		return -ENOMEM;
+
+	if (acl)
+		_acl_to_value(acl, buf);
+
+	err = __zuf_setxattr(inode, ZUF_XF_SYSTEM, name, buf, size, 0);
+	if (!err)
+		set_cached_acl(inode, type, acl);
+
+	kfree(buf);
+	return err;
+}
+
+static struct posix_acl *_value_to_acl(void *value, size_t size)
+{
+	int n, count;
+	struct posix_acl *acl;
+	struct zuf_acl *macl = value;
+	void *end = value + size;
+
+	if (!value)
+		return NULL;
+
+	count = size / sizeof(struct zuf_acl);
+	if (count < 0)
+		return ERR_PTR(-EINVAL);
+	if (count == 0)
+		return NULL;
+
+	acl = posix_acl_alloc(count, GFP_NOFS);
+	if (unlikely(!acl))
+		return ERR_PTR(-ENOMEM);
+
+	for (n = 0; n < count; n++) {
+		if (end < (void *)macl + sizeof(struct zuf_acl))
+			goto fail;
+
+		zuf_dbg_acl("aclno=%d tag=0x%x perm=0x%x id=0x%x\n",
+			     n, le16_to_cpu(macl->tag), le16_to_cpu(macl->perm),
+			     le32_to_cpu(macl->id));
+
+		acl->a_entries[n].e_tag  = le16_to_cpu(macl->tag);
+		acl->a_entries[n].e_perm = le16_to_cpu(macl->perm);
+
+		switch (acl->a_entries[n].e_tag) {
+		case ACL_USER_OBJ:
+		case ACL_GROUP_OBJ:
+		case ACL_MASK:
+		case ACL_OTHER:
+			macl++;
+			break;
+		case ACL_USER:
+			acl->a_entries[n].e_uid =
+					     KUIDT_INIT(le32_to_cpu(macl->id));
+			macl++;
+			if (end < (void *)macl)
+				goto fail;
+			break;
+		case ACL_GROUP:
+			acl->a_entries[n].e_gid =
+					     KGIDT_INIT(le32_to_cpu(macl->id));
+			macl++;
+			if (end < (void *)macl)
+				goto fail;
+			break;
+
+		default:
+			goto fail;
+		}
+	}
+	if (macl != end)
+		goto fail;
+	return acl;
+
+fail:
+	posix_acl_release(acl);
+	return ERR_PTR(-EINVAL);
+}
+
+struct posix_acl *zuf_get_acl(struct inode *inode, int type)
+{
+	struct zuf_inode_info *zii = ZUII(inode);
+	char *name = NULL;
+	void *buf;
+	struct posix_acl *acl = NULL;
+	int ret;
+
+	zuf_dbg_acl("[%ld] type=0x%x\n", inode->i_ino, type);
+
+	buf = (void *)__get_free_page(GFP_KERNEL);
+	if (unlikely(!buf))
+		return ERR_PTR(-ENOMEM);
+
+	switch (type) {
+	case ACL_TYPE_ACCESS:
+		name = XATTR_POSIX_ACL_ACCESS;
+		break;
+	case ACL_TYPE_DEFAULT:
+		name = XATTR_POSIX_ACL_DEFAULT;
+		break;
+	default:
+		WARN_ON(1);
+		return ERR_PTR(-EINVAL);
+	}
+
+	zuf_smr_lock(zii);
+
+	ret = __zuf_getxattr(inode, ZUF_XF_SYSTEM, name, buf, PAGE_SIZE);
+	if (likely(ret > 0)) {
+		acl = _value_to_acl(buf, ret);
+	} else if (ret != -ENODATA) {
+		if (ret != 0)
+			zuf_dbg_err("failed to getattr ret=%d\n", ret);
+		acl = ERR_PTR(ret);
+	}
+
+	if (!IS_ERR(acl))
+		set_cached_acl(inode, type, acl);
+
+	zuf_smr_unlock(zii);
+
+	free_page((ulong)buf);
+
+	return acl;
+}
+
+/* Used by creation of new inodes */
+int zuf_acls_create_pre(struct inode *dir, struct inode *inode,
+			struct posix_acl **user_acl)
+{
+	struct posix_acl *acl;
+
+	if (!IS_POSIXACL(dir))
+		return 0;
+
+	zuf_dbg_acl("[%ld] i_ino=%ld i_mode=o%o\n",
+		     dir->i_ino, inode->i_ino, inode->i_mode);
+
+	if (S_ISLNK(inode->i_mode))
+		return 0;
+
+	acl = get_acl(dir, ACL_TYPE_DEFAULT);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+	if (!acl)
+		inode->i_mode &= ~current_umask();
+	else
+		*user_acl = acl;
+
+	return 0;
+}
+
+int zuf_acls_create_post(struct inode *dir, struct inode *inode,
+			 struct posix_acl *acl)
+{
+	int err;
+
+	zuf_dbg_acl("[%ld] i_ino=%ld i_mode=o%o\n",
+		     dir->i_ino, inode->i_ino, inode->i_mode);
+
+	if (S_ISDIR(inode->i_mode)) {
+		err = zuf_set_acl(inode, acl, ACL_TYPE_DEFAULT);
+		if (err)
+			goto cleanup;
+	}
+	err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
+	if (unlikely(err < 0))
+		return err;
+
+	zus_zi(inode)->i_mode = cpu_to_le16(inode->i_mode);
+	if (err > 0) { /* This is an extended ACL */
+		err = zuf_set_acl(inode, acl, ACL_TYPE_ACCESS);
+	} else {
+		/* NOTE: Boaz think we will cry over this... */
+		struct zufs_ioc_attr ioc_attr = {
+			.hdr.in_len = sizeof(ioc_attr),
+			.hdr.out_len = sizeof(ioc_attr),
+			.hdr.operation = ZUFS_OP_SETATTR,
+			.zus_ii = ZUII(inode)->zus_ii,
+			.zuf_attr = STATX_MODE,
+		};
+
+		err = zufc_dispatch(ZUF_ROOT(SBI(inode->i_sb)),
+				    &ioc_attr.hdr, NULL, 0);
+		if (unlikely(err && err != -EINTR))
+			zuf_err("zufc_dispatch failed => %d\n", err);
+	}
+
+cleanup:
+	posix_acl_release(acl);
+	return err;
+}
diff --git a/fs/zuf/file.c b/fs/zuf/file.c
index 814a75105321..0ec87ec4d078 100644
--- a/fs/zuf/file.c
+++ b/fs/zuf/file.c
@@ -521,5 +521,7 @@  const struct inode_operations zuf_file_inode_operations = {
 	.getattr	= zuf_getattr,
 	.update_time	= zuf_update_time,
 	.fiemap		= tozu_fiemap,
+	.get_acl	= zuf_get_acl,
+	.set_acl	= zuf_set_acl,
 	.listxattr	= zuf_listxattr,
 };
diff --git a/fs/zuf/inode.c b/fs/zuf/inode.c
index 73f94e7062e5..3b9e78feab06 100644
--- a/fs/zuf/inode.c
+++ b/fs/zuf/inode.c
@@ -342,6 +342,7 @@  struct inode *zuf_new_inode(struct inode *dir, umode_t mode,
 		.flags = tmpfile ? ZI_TMPFILE : 0,
 		.str.len = qstr->len,
 	};
+	struct posix_acl *acl = NULL;
 	struct inode *inode;
 	struct zus_inode *zi = NULL;
 	struct page *pages[2];
@@ -366,6 +367,10 @@  struct inode *zuf_new_inode(struct inode *dir, umode_t mode,
 	if (err && err != -EOPNOTSUPP)
 		goto fail;
 
+	err = zuf_acls_create_pre(dir, inode, &acl);
+	if (unlikely(err))
+		goto fail;
+
 	zuf_set_inode_flags(inode, &ioc_new_inode.zi);
 
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
@@ -406,6 +411,12 @@  struct inode *zuf_new_inode(struct inode *dir, umode_t mode,
 
 	zuf_dbg_verbose("allocating inode %ld (zi=%p)\n", _zi_ino(zi), zi);
 
+	if (acl && !symname) {
+		err = zuf_acls_create_post(dir, inode, acl);
+		if (unlikely(err))
+			goto fail;
+	}
+
 	err = insert_inode_locked(inode);
 	if (unlikely(err)) {
 		zuf_dbg_err("[%ld:%s] generation=%lld insert_inode_locked => %d\n",
diff --git a/fs/zuf/namei.c b/fs/zuf/namei.c
index 803069423674..a33745c328b9 100644
--- a/fs/zuf/namei.c
+++ b/fs/zuf/namei.c
@@ -420,6 +420,8 @@  const struct inode_operations zuf_dir_inode_operations = {
 	.setattr	= zuf_setattr,
 	.getattr	= zuf_getattr,
 	.update_time	= zuf_update_time,
+	.get_acl	= zuf_get_acl,
+	.set_acl	= zuf_set_acl,
 	.listxattr	= zuf_listxattr,
 };
 
@@ -427,5 +429,7 @@  const struct inode_operations zuf_special_inode_operations = {
 	.setattr	= zuf_setattr,
 	.getattr	= zuf_getattr,
 	.update_time	= zuf_update_time,
+	.get_acl	= zuf_get_acl,
+	.set_acl	= zuf_set_acl,
 	.listxattr	= zuf_listxattr,
 };
diff --git a/fs/zuf/zuf.h b/fs/zuf/zuf.h
index 13b246189d8b..b6347dc6eb6a 100644
--- a/fs/zuf/zuf.h
+++ b/fs/zuf/zuf.h
@@ -335,6 +335,12 @@  enum {	ZUF_XF_SECURITY    = 1,
 	ZUF_XF_USER        = 4,
 };
 
+struct zuf_acl {
+	__le16	tag;
+	__le16	perm;
+	__le32	id;
+} __packed;
+
 enum big_alloc_type { ba_stack, ba_kmalloc, ba_vmalloc };
 
 static inline