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
