[Btrfs-devel][PATCH] The second patch of acl supporting for
btrfs(patch for btrfs-unstable)
Liu Hui
onlyflyer at gmail.com
Sun Jan 27 06:50:34 PST 2008
Hi:
This is second patch for btrfs acl supporting. This patch complete
acl supporting for btrfs-unstable:
1,Enable posix acl support by default, unless someone mounts with -o noacl
2,acl check support
3,acl init support
4,acl chmod support
5,Avoid a performance hit related to always checking acls by mark
inode's flag with BTRFS_INODE_NO_DEFAULT_ACL and
BTRFS_INODE_NO_ACCESS_ACL
6,Remove fs lock operation from btrfs_xattr_get and btrfs_xattr_set
because the lock operation confict with higher caller such as
btrfs_mkfs. These lock operation should be move to higher caller, e.g.
btrfs_xattr_acl_access_get.
--
diff -r 21e9b461f802 acl.c
--- a/acl.c Thu Jan 24 16:13:14 2008 -0500
+++ b/acl.c Sun Jan 27 22:44:59 2008 +0800
@@ -23,19 +23,83 @@
#include <linux/sched.h>
#include "ctree.h"
#include "xattr.h"
+#include "btrfs_inode.h"
+
#ifndef is_owner_or_cap
-#define is_owner_or_cap(inode) \
+ #define is_owner_or_cap(inode) \
((current->fsuid == (inode)->i_uid) || capable(CAP_FOWNER))
#endif
+static void *btrfs_acl_to_xattr(struct posix_acl *acl, size_t *size)
+{
+ size_t real_size;
+ void *buf = NULL;
+ int error;
+
+ real_size = posix_acl_xattr_size(acl->a_count);
+ if (real_size <= 0)
+ return NULL;
+
+ *size = real_size;
+ buf = kmalloc(real_size, GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ error = posix_acl_to_xattr(acl, buf, real_size);
+ if (error < 0) {
+ kfree(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+static int btrfs_xattr_get_acl(struct inode *inode, int type,
+ void *value, size_t size)
+{
+ if (btrfs_test_opt(BTRFS_I(inode)->root, NOACL))
+ return -EOPNOTSUPP;
+ return btrfs_xattr_get(inode, type, "", value, size);
+}
+
+static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) {
+ int ret, len;
+ char *value = NULL;
+ struct posix_acl *acl;
+
+ len = btrfs_xattr_get(inode, type, "", NULL, 0);
+ if (IS_ERR((const void *)len))
+ return ERR_PTR(len);
+ if (len > 0) {
+ value = kmalloc(len, GFP_KERNEL);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+
+ } else
+ return NULL;
+
+ ret = btrfs_xattr_get_acl(inode, type, value, len);
+ if (ret > 0)
+ acl = posix_acl_from_xattr(value, len);
+ else if (-ENODATA == ret)
+ acl = NULL;
+ else
+ acl = ERR_PTR(ret);
+
+ kfree(value);
+ return acl;
+}
+
static int btrfs_xattr_set_acl(struct inode *inode, int type,
const void *value, size_t size)
{
int ret = 0;
struct posix_acl *acl;
+ if (btrfs_test_opt(BTRFS_I(inode)->root, NOACL))
+ return -EOPNOTSUPP;
if (!is_owner_or_cap(inode))
return -EPERM;
+
if (value) {
acl = posix_acl_from_xattr(value, size);
if (acl == NULL) {
@@ -53,53 +117,229 @@ static int btrfs_xattr_set_acl(struct in
return btrfs_xattr_set(inode, type, "", value, size, 0);
}
-static int btrfs_xattr_get_acl(struct inode *inode, int type,
- void *value, size_t size)
-{
- return btrfs_xattr_get(inode, type, "", value, size);
-}
+static int btrfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+{
+ void *value = NULL;
+ size_t size = 0;
+ int err;
+
+ if (!acl)
+ return -ENODATA;
+
+ value = btrfs_acl_to_xattr(acl, &size);
+ if (!value)
+ return -ENODATA;
+
+ err = btrfs_xattr_set_acl(inode, type, value, size);
+ kfree(value);
+ return err;
+}
+
static int btrfs_xattr_acl_access_get(struct inode *inode, const char *name,
void *value, size_t size)
{
- if (*name != '\0')
- return -EINVAL;
- return btrfs_xattr_get_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS,
- value, size);
-}
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ int err;
+
+ if (*name != '\0')
+ return -EINVAL;
+ if (btrfs_test_flag(inode, NO_ACCESS_ACL))
+ return -ENODATA;
+ mutex_lock(&root->fs_info->fs_mutex);
+ err = btrfs_xattr_get_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS,
+ value, size);
+ mutex_unlock(&root->fs_info->fs_mutex);
+ return err;
+}
+
static int btrfs_xattr_acl_access_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
- if (*name != '\0')
- return -EINVAL;
- return btrfs_xattr_set_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS,
- value, size);
-}
+ int err;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+
+ if (*name != '\0')
+ return -EINVAL;
+ mutex_lock(&root->fs_info->fs_mutex);
+ err = btrfs_xattr_set_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS,
+ value, size);
+ mutex_unlock(&root->fs_info->fs_mutex);
+ if (!err)
+ btrfs_clear_flag(inode, NO_ACCESS_ACL);
+ return err;
+}
+
+struct xattr_handler btrfs_xattr_acl_access_handler = {
+ .prefix = POSIX_ACL_XATTR_ACCESS,
+ .list = btrfs_xattr_generic_list,
+ .get = btrfs_xattr_acl_access_get,
+ .set = btrfs_xattr_acl_access_set,
+};
+
static int btrfs_xattr_acl_default_get(struct inode *inode, const char *name,
void *value, size_t size)
{
- if (*name != '\0')
- return -EINVAL;
- return btrfs_xattr_get_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT,
- value, size);
-}
+ int err;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+
+ if (*name != '\0')
+ return -EINVAL;
+ if (btrfs_test_flag(inode, NO_DEFAULT_ACL))
+ return -ENODATA;
+
+ mutex_lock(&root->fs_info->fs_mutex);
+ err = btrfs_xattr_get_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT,
+ value, size);
+ mutex_unlock(&root->fs_info->fs_mutex);
+ return err;
+}
+
static int btrfs_xattr_acl_default_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
- if (*name != '\0')
- return -EINVAL;
- return btrfs_xattr_set_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT,
- value, size);
+ int err;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+
+ if (*name != '\0')
+ return -EINVAL;
+ mutex_lock(&root->fs_info->fs_mutex);
+ err = btrfs_xattr_set_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT,
+ value, size);
+ mutex_unlock(&root->fs_info->fs_mutex);
+ if (!err)
+ btrfs_clear_flag(inode, NO_DEFAULT_ACL);
+ return err;
}
struct xattr_handler btrfs_xattr_acl_default_handler = {
.prefix = POSIX_ACL_XATTR_DEFAULT,
- .list = btrfs_xattr_generic_list,
- .get = btrfs_xattr_acl_default_get,
- .set = btrfs_xattr_acl_default_set,
+ .list = btrfs_xattr_generic_list,
+ .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,
- .list = btrfs_xattr_generic_list,
- .get = btrfs_xattr_acl_access_get,
- .set = btrfs_xattr_acl_access_set,
-};
+static int __btrfs_acl_init(struct inode *inode, struct inode *dir)
+{
+ struct posix_acl *acl, *clone;
+ mode_t mode;
+ int err;
+
+ acl = btrfs_get_acl(dir, BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT);
+ if (!acl)
+ return -ENODATA;
+
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+
+ if (S_ISDIR(inode->i_mode)) {
+ err = btrfs_set_acl(inode,
+ BTRFS_XATTR_INDEX_POSIX_ACL_DEFAULT,
+ acl);
+ if (err)
+ goto cleanup;
+ }
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ if (!clone) {
+ err = -ENOMEM;
+ goto cleanup;
+ }
+ mode = inode->i_mode;
+ err = posix_acl_create_masq(clone, &mode);
+ if (err >= 0) {
+ inode->i_mode = mode;
+ if (err > 0)
+ btrfs_set_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS,
+ clone);
+ }
+ posix_acl_release(clone);
+ err = 0;
+cleanup:
+ posix_acl_release(acl);
+ return err;
+}
+
+int btrfs_acl_init(struct inode *inode, struct inode *dir)
+{
+ int err;
+
+ inode->i_mode &= ~current->fs->umask;
+ if (S_ISLNK(inode->i_mode))
+ return 0;
+
+ if (btrfs_test_flag(dir, NO_DEFAULT_ACL) ||
+ btrfs_test_opt(BTRFS_I(inode)->root, NOACL)) {
+
+ btrfs_set_flag(inode, NO_ACCESS_ACL);
+
+ if (S_ISDIR(inode->i_mode))
+ btrfs_set_flag(inode, NO_DEFAULT_ACL);
+ return 0;
+ }
+
+ err = __btrfs_acl_init(inode, dir);
+ if (err) {
+ if (S_ISDIR(inode->i_mode))
+ btrfs_set_flag(inode, NO_DEFAULT_ACL);
+
+ btrfs_set_flag(inode, NO_ACCESS_ACL);
+ } else {
+ if (S_ISDIR(inode->i_mode))
+ btrfs_clear_flag(inode, NO_DEFAULT_ACL);
+
+ btrfs_clear_flag(inode, NO_ACCESS_ACL);
+ }
+ return err;
+}
+
+int btrfs_acl_chmod(struct inode *inode)
+{
+ struct posix_acl *acl, *clone;
+ int err = 0;
+
+ if (btrfs_test_opt(BTRFS_I(inode)->root, NOACL) ||
+ btrfs_test_flag(inode, NO_ACCESS_ACL))
+ return 0;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+
+ acl = btrfs_get_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_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;
+
+ err = posix_acl_chmod_masq(clone, inode->i_mode);
+ if (!err)
+ err = btrfs_set_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS,
+ clone);
+ posix_acl_release(clone);
+
+ return err;
+}
+
+int btrfs_check_acl(struct inode *inode, int mask)
+{
+ struct posix_acl *acl;
+ int error;
+
+ if (btrfs_test_opt(BTRFS_I(inode)->root, NOACL) ||
+ btrfs_test_flag(inode, NO_ACCESS_ACL))
+ return -EAGAIN;
+
+ mutex_lock(&BTRFS_I(inode)->root->fs_info->fs_mutex);
+ acl = btrfs_get_acl(inode, BTRFS_XATTR_INDEX_POSIX_ACL_ACCESS);
+ mutex_unlock(&BTRFS_I(inode)->root->fs_info->fs_mutex);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+
+ if (acl) {
+ error = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ return error;
+ }
+
+ return -EAGAIN;
+}
diff -r 21e9b461f802 ctree.h
--- a/ctree.h Thu Jan 24 16:13:14 2008 -0500
+++ b/ctree.h Sun Jan 27 22:44:59 2008 +0800
@@ -447,6 +447,7 @@ struct btrfs_root {
#define BTRFS_MOUNT_NODATACOW (1 << 1)
#define BTRFS_MOUNT_NOBARRIER (1 << 2)
#define BTRFS_MOUNT_SSD (1 << 3)
+#define BTRFS_MOUNT_NOACL (1 << 4)
#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
@@ -458,6 +459,8 @@ struct btrfs_root {
#define BTRFS_INODE_NODATASUM (1 << 0)
#define BTRFS_INODE_NODATACOW (1 << 1)
#define BTRFS_INODE_READONLY (1 << 2)
+#define BTRFS_INODE_NO_ACCESS_ACL (1 << 3)
+#define BTRFS_INODE_NO_DEFAULT_ACL (1 << 4)
#define btrfs_clear_flag(inode, flag) (BTRFS_I(inode)->flags &= \
~BTRFS_INODE_##flag)
#define btrfs_set_flag(inode, flag) (BTRFS_I(inode)->flags |= \
@@ -1194,4 +1197,9 @@ int btrfs_delete_xattrs(struct btrfs_tra
struct btrfs_root *root, struct inode *inode);
/* super.c */
u64 btrfs_parse_size(char *str);
+
+/* acl.c */
+int btrfs_acl_init(struct inode *ionde, struct inode *dir);
+int btrfs_acl_chmod(struct inode *inode);
+int btrfs_check_acl(struct inode *inode, int mask);
#endif
diff -r 21e9b461f802 inode.c
--- a/inode.c Thu Jan 24 16:13:14 2008 -0500
+++ b/inode.c Sun Jan 27 22:44:59 2008 +0800
@@ -1020,6 +1020,13 @@ static int btrfs_setattr(struct dentry *
}
out:
err = inode_setattr(inode, attr);
+#ifdef CONFIG_FS_POSIX_ACL
+ if (!err && (attr->ia_valid & ATTR_MODE)) {
+ mutex_lock(&BTRFS_I(inode)->root->fs_info->fs_mutex);
+ err = btrfs_acl_chmod(inode);
+ mutex_unlock(&BTRFS_I(inode)->root->fs_info->fs_mutex);
+ }
+#endif
fail:
return err;
}
@@ -1617,7 +1624,13 @@ static int btrfs_mknod(struct inode *dir
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_unlock;
-
+#ifdef CONFIG_FS_POSIX_ACL
+ err = btrfs_acl_init(inode, dir);
+ if (err) {
+ drop_inode = 1;
+ goto out_unlock;
+ }
+#endif
btrfs_set_trans_block_group(trans, inode);
err = btrfs_add_nondir(trans, dentry, inode);
if (err)
@@ -1674,7 +1687,13 @@ static int btrfs_create(struct inode *di
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out_unlock;
-
+#ifdef CONFIG_FS_POSIX_ACL
+ err = btrfs_acl_init(inode, dir);
+ if (err) {
+ drop_inode = 1;
+ goto out_unlock;
+ }
+#endif
btrfs_set_trans_block_group(trans, inode);
err = btrfs_add_nondir(trans, dentry, inode);
if (err)
@@ -1793,7 +1812,13 @@ static int btrfs_mkdir(struct inode *dir
err = PTR_ERR(inode);
goto out_fail;
}
-
+#ifdef CONFIG_FS_POSIX_ACL
+ err = btrfs_acl_init(inode, dir);
+ if (err) {
+ drop_on_err = 1;
+ goto out_fail;
+ }
+#endif
drop_on_err = 1;
inode->i_op = &btrfs_dir_inode_operations;
inode->i_fop = &btrfs_dir_file_operations;
@@ -2909,7 +2934,12 @@ static int btrfs_permission(struct inode
{
if (btrfs_test_flag(inode, READONLY) && (mask & MAY_WRITE))
return -EACCES;
+
+#ifdef CONFIG_FS_POSIX_ACL
+ return generic_permission(inode, mask, btrfs_check_acl);
+#else
return generic_permission(inode, mask, NULL);
+#endif
}
static struct inode_operations btrfs_dir_inode_operations = {
diff -r 21e9b461f802 super.c
--- a/super.c Thu Jan 24 16:13:14 2008 -0500
+++ b/super.c Sun Jan 27 22:44:59 2008 +0800
@@ -64,7 +64,7 @@ static void btrfs_put_super (struct supe
enum {
Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_max_extent,
- Opt_alloc_start, Opt_nobarrier, Opt_ssd, Opt_err,
+ Opt_alloc_start, Opt_nobarrier, Opt_ssd, Opt_noacl, Opt_err,
};
static match_table_t tokens = {
@@ -75,6 +75,7 @@ static match_table_t tokens = {
{Opt_max_extent, "max_extent=%s"},
{Opt_alloc_start, "alloc_start=%s"},
{Opt_ssd, "ssd"},
+ {Opt_noacl, "noacl"},
{Opt_err, NULL}
};
@@ -156,6 +157,12 @@ static int parse_options (char * options
btrfs_set_opt(info->mount_opt, SSD);
}
break;
+ case Opt_noacl:
+ if (info) {
+ printk("btrfs: disable posix acl\n");
+ btrfs_set_opt(info->mount_opt, NOACL);
+ }
+ break;
case Opt_nobarrier:
if (info) {
printk("btrfs: turning off barriers\n");
@@ -247,6 +254,11 @@ static int btrfs_fill_super(struct super
}
parse_options((char *)data, tree_root, NULL);
+ if (btrfs_test_opt(tree_root, NOACL)) {
+ sb->s_flags = sb->s_flags & ~MS_POSIXACL;
+ } else {
+ sb->s_flags |= MS_POSIXACL;
+ }
/* this does the super kobj at the same time */
err = btrfs_sysfs_add_super(tree_root->fs_info);
diff -r 21e9b461f802 xattr.c
--- a/xattr.c Thu Jan 24 16:13:14 2008 -0500
+++ b/xattr.c Sun Jan 27 22:44:59 2008 +0800
@@ -129,6 +129,9 @@ size_t btrfs_xattr_generic_list(struct i
return name_len+1;
}
+/*
+ * fs_mutex should be held when we come into here
+ */
ssize_t btrfs_xattr_get(struct inode *inode, int name_index,
const char *attr_name, void *buffer, size_t size)
{
@@ -153,7 +156,6 @@ ssize_t btrfs_xattr_get(struct inode *in
return -ENOMEM;
}
- mutex_lock(&root->fs_info->fs_mutex);
/* lookup the xattr by name */
di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name,
strlen(name), 0);
@@ -181,12 +183,15 @@ ssize_t btrfs_xattr_get(struct inode *in
ret = btrfs_dir_data_len(leaf, di);
out:
- mutex_unlock(&root->fs_info->fs_mutex);
kfree(name);
btrfs_free_path(path);
return ret;
}
+
+/*
+ * fs_mutex should be held when we come into here
+ */
int btrfs_xattr_set(struct inode *inode, int name_index,
const char *attr_name, const void *value, size_t size,
int flags)
@@ -210,7 +215,6 @@ int btrfs_xattr_set(struct inode *inode,
return -ENOMEM;
}
- mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
@@ -260,7 +264,6 @@ out:
}
btrfs_end_transaction(trans, root);
- mutex_unlock(&root->fs_info->fs_mutex);
kfree(name);
btrfs_free_path(path);
@@ -445,17 +448,27 @@ static int btrfs_xattr_##name##_get(stru
const char *name, void *value, \
size_t size) \
{ \
+ int err; \
+ struct btrfs_root *root = BTRFS_I(inode)->root; \
if (*name == '\0') \
return -EINVAL; \
- return btrfs_xattr_get(inode, index, name, value, size); \
+ mutex_lock(&root->fs_info->fs_mutex); \
+ err = btrfs_xattr_get(inode, index, name, value, size); \
+ mutex_unlock(&root->fs_info->fs_mutex); \
+ return err; \
} \
static int btrfs_xattr_##name##_set(struct inode *inode, \
const char *name, const void *value,\
size_t size, int flags) \
{ \
+ int err; \
+ struct btrfs_root *root = BTRFS_I(inode)->root; \
if (*name == '\0') \
return -EINVAL; \
- return btrfs_xattr_set(inode, index, name, value, size, flags); \
+ mutex_lock(&root->fs_info->fs_mutex); \
+ err = btrfs_xattr_set(inode, index, name, value, size, flags); \
+ mutex_unlock(&root->fs_info->fs_mutex); \
+ return err; \
}
BTRFS_XATTR_SETGET_FUNCS(security, BTRFS_XATTR_INDEX_SECURITY);
--
Thanks & Best Regards
Liu Hui
More information about the Btrfs-devel
mailing list