diff options
Diffstat (limited to 'fs/btrfs/acl.c')
| -rw-r--r-- | fs/btrfs/acl.c | 279 |
1 files changed, 47 insertions, 232 deletions
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 1d53b62dbba..9a0124a9585 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -22,124 +22,79 @@ #include <linux/posix_acl_xattr.h> #include <linux/posix_acl.h> #include <linux/sched.h> +#include <linux/slab.h> #include "ctree.h" #include "btrfs_inode.h" #include "xattr.h" -#ifdef CONFIG_FS_POSIX_ACL - -static void btrfs_update_cached_acl(struct inode *inode, - struct posix_acl **p_acl, - struct posix_acl *acl) -{ - spin_lock(&inode->i_lock); - if (*p_acl && *p_acl != BTRFS_ACL_NOT_CACHED) - posix_acl_release(*p_acl); - *p_acl = posix_acl_dup(acl); - spin_unlock(&inode->i_lock); -} - -static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) +struct posix_acl *btrfs_get_acl(struct inode *inode, int type) { int size; const char *name; char *value = NULL; - struct posix_acl *acl = NULL, **p_acl; + struct posix_acl *acl; switch (type) { case ACL_TYPE_ACCESS: name = POSIX_ACL_XATTR_ACCESS; - p_acl = &BTRFS_I(inode)->i_acl; break; case ACL_TYPE_DEFAULT: name = POSIX_ACL_XATTR_DEFAULT; - p_acl = &BTRFS_I(inode)->i_default_acl; break; default: - return ERR_PTR(-EINVAL); + BUG(); } - spin_lock(&inode->i_lock); - if (*p_acl != BTRFS_ACL_NOT_CACHED) - acl = posix_acl_dup(*p_acl); - spin_unlock(&inode->i_lock); - - if (acl) - return acl; - - size = __btrfs_getxattr(inode, name, "", 0); if (size > 0) { value = kzalloc(size, GFP_NOFS); if (!value) return ERR_PTR(-ENOMEM); size = __btrfs_getxattr(inode, name, value, size); - if (size > 0) { - acl = posix_acl_from_xattr(value, size); - btrfs_update_cached_acl(inode, p_acl, acl); - } - kfree(value); - } else if (size == -ENOENT) { + } + if (size > 0) { + acl = posix_acl_from_xattr(&init_user_ns, value, size); + } else if (size == -ENOENT || size == -ENODATA || size == 0) { + /* FIXME, who returns -ENOENT? I think nobody */ acl = NULL; - btrfs_update_cached_acl(inode, p_acl, acl); + } else { + acl = ERR_PTR(-EIO); } + kfree(value); - return acl; -} - -static int btrfs_xattr_get_acl(struct inode *inode, int type, - void *value, size_t size) -{ - struct posix_acl *acl; - int ret = 0; - - acl = btrfs_get_acl(inode, type); - - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - ret = posix_acl_to_xattr(acl, value, size); - posix_acl_release(acl); + if (!IS_ERR(acl)) + set_cached_acl(inode, type, acl); - return ret; + return acl; } /* * Needs to be called with fs_mutex held */ -static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) +static int __btrfs_set_acl(struct btrfs_trans_handle *trans, + struct inode *inode, struct posix_acl *acl, int type) { int ret, size = 0; const char *name; - struct posix_acl **p_acl; char *value = NULL; - mode_t mode; - - if (acl) { - ret = posix_acl_valid(acl); - if (ret < 0) - return ret; - ret = 0; - } switch (type) { case ACL_TYPE_ACCESS: - mode = inode->i_mode; - ret = posix_acl_equiv_mode(acl, &mode); - if (ret < 0) - return ret; - ret = 0; - inode->i_mode = mode; name = POSIX_ACL_XATTR_ACCESS; - p_acl = &BTRFS_I(inode)->i_acl; + if (acl) { + ret = posix_acl_equiv_mode(acl, &inode->i_mode); + if (ret < 0) + return ret; + if (ret == 0) + acl = NULL; + } + ret = 0; break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) return acl ? -EINVAL : 0; name = POSIX_ACL_XATTR_DEFAULT; - p_acl = &BTRFS_I(inode)->i_default_acl; break; default: return -EINVAL; @@ -153,85 +108,24 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) goto out; } - ret = posix_acl_to_xattr(acl, value, size); + ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); if (ret < 0) goto out; } - ret = __btrfs_setxattr(inode, name, value, size, 0); - + ret = __btrfs_setxattr(trans, inode, name, value, size, 0); out: kfree(value); if (!ret) - btrfs_update_cached_acl(inode, p_acl, acl); - - return ret; -} - -static int btrfs_xattr_set_acl(struct inode *inode, int type, - const void *value, size_t size) -{ - int ret = 0; - struct posix_acl *acl = NULL; - - if (value) { - acl = posix_acl_from_xattr(value, size); - if (acl == NULL) { - value = NULL; - size = 0; - } else if (IS_ERR(acl)) { - return PTR_ERR(acl); - } - } - - ret = btrfs_set_acl(inode, acl, type); - - posix_acl_release(acl); + set_cached_acl(inode, type, acl); return ret; } - -static int btrfs_xattr_acl_access_get(struct inode *inode, const char *name, - void *value, size_t size) -{ - return btrfs_xattr_get_acl(inode, ACL_TYPE_ACCESS, value, size); -} - -static int btrfs_xattr_acl_access_set(struct inode *inode, const char *name, - const void *value, size_t size, int flags) +int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - return btrfs_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); -} - -static int btrfs_xattr_acl_default_get(struct inode *inode, const char *name, - void *value, size_t size) -{ - return btrfs_xattr_get_acl(inode, ACL_TYPE_DEFAULT, value, size); -} - -static int btrfs_xattr_acl_default_set(struct inode *inode, const char *name, - const void *value, size_t size, int flags) -{ - return btrfs_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); -} - -int btrfs_check_acl(struct inode *inode, int mask) -{ - struct posix_acl *acl; - int error = -EAGAIN; - - acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); - - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - error = posix_acl_permission(inode, acl, mask); - posix_acl_release(acl); - } - - return error; + return __btrfs_set_acl(NULL, inode, acl, type); } /* @@ -239,113 +133,34 @@ int btrfs_check_acl(struct inode *inode, int mask) * stuff has been fixed to work with that. If the locking stuff changes, we * need to re-evaluate the acl locking stuff. */ -int btrfs_init_acl(struct inode *inode, struct inode *dir) +int btrfs_init_acl(struct btrfs_trans_handle *trans, + struct inode *inode, struct inode *dir) { - struct posix_acl *acl = NULL; + struct posix_acl *default_acl, *acl; int ret = 0; /* this happens with subvols */ if (!dir) return 0; - if (!S_ISLNK(inode->i_mode)) { - if (IS_POSIXACL(dir)) { - acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } + ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (ret) + return ret; - if (!acl) - inode->i_mode &= ~current->fs->umask; + if (default_acl) { + ret = __btrfs_set_acl(trans, inode, default_acl, + ACL_TYPE_DEFAULT); + posix_acl_release(default_acl); } - if (IS_POSIXACL(dir) && acl) { - struct posix_acl *clone; - mode_t mode; - - if (S_ISDIR(inode->i_mode)) { - ret = btrfs_set_acl(inode, acl, ACL_TYPE_DEFAULT); - if (ret) - goto failed; - } - clone = posix_acl_clone(acl, GFP_NOFS); - ret = -ENOMEM; - if (!clone) - goto failed; - - mode = inode->i_mode; - ret = posix_acl_create_masq(clone, &mode); - if (ret >= 0) { - inode->i_mode = mode; - if (ret > 0) { - /* we need an acl */ - ret = btrfs_set_acl(inode, clone, - ACL_TYPE_ACCESS); - } - } + if (acl) { + if (!ret) + ret = __btrfs_set_acl(trans, inode, acl, + ACL_TYPE_ACCESS); + posix_acl_release(acl); } -failed: - posix_acl_release(acl); - - return ret; -} - -int btrfs_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl, *clone; - int ret = 0; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - if (!IS_POSIXACL(inode)) - return 0; - - acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - - clone = posix_acl_clone(acl, GFP_KERNEL); - posix_acl_release(acl); - if (!clone) - return -ENOMEM; - - ret = posix_acl_chmod_masq(clone, inode->i_mode); - if (!ret) - ret = btrfs_set_acl(inode, clone, ACL_TYPE_ACCESS); - - posix_acl_release(clone); + if (!default_acl && !acl) + cache_no_acl(inode); return ret; } - -struct xattr_handler btrfs_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .get = btrfs_xattr_acl_default_get, - .set = btrfs_xattr_acl_default_set, -}; - -struct xattr_handler btrfs_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .get = btrfs_xattr_acl_access_get, - .set = btrfs_xattr_acl_access_set, -}; - -#else /* CONFIG_FS_POSIX_ACL */ - -int btrfs_acl_chmod(struct inode *inode) -{ - return 0; -} - -int btrfs_init_acl(struct inode *inode, struct inode *dir) -{ - return 0; -} - -int btrfs_check_acl(struct inode *inode, int mask) -{ - return 0; -} - -#endif /* CONFIG_FS_POSIX_ACL */ |
