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

_______________________________________________
Btrfs-devel mailing list
[email protected]
http://oss.oracle.com/mailman/listinfo/btrfs-devel

Reply via email to