diff options
Diffstat (limited to 'module')
-rw-r--r-- | module/zcommon/zfs_prop.c | 11 | ||||
-rw-r--r-- | module/zfs/zfs_acl.c | 3 | ||||
-rw-r--r-- | module/zfs/zfs_vfsops.c | 40 | ||||
-rw-r--r-- | module/zfs/zfs_vnops.c | 12 | ||||
-rw-r--r-- | module/zfs/zpl_inode.c | 40 | ||||
-rw-r--r-- | module/zfs/zpl_super.c | 42 | ||||
-rw-r--r-- | module/zfs/zpl_xattr.c | 467 |
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 }; |