summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
Diffstat (limited to 'module')
-rw-r--r--module/zcommon/zfs_prop.c11
-rw-r--r--module/zfs/zfs_acl.c3
-rw-r--r--module/zfs/zfs_vfsops.c40
-rw-r--r--module/zfs/zfs_vnops.c12
-rw-r--r--module/zfs/zpl_inode.c40
-rw-r--r--module/zfs/zpl_super.c42
-rw-r--r--module/zfs/zpl_xattr.c467
7 files changed, 590 insertions, 25 deletions
diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c
index b27e4f36f..722995dc5 100644
--- a/module/zcommon/zfs_prop.c
+++ b/module/zcommon/zfs_prop.c
@@ -112,6 +112,14 @@ zfs_prop_init(void)
{ NULL }
};
+ static zprop_index_t acltype_table[] = {
+ { "off", ZFS_ACLTYPE_OFF },
+ { "disabled", ZFS_ACLTYPE_OFF },
+ { "noacl", ZFS_ACLTYPE_OFF },
+ { "posixacl", ZFS_ACLTYPE_POSIXACL },
+ { NULL }
+ };
+
static zprop_index_t acl_inherit_table[] = {
{ "discard", ZFS_ACL_DISCARD },
{ "noallow", ZFS_ACL_NOALLOW },
@@ -226,6 +234,9 @@ zfs_prop_init(void)
zprop_register_index(ZFS_PROP_SNAPDEV, "snapdev", ZFS_SNAPDEV_HIDDEN,
PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"hidden | visible", "SNAPDEV", snapdev_table);
+ zprop_register_index(ZFS_PROP_ACLTYPE, "acltype", ZFS_ACLTYPE_OFF,
+ PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
+ "noacl | posixacl", "ACLTYPE", acltype_table);
zprop_register_index(ZFS_PROP_ACLINHERIT, "aclinherit",
ZFS_ACL_RESTRICTED, PROP_INHERIT, ZFS_TYPE_FILESYSTEM,
"discard | noallow | restricted | passthrough | passthrough-x",
diff --git a/module/zfs/zfs_acl.c b/module/zfs/zfs_acl.c
index 8ab5abe81..25f236a14 100644
--- a/module/zfs/zfs_acl.c
+++ b/module/zfs/zfs_acl.c
@@ -1155,6 +1155,9 @@ zfs_acl_chown_setattr(znode_t *zp)
int error;
zfs_acl_t *aclp;
+ if (ZTOZSB(zp)->z_acl_type == ZFS_ACLTYPE_POSIXACL)
+ return 0;
+
ASSERT(MUTEX_HELD(&zp->z_lock));
ASSERT(MUTEX_HELD(&zp->z_acl_lock));
diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c
index eeac0391c..3af174479 100644
--- a/module/zfs/zfs_vfsops.c
+++ b/module/zfs/zfs_vfsops.c
@@ -155,6 +155,25 @@ xattr_changed_cb(void *arg, uint64_t newval)
}
static void
+acltype_changed_cb(void *arg, uint64_t newval)
+{
+ zfs_sb_t *zsb = arg;
+
+ switch (newval) {
+ case ZFS_ACLTYPE_OFF:
+ zsb->z_acl_type = ZFS_ACLTYPE_OFF;
+ zsb->z_sb->s_flags &= ~MS_POSIXACL;
+ break;
+ case ZFS_ACLTYPE_POSIXACL:
+ zsb->z_acl_type = ZFS_ACLTYPE_POSIXACL;
+ zsb->z_sb->s_flags |= MS_POSIXACL;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
blksz_changed_cb(void *arg, uint64_t newval)
{
zfs_sb_t *zsb = arg;
@@ -266,8 +285,9 @@ zfs_register_callbacks(zfs_sb_t *zsb)
error = error ? error : dsl_prop_register(ds,
zfs_prop_to_name(ZFS_PROP_SNAPDIR), snapdir_changed_cb, zsb);
error = error ? error : dsl_prop_register(ds,
- zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb,
- zsb);
+ zfs_prop_to_name(ZFS_PROP_ACLTYPE), acltype_changed_cb, zsb);
+ error = error ? error : dsl_prop_register(ds,
+ zfs_prop_to_name(ZFS_PROP_ACLINHERIT), acl_inherit_changed_cb, zsb);
error = error ? error : dsl_prop_register(ds,
zfs_prop_to_name(ZFS_PROP_VSCAN), vscan_changed_cb, zsb);
error = error ? error : dsl_prop_register(ds,
@@ -303,6 +323,8 @@ unregister:
exec_changed_cb, zsb);
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SNAPDIR),
snapdir_changed_cb, zsb);
+ (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLTYPE),
+ acltype_changed_cb, zsb);
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLINHERIT),
acl_inherit_changed_cb, zsb);
(void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_VSCAN),
@@ -663,6 +685,10 @@ zfs_sb_create(const char *osname, zfs_sb_t **zsbp)
goto out;
zsb->z_case = (uint_t)zval;
+ if ((error = zfs_get_zplprop(os, ZFS_PROP_ACLTYPE, &zval)) != 0)
+ goto out;
+ zsb->z_acl_type = (uint_t)zval;
+
/*
* Fold case on file systems that are always or sometimes case
* insensitive.
@@ -904,6 +930,9 @@ zfs_unregister_callbacks(zfs_sb_t *zsb)
VERIFY(dsl_prop_unregister(ds, "snapdir", snapdir_changed_cb,
zsb) == 0);
+ VERIFY(dsl_prop_unregister(ds, "acltype", acltype_changed_cb,
+ zsb) == 0);
+
VERIFY(dsl_prop_unregister(ds, "aclinherit",
acl_inherit_changed_cb, zsb) == 0);
@@ -1221,6 +1250,9 @@ zfs_domount(struct super_block *sb, void *data, int silent)
if ((error = dsl_prop_get_integer(osname,"xattr",&pval,NULL)))
goto out;
xattr_changed_cb(zsb, pval);
+ if ((error = dsl_prop_get_integer(osname,"acltype",&pval,NULL)))
+ goto out;
+ acltype_changed_cb(zsb, pval);
zsb->z_issnap = B_TRUE;
zsb->z_os->os_sync = ZFS_SYNC_DISABLED;
@@ -1610,6 +1642,9 @@ zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value)
case ZFS_PROP_CASE:
*value = ZFS_CASE_SENSITIVE;
break;
+ case ZFS_PROP_ACLTYPE:
+ *value = ZFS_ACLTYPE_OFF;
+ break;
default:
return (error);
}
@@ -1632,6 +1667,7 @@ zfs_init(void)
void
zfs_fini(void)
{
+ taskq_wait(system_taskq);
unregister_filesystem(&zpl_fs_type);
zfs_znode_fini();
zfsctl_fini();
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c
index 436a25eaf..423ca3800 100644
--- a/module/zfs/zfs_vnops.c
+++ b/module/zfs/zfs_vnops.c
@@ -3971,7 +3971,7 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
/*
* Update the system attributes when the inode has been dirtied. For the
- * moment we're conservative and only update the atime, mtime, and ctime.
+ * moment we only update the mode, atime, mtime, and ctime.
*/
int
zfs_dirty_inode(struct inode *ip, int flags)
@@ -3979,8 +3979,8 @@ zfs_dirty_inode(struct inode *ip, int flags)
znode_t *zp = ITOZ(ip);
zfs_sb_t *zsb = ITOZSB(ip);
dmu_tx_t *tx;
- uint64_t atime[2], mtime[2], ctime[2];
- sa_bulk_attr_t bulk[3];
+ uint64_t mode, atime[2], mtime[2], ctime[2];
+ sa_bulk_attr_t bulk[4];
int error;
int cnt = 0;
@@ -3999,14 +3999,18 @@ zfs_dirty_inode(struct inode *ip, int flags)
}
mutex_enter(&zp->z_lock);
+ SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MODE(zsb), NULL, &mode, 8);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(zsb), NULL, &atime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_CTIME(zsb), NULL, &ctime, 16);
- /* Preserve the mtime and ctime provided by the inode */
+ /* Preserve the mode, mtime and ctime provided by the inode */
ZFS_TIME_ENCODE(&ip->i_atime, atime);
ZFS_TIME_ENCODE(&ip->i_mtime, mtime);
ZFS_TIME_ENCODE(&ip->i_ctime, ctime);
+ mode = ip->i_mode;
+
+ zp->z_mode = mode;
zp->z_atime_dirty = 0;
error = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx);
diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c
index 720d2d9fa..e15f0451a 100644
--- a/module/zfs/zpl_inode.c
+++ b/module/zfs/zpl_inode.c
@@ -102,8 +102,8 @@ zpl_create(struct inode *dir, struct dentry *dentry, zpl_umode_t mode,
error = -zfs_create(dir, dname(dentry), vap, 0, mode, &ip, cr, 0, NULL);
if (error == 0) {
- error = zpl_xattr_security_init(ip, dir, &dentry->d_name);
- VERIFY3S(error, ==, 0);
+ VERIFY0(zpl_xattr_security_init(ip, dir, &dentry->d_name));
+ VERIFY0(zpl_init_acl(ip, dir));
d_instantiate(dentry, ip);
}
@@ -136,8 +136,10 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, zpl_umode_t mode,
vap->va_rdev = rdev;
error = -zfs_create(dir, dname(dentry), vap, 0, mode, &ip, cr, 0, NULL);
- if (error == 0)
+ if (error == 0) {
+ VERIFY0(zpl_init_acl(ip, dir));
d_instantiate(dentry, ip);
+ }
kmem_free(vap, sizeof(vattr_t));
crfree(cr);
@@ -173,8 +175,10 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, zpl_umode_t mode)
zpl_vap_init(vap, dir, mode | S_IFDIR, cr);
error = -zfs_mkdir(dir, dname(dentry), vap, &ip, cr, 0, NULL);
- if (error == 0)
+ if (error == 0) {
+ VERIFY0(zpl_init_acl(ip, dir));
d_instantiate(dentry, ip);
+ }
kmem_free(vap, sizeof(vattr_t));
crfree(cr);
@@ -223,11 +227,12 @@ zpl_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
static int
zpl_setattr(struct dentry *dentry, struct iattr *ia)
{
+ struct inode *ip = dentry->d_inode;
cred_t *cr = CRED();
vattr_t *vap;
int error;
- error = inode_change_ok(dentry->d_inode, ia);
+ error = inode_change_ok(ip, ia);
if (error)
return (error);
@@ -242,7 +247,9 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia)
vap->va_mtime = ia->ia_mtime;
vap->va_ctime = ia->ia_ctime;
- error = -zfs_setattr(dentry->d_inode, vap, 0, cr);
+ error = -zfs_setattr(ip, vap, 0, cr);
+ if (!error && (ia->ia_valid & ATTR_MODE))
+ error = zpl_chmod_acl(ip);
kmem_free(vap, sizeof(vattr_t));
crfree(cr);
@@ -455,6 +462,13 @@ const struct inode_operations zpl_inode_operations = {
#ifdef HAVE_INODE_FALLOCATE
.fallocate = zpl_fallocate,
#endif /* HAVE_INODE_FALLOCATE */
+#if defined(HAVE_GET_ACL)
+ .get_acl = zpl_get_acl,
+#elif defined(HAVE_CHECK_ACL)
+ .check_acl = zpl_check_acl,
+#elif defined(HAVE_PERMISSION)
+ .permission = zpl_permission,
+#endif /* HAVE_GET_ACL | HAVE_CHECK_ACL | HAVE_PERMISSION */
};
const struct inode_operations zpl_dir_inode_operations = {
@@ -473,6 +487,13 @@ const struct inode_operations zpl_dir_inode_operations = {
.getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = zpl_xattr_list,
+#if defined(HAVE_GET_ACL)
+ .get_acl = zpl_get_acl,
+#elif defined(HAVE_CHECK_ACL)
+ .check_acl = zpl_check_acl,
+#elif defined(HAVE_PERMISSION)
+ .permission = zpl_permission,
+#endif /* HAVE_GET_ACL | HAVE_CHECK_ACL | HAVE_PERMISSION */
};
const struct inode_operations zpl_symlink_inode_operations = {
@@ -494,6 +515,13 @@ const struct inode_operations zpl_special_inode_operations = {
.getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = zpl_xattr_list,
+#if defined(HAVE_GET_ACL)
+ .get_acl = zpl_get_acl,
+#elif defined(HAVE_CHECK_ACL)
+ .check_acl = zpl_check_acl,
+#elif defined(HAVE_PERMISSION)
+ .permission = zpl_permission,
+#endif /* HAVE_GET_ACL | HAVE_CHECK_ACL | HAVE_PERMISSION */
};
dentry_operations_t zpl_dentry_operations = {
diff --git a/module/zfs/zpl_super.c b/module/zfs/zpl_super.c
index eee4a50e0..72859ac5c 100644
--- a/module/zfs/zpl_super.c
+++ b/module/zfs/zpl_super.c
@@ -179,28 +179,48 @@ zpl_umount_begin(struct super_block *sb)
}
/*
- * The Linux VFS automatically handles the following flags:
- * MNT_NOSUID, MNT_NODEV, MNT_NOEXEC, MNT_NOATIME, MNT_READONLY
+ * ZFS specific features must be explicitly handled here, the VFS will
+ * automatically handled the following generic functionality.
+ *
+ * MNT_NOSUID,
+ * MNT_NODEV,
+ * MNT_NOEXEC,
+ * MNT_NOATIME,
+ * MNT_NODIRATIME,
+ * MNT_READONLY,
+ * MNT_STRICTATIME,
+ * MS_SYNCHRONOUS,
+ * MS_DIRSYNC,
+ * MS_MANDLOCK.
*/
-#ifdef HAVE_SHOW_OPTIONS_WITH_DENTRY
static int
-zpl_show_options(struct seq_file *seq, struct dentry *root)
+__zpl_show_options(struct seq_file *seq, zfs_sb_t *zsb)
{
- zfs_sb_t *zsb = root->d_sb->s_fs_info;
-
seq_printf(seq, ",%s", zsb->z_flags & ZSB_XATTR ? "xattr" : "noxattr");
+ switch (zsb->z_acl_type) {
+ case ZFS_ACLTYPE_POSIXACL:
+ seq_puts(seq, ",posixacl");
+ break;
+ default:
+ seq_puts(seq, ",noacl");
+ break;
+ }
+
return (0);
}
+
+#ifdef HAVE_SHOW_OPTIONS_WITH_DENTRY
+static int
+zpl_show_options(struct seq_file *seq, struct dentry *root)
+{
+ return __zpl_show_options(seq, root->d_sb->s_fs_info);
+}
#else
static int
zpl_show_options(struct seq_file *seq, struct vfsmount *vfsp)
{
- zfs_sb_t *zsb = vfsp->mnt_sb->s_fs_info;
-
- seq_printf(seq, ",%s", zsb->z_flags & ZSB_XATTR ? "xattr" : "noxattr");
-
- return (0);
+ return __zpl_show_options(seq, vfsp->mnt_sb->s_fs_info);
}
#endif /* HAVE_SHOW_OPTIONS_WITH_DENTRY */
diff --git a/module/zfs/zpl_xattr.c b/module/zfs/zpl_xattr.c
index 0918e7404..276ea3361 100644
--- a/module/zfs/zpl_xattr.c
+++ b/module/zfs/zpl_xattr.c
@@ -722,13 +722,476 @@ xattr_handler_t zpl_xattr_security_handler = {
.set = zpl_xattr_security_set,
};
+int
+zpl_set_acl(struct inode *ip, int type, struct posix_acl *acl)
+{
+ struct super_block *sb = ITOZSB(ip)->z_sb;
+ char *name, *value = NULL;
+ int error = 0;
+ size_t size = 0;
+
+ if (S_ISLNK(ip->i_mode))
+ return (-EOPNOTSUPP);
+
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ if (acl) {
+ zpl_equivmode_t mode = ip->i_mode;
+ error = posix_acl_equiv_mode(acl, &mode);
+ if (error < 0) {
+ return (error);
+ } else {
+ /*
+ * The mode bits will have been set by
+ * ->zfs_setattr()->zfs_acl_chmod_setattr()
+ * using the ZFS ACL conversion. If they
+ * differ from the Posix ACL conversion dirty
+ * the inode to write the Posix mode bits.
+ */
+ if (ip->i_mode != mode) {
+ ip->i_mode = mode;
+ ip->i_ctime = current_fs_time(sb);
+ mark_inode_dirty(ip);
+ }
+
+ if (error == 0)
+ acl = NULL;
+ }
+ }
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ if (!S_ISDIR(ip->i_mode))
+ return (acl ? -EACCES : 0);
+ break;
+
+ default:
+ return (-EINVAL);
+ }
+
+ if (acl) {
+ size = posix_acl_xattr_size(acl->a_count);
+ value = kmem_alloc(size, KM_SLEEP);
+
+ error = zpl_acl_to_xattr(acl, value, size);
+ if (error < 0) {
+ kmem_free(value, size);
+ return (error);
+ }
+ }
+
+ error = zpl_xattr_set(ip, name, value, size, 0);
+ if (value)
+ kmem_free(value, size);
+
+ if (!error) {
+ if (acl)
+ zpl_set_cached_acl(ip, type, acl);
+ else
+ zpl_forget_cached_acl(ip, type);
+ }
+
+ return (error);
+}
+
+struct posix_acl *
+zpl_get_acl(struct inode *ip, int type)
+{
+ struct posix_acl *acl;
+ void *value = NULL;
+ char *name;
+ int size;
+
+#ifdef HAVE_POSIX_ACL_CACHING
+ acl = get_cached_acl(ip, type);
+ if (acl != ACL_NOT_CACHED)
+ return (acl);
+#endif /* HAVE_POSIX_ACL_CACHING */
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ size = zpl_xattr_get(ip, name, NULL, 0);
+ if (size > 0) {
+ value = kmem_alloc(size, KM_PUSHPAGE);
+ size = zpl_xattr_get(ip, name, value, size);
+ }
+
+ if (size > 0) {
+ acl = zpl_acl_from_xattr(value, size);
+ } else if (size == -ENODATA || size == -ENOSYS) {
+ acl = NULL;
+ } else {
+ acl = ERR_PTR(-EIO);
+ }
+
+ if (size > 0)
+ kmem_free(value, size);
+
+ if (!IS_ERR(acl))
+ zpl_set_cached_acl(ip, type, acl);
+
+ return (acl);
+}
+
+#if !defined(HAVE_GET_ACL)
+static int
+__zpl_check_acl(struct inode *ip, int mask)
+{
+ struct posix_acl *acl;
+ int error;
+
+ acl = zpl_get_acl(ip, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl))
+ return (PTR_ERR(acl));
+
+ if (acl) {
+ error = posix_acl_permission(ip, acl, mask);
+ zpl_posix_acl_release(acl);
+ return (error);
+ }
+
+ return (-EAGAIN);
+}
+
+#if defined(HAVE_CHECK_ACL_WITH_FLAGS)
+int
+zpl_check_acl(struct inode *ip, int mask, unsigned int flags)
+{
+ return __zpl_check_acl(ip, mask);
+}
+#elif defined(HAVE_CHECK_ACL)
+int
+zpl_check_acl(struct inode *ip, int mask)
+{
+ return __zpl_check_acl(ip , mask);
+}
+#elif defined(HAVE_PERMISSION_WITH_NAMEIDATA)
+int
+zpl_permission(struct inode *ip, int mask, struct nameidata *nd)
+{
+ return generic_permission(ip, mask, __zpl_check_acl);
+}
+#elif defined(HAVE_PERMISSION)
+int
+zpl_permission(struct inode *ip, int mask)
+{
+ return generic_permission(ip, mask, __zpl_check_acl);
+}
+#endif /* HAVE_CHECK_ACL | HAVE_PERMISSION */
+#endif /* !HAVE_GET_ACL */
+
+int
+zpl_init_acl(struct inode *ip, struct inode *dir)
+{
+ struct posix_acl *acl = NULL;
+ int error = 0;
+
+ if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+ return (0);
+
+ if (!S_ISLNK(ip->i_mode)) {
+ if (ITOZSB(ip)->z_acl_type == ZFS_ACLTYPE_POSIXACL) {
+ acl = zpl_get_acl(dir, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl))
+ return (PTR_ERR(acl));
+ }
+
+ if (!acl) {
+ ip->i_mode &= ~current_umask();
+ ip->i_ctime = current_fs_time(ITOZSB(ip)->z_sb);
+ mark_inode_dirty(ip);
+ return (0);
+ }
+ }
+
+ if ((ITOZSB(ip)->z_acl_type == ZFS_ACLTYPE_POSIXACL) && acl) {
+ umode_t mode;
+
+ if (S_ISDIR(ip->i_mode)) {
+ error = zpl_set_acl(ip, ACL_TYPE_DEFAULT, acl);
+ if (error)
+ goto out;
+ }
+
+ mode = ip->i_mode;
+ error = posix_acl_create(&acl,GFP_KERNEL, &mode);
+ if (error >= 0) {
+ ip->i_mode = mode;
+ mark_inode_dirty(ip);
+ if (error > 0)
+ error = zpl_set_acl(ip, ACL_TYPE_ACCESS, acl);
+ }
+ }
+out:
+ zpl_posix_acl_release(acl);
+
+ return (error);
+}
+
+int
+zpl_chmod_acl(struct inode *ip)
+{
+ struct posix_acl *acl;
+ int error;
+
+ if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+ return (0);
+
+ if (S_ISLNK(ip->i_mode))
+ return (-EOPNOTSUPP);
+
+ acl = zpl_get_acl(ip, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl) || !acl)
+ return (PTR_ERR(acl));
+
+ error = posix_acl_chmod(&acl,GFP_KERNEL, ip->i_mode);
+ if (!error)
+ error = zpl_set_acl(ip,ACL_TYPE_ACCESS, acl);
+
+ zpl_posix_acl_release(acl);
+
+ return (error);
+}
+
+static size_t
+zpl_xattr_acl_list(struct inode *ip, char *list, size_t list_size,
+ const char *name, size_t name_len, int type)
+{
+ char *xattr_name;
+ size_t xattr_size;
+
+ if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+ return (0);
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ xattr_name = POSIX_ACL_XATTR_ACCESS;
+ xattr_size = sizeof(xattr_name);
+ break;
+ case ACL_TYPE_DEFAULT:
+ xattr_name = POSIX_ACL_XATTR_DEFAULT;
+ xattr_size = sizeof(xattr_name);
+ break;
+ default:
+ return (0);
+ }
+
+ if (list && xattr_size <= list_size)
+ memcpy(list, xattr_name, xattr_size);
+
+ return (xattr_size);
+}
+
+#ifdef HAVE_DENTRY_XATTR_LIST
+static size_t
+zpl_xattr_acl_list_access(struct dentry *dentry, char *list,
+ size_t list_size, const char *name, size_t name_len, int type)
+{
+ ASSERT3S(type, ==, ACL_TYPE_ACCESS);
+ return zpl_xattr_acl_list(dentry->d_inode,
+ list, list_size, name, name_len, type);
+}
+
+static size_t
+zpl_xattr_acl_list_default(struct dentry *dentry, char *list,
+ size_t list_size, const char *name, size_t name_len, int type)
+{
+ ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
+ return zpl_xattr_acl_list(dentry->d_inode,
+ list, list_size, name, name_len, type);
+}
+
+#else
+
+static size_t
+zpl_xattr_acl_list_access(struct inode *ip, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ return zpl_xattr_acl_list(ip,
+ list, list_size, name, name_len, ACL_TYPE_ACCESS);
+}
+
+static size_t
+zpl_xattr_acl_list_default(struct inode *ip, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ return zpl_xattr_acl_list(ip,
+ list, list_size, name, name_len, ACL_TYPE_DEFAULT);
+}
+#endif /* HAVE_DENTRY_XATTR_LIST */
+
+static int
+zpl_xattr_acl_get(struct inode *ip, const char *name,
+ void *buffer, size_t size, int type)
+{
+ struct posix_acl *acl;
+ int error;
+
+ if (strcmp(name, "") != 0)
+ return (-EINVAL);
+
+ if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+ return (-EOPNOTSUPP);
+
+ acl = zpl_get_acl(ip, type);
+ if (IS_ERR(acl))
+ return (PTR_ERR(acl));
+ if (acl == NULL)
+ return (-ENODATA);
+
+ error = zpl_acl_to_xattr(acl, buffer, size);
+ zpl_posix_acl_release(acl);
+
+ return (error);
+}
+
+#ifdef HAVE_DENTRY_XATTR_GET
+static int
+zpl_xattr_acl_get_access(struct dentry *dentry, const char *name,
+ void *buffer, size_t size, int type)
+{
+ ASSERT3S(type, ==, ACL_TYPE_ACCESS);
+ return zpl_xattr_acl_get(dentry->d_inode, name, buffer, size, type);
+}
+
+static int
+zpl_xattr_acl_get_default(struct dentry *dentry, const char *name,
+ void *buffer, size_t size, int type)
+{
+ ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
+ return zpl_xattr_acl_get(dentry->d_inode, name, buffer, size, type);
+}
+
+#else
+
+static int
+zpl_xattr_acl_get_access(struct inode *ip, const char *name,
+ void *buffer, size_t size)
+{
+ return zpl_xattr_acl_get(ip, name, buffer, size, ACL_TYPE_ACCESS);
+}
+
+static int
+zpl_xattr_acl_get_default(struct inode *ip, const char *name,
+ void *buffer, size_t size)
+{
+ return zpl_xattr_acl_get(ip, name, buffer, size, ACL_TYPE_DEFAULT);
+}
+#endif /* HAVE_DENTRY_XATTR_GET */
+
+static int
+zpl_xattr_acl_set(struct inode *ip, const char *name,
+ const void *value, size_t size, int flags, int type)
+{
+ struct posix_acl *acl;
+ int error = 0;
+
+ if (strcmp(name, "") != 0)
+ return (-EINVAL);
+
+ if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
+ return (-EOPNOTSUPP);
+
+ if (!zpl_inode_owner_or_capable(ip))
+ return (-EPERM);
+
+ if (value) {
+ acl = zpl_acl_from_xattr(value, size);
+ if (IS_ERR(acl))
+ return (PTR_ERR(acl));
+ else if (acl) {
+ error = posix_acl_valid(acl);
+ if (error) {
+ zpl_posix_acl_release(acl);
+ return (error);
+ }
+ }
+ } else {
+ acl = NULL;
+ }
+
+ error = zpl_set_acl(ip, type, acl);
+ zpl_posix_acl_release(acl);
+
+ return (error);
+}
+
+#ifdef HAVE_DENTRY_XATTR_SET
+static int
+zpl_xattr_acl_set_access(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags, int type)
+{
+ ASSERT3S(type, ==, ACL_TYPE_ACCESS);
+ return zpl_xattr_acl_set(dentry->d_inode,
+ name, value, size, flags, type);
+}
+
+static int
+zpl_xattr_acl_set_default(struct dentry *dentry, const char *name,
+ const void *value, size_t size,int flags, int type)
+{
+ ASSERT3S(type, ==, ACL_TYPE_DEFAULT);
+ return zpl_xattr_acl_set(dentry->d_inode,
+ name, value, size, flags, type);
+}
+
+#else
+
+static int
+zpl_xattr_acl_set_access(struct inode *ip, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return zpl_xattr_acl_set(ip,
+ name, value, size, flags, ACL_TYPE_ACCESS);
+}
+
+static int
+zpl_xattr_acl_set_default(struct inode *ip, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return zpl_xattr_acl_set(ip,
+ name, value, size, flags, ACL_TYPE_DEFAULT);
+}
+#endif /* HAVE_DENTRY_XATTR_SET */
+
+struct xattr_handler zpl_xattr_acl_access_handler =
+{
+ .prefix = POSIX_ACL_XATTR_ACCESS,
+ .list = zpl_xattr_acl_list_access,
+ .get = zpl_xattr_acl_get_access,
+ .set = zpl_xattr_acl_set_access,
+#ifdef HAVE_DENTRY_XATTR_LIST
+ .flags = ACL_TYPE_ACCESS,
+#endif /* HAVE_DENTRY_XATTR_LIST */
+};
+
+struct xattr_handler zpl_xattr_acl_default_handler =
+{
+ .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .list = zpl_xattr_acl_list_default,
+ .get = zpl_xattr_acl_get_default,
+ .set = zpl_xattr_acl_set_default,
+#ifdef HAVE_DENTRY_XATTR_LIST
+ .flags = ACL_TYPE_DEFAULT,
+#endif /* HAVE_DENTRY_XATTR_LIST */
+};
+
xattr_handler_t *zpl_xattr_handlers[] = {
&zpl_xattr_security_handler,
&zpl_xattr_trusted_handler,
&zpl_xattr_user_handler,
-#ifdef HAVE_POSIX_ACLS
&zpl_xattr_acl_access_handler,
&zpl_xattr_acl_default_handler,
-#endif /* HAVE_POSIX_ACLS */
NULL
};