Btrfs: Pass transaction handle to security and ACL initialization functions
authorYan, Zheng <zheng.yan@oracle.com>
Thu, 12 Nov 2009 09:35:27 +0000 (09:35 +0000)
committerChris Mason <chris.mason@oracle.com>
Thu, 17 Dec 2009 17:33:34 +0000 (12:33 -0500)
Pass transaction handle down to security and ACL initialization
functions, so we can avoid starting nested transactions

Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/acl.c
fs/btrfs/ctree.h
fs/btrfs/dir-item.c
fs/btrfs/inode.c
fs/btrfs/xattr.c
fs/btrfs/xattr.h

index 36160424427124947179e7270bfb77e03dbc1686..1898f8555f06cf3284bd9f7317cb75618b97ab53 100644 (file)
@@ -94,7 +94,8 @@ static int btrfs_xattr_get_acl(struct inode *inode, int type,
 /*
  * 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;
@@ -140,8 +141,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                        goto out;
        }
 
-       ret = __btrfs_setxattr(inode, name, value, size, 0);
-
+       ret = __btrfs_setxattr(trans, inode, name, value, size, 0);
 out:
        kfree(value);
 
@@ -154,7 +154,7 @@ out:
 static int btrfs_xattr_set_acl(struct inode *inode, int type,
                               const void *value, size_t size)
 {
-       int ret = 0;
+       int ret;
        struct posix_acl *acl = NULL;
 
        if (value) {
@@ -167,7 +167,7 @@ static int btrfs_xattr_set_acl(struct inode *inode, int type,
                }
        }
 
-       ret = btrfs_set_acl(inode, acl, type);
+       ret = btrfs_set_acl(NULL, inode, acl, type);
 
        posix_acl_release(acl);
 
@@ -221,7 +221,8 @@ 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;
        int ret = 0;
@@ -246,7 +247,8 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
                mode_t mode;
 
                if (S_ISDIR(inode->i_mode)) {
-                       ret = btrfs_set_acl(inode, acl, ACL_TYPE_DEFAULT);
+                       ret = btrfs_set_acl(trans, inode, acl,
+                                           ACL_TYPE_DEFAULT);
                        if (ret)
                                goto failed;
                }
@@ -261,7 +263,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
                        inode->i_mode = mode;
                        if (ret > 0) {
                                /* we need an acl */
-                               ret = btrfs_set_acl(inode, clone,
+                               ret = btrfs_set_acl(trans, inode, clone,
                                                    ACL_TYPE_ACCESS);
                        }
                }
@@ -294,7 +296,7 @@ int btrfs_acl_chmod(struct inode *inode)
 
        ret = posix_acl_chmod_masq(clone, inode->i_mode);
        if (!ret)
-               ret = btrfs_set_acl(inode, clone, ACL_TYPE_ACCESS);
+               ret = btrfs_set_acl(NULL, inode, clone, ACL_TYPE_ACCESS);
 
        posix_acl_release(clone);
 
@@ -320,7 +322,8 @@ int btrfs_acl_chmod(struct inode *inode)
        return 0;
 }
 
-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)
 {
        return 0;
 }
index fcfbefbbb6856aaabce5408655dbfa0cf9751b0e..a7cac2148c7cc9e30103bb6dc2261332882e67a6 100644 (file)
@@ -310,6 +310,9 @@ struct btrfs_header {
 #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
                                        sizeof(struct btrfs_item) - \
                                        sizeof(struct btrfs_file_extent_item))
+#define BTRFS_MAX_XATTR_SIZE(r)        (BTRFS_LEAF_DATA_SIZE(r) - \
+                                sizeof(struct btrfs_item) -\
+                                sizeof(struct btrfs_dir_item))
 
 
 /*
@@ -2201,9 +2204,10 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
                              struct btrfs_path *path,
                              struct btrfs_dir_item *di);
 int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, const char *name,
-                           u16 name_len, const void *data, u16 data_len,
-                           u64 dir);
+                           struct btrfs_root *root,
+                           struct btrfs_path *path, u64 objectid,
+                           const char *name, u16 name_len,
+                           const void *data, u16 data_len);
 struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
                                          struct btrfs_root *root,
                                          struct btrfs_path *path, u64 dir,
@@ -2382,7 +2386,8 @@ int btrfs_check_acl(struct inode *inode, int mask);
 #else
 #define btrfs_check_acl NULL
 #endif
-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);
 int btrfs_acl_chmod(struct inode *inode);
 
 /* relocation.c */
index f3a6075519ccc1d96e42157f95769a5ad6641a12..e9103b3baa49f4309c94eca9e0d7b7069665359c 100644 (file)
@@ -68,12 +68,12 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
  * into the tree
  */
 int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
-                           struct btrfs_root *root, const char *name,
-                           u16 name_len, const void *data, u16 data_len,
-                           u64 dir)
+                           struct btrfs_root *root,
+                           struct btrfs_path *path, u64 objectid,
+                           const char *name, u16 name_len,
+                           const void *data, u16 data_len)
 {
        int ret = 0;
-       struct btrfs_path *path;
        struct btrfs_dir_item *dir_item;
        unsigned long name_ptr, data_ptr;
        struct btrfs_key key, location;
@@ -81,15 +81,11 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
        u32 data_size;
 
-       key.objectid = dir;
+       BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root));
+
+       key.objectid = objectid;
        btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
        key.offset = btrfs_name_hash(name, name_len);
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-       if (name_len + data_len + sizeof(struct btrfs_dir_item) >
-           BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item))
-               return -ENOSPC;
 
        data_size = sizeof(*dir_item) + name_len + data_len;
        dir_item = insert_with_overflow(trans, root, path, &key, data_size,
@@ -117,7 +113,6 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
        write_extent_buffer(leaf, data, data_ptr, data_len);
        btrfs_mark_buffer_dirty(path->nodes[0]);
 
-       btrfs_free_path(path);
        return ret;
 }
 
index dcec42ee8cf22675d6c400ebca4d659e9c36bbdb..82740a3c628a0add03951a21932f6b26c8a7b2e6 100644 (file)
@@ -88,13 +88,14 @@ static noinline int cow_file_range(struct inode *inode,
                                   u64 start, u64 end, int *page_started,
                                   unsigned long *nr_written, int unlock);
 
-static int btrfs_init_inode_security(struct inode *inode,  struct inode *dir)
+static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
+                                    struct inode *inode,  struct inode *dir)
 {
        int err;
 
-       err = btrfs_init_acl(inode, dir);
+       err = btrfs_init_acl(trans, inode, dir);
        if (!err)
-               err = btrfs_xattr_security_init(inode, dir);
+               err = btrfs_xattr_security_init(trans, inode, dir);
        return err;
 }
 
@@ -4296,7 +4297,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                goto out_unlock;
 
-       err = btrfs_init_inode_security(inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@ -4367,7 +4368,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                goto out_unlock;
 
-       err = btrfs_init_inode_security(inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
@@ -4500,7 +4501,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        drop_on_err = 1;
 
-       err = btrfs_init_inode_security(inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir);
        if (err)
                goto out_fail;
 
@@ -5660,7 +5661,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(inode))
                goto out_unlock;
 
-       err = btrfs_init_inode_security(inode, dir);
+       err = btrfs_init_inode_security(trans, inode, dir);
        if (err) {
                drop_inode = 1;
                goto out_unlock;
index b6dd5967c48a2785074f75db2dacd6a7370a9ec2..193b58f7d3f3b36d027a85756c917aa7191f99b2 100644 (file)
@@ -85,22 +85,23 @@ out:
        return ret;
 }
 
-int __btrfs_setxattr(struct inode *inode, const char *name,
-                           const void *value, size_t size, int flags)
+static int do_setxattr(struct btrfs_trans_handle *trans,
+                      struct inode *inode, const char *name,
+                      const void *value, size_t size, int flags)
 {
        struct btrfs_dir_item *di;
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_trans_handle *trans;
        struct btrfs_path *path;
-       int ret = 0, mod = 0;
+       size_t name_len = strlen(name);
+       int ret = 0;
+
+       if (name_len + size > BTRFS_MAX_XATTR_SIZE(root))
+               return -ENOSPC;
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
-       trans = btrfs_join_transaction(root, 1);
-       btrfs_set_trans_block_group(trans, inode);
-
        /* first lets see if we already have this xattr */
        di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
                                strlen(name), -1);
@@ -118,15 +119,12 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
                }
 
                ret = btrfs_delete_one_dir_name(trans, root, path, di);
-               if (ret)
-                       goto out;
+               BUG_ON(ret);
                btrfs_release_path(root, path);
 
                /* if we don't have a value then we are removing the xattr */
-               if (!value) {
-                       mod = 1;
+               if (!value)
                        goto out;
-               }
        } else {
                btrfs_release_path(root, path);
 
@@ -138,20 +136,45 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
        }
 
        /* ok we have to create a completely new xattr */
-       ret = btrfs_insert_xattr_item(trans, root, name, strlen(name),
-                                     value, size, inode->i_ino);
+       ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino,
+                                     name, name_len, value, size);
+       BUG_ON(ret);
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int __btrfs_setxattr(struct btrfs_trans_handle *trans,
+                    struct inode *inode, const char *name,
+                    const void *value, size_t size, int flags)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret;
+
+       if (trans)
+               return do_setxattr(trans, inode, name, value, size, flags);
+
+       ret = btrfs_reserve_metadata_space(root, 2);
        if (ret)
-               goto out;
-       mod = 1;
+               return ret;
 
-out:
-       if (mod) {
-               inode->i_ctime = CURRENT_TIME;
-               ret = btrfs_update_inode(trans, root, inode);
+       trans = btrfs_start_transaction(root, 1);
+       if (!trans) {
+               ret = -ENOMEM;
+               goto out;
        }
+       btrfs_set_trans_block_group(trans, inode);
 
-       btrfs_end_transaction(trans, root);
-       btrfs_free_path(path);
+       ret = do_setxattr(trans, inode, name, value, size, flags);
+       if (ret)
+               goto out;
+
+       inode->i_ctime = CURRENT_TIME;
+       ret = btrfs_update_inode(trans, root, inode);
+       BUG_ON(ret);
+out:
+       btrfs_end_transaction_throttle(trans, root);
+       btrfs_unreserve_metadata_space(root, 2);
        return ret;
 }
 
@@ -314,7 +337,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
 
        if (size == 0)
                value = "";  /* empty EA, do not remove */
-       return __btrfs_setxattr(dentry->d_inode, name, value, size, flags);
+
+       return __btrfs_setxattr(NULL, dentry->d_inode, name, value, size,
+                               flags);
 }
 
 int btrfs_removexattr(struct dentry *dentry, const char *name)
@@ -329,10 +354,13 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
 
        if (!btrfs_is_valid_xattr(name))
                return -EOPNOTSUPP;
-       return __btrfs_setxattr(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
+
+       return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0,
+                               XATTR_REPLACE);
 }
 
-int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
+int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
+                             struct inode *inode, struct inode *dir)
 {
        int err;
        size_t len;
@@ -354,7 +382,7 @@ int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
        } else {
                strcpy(name, XATTR_SECURITY_PREFIX);
                strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);
-               err = __btrfs_setxattr(inode, name, value, len, 0);
+               err = __btrfs_setxattr(trans, inode, name, value, len, 0);
                kfree(name);
        }
 
index c71e9c3cf3f749e8981d19433bef8ada685383aa..721efa0346e037c2f6f32c91d7f284fbc580c87f 100644 (file)
@@ -27,15 +27,16 @@ extern struct xattr_handler *btrfs_xattr_handlers[];
 
 extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
                void *buffer, size_t size);
-extern int __btrfs_setxattr(struct inode *inode, const char *name,
-               const void *value, size_t size, int flags);
-
+extern int __btrfs_setxattr(struct btrfs_trans_handle *trans,
+                           struct inode *inode, const char *name,
+                           const void *value, size_t size, int flags);
 extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
                void *buffer, size_t size);
 extern int btrfs_setxattr(struct dentry *dentry, const char *name,
                const void *value, size_t size, int flags);
 extern int btrfs_removexattr(struct dentry *dentry, const char *name);
 
-extern int btrfs_xattr_security_init(struct inode *inode, struct inode *dir);
+extern int btrfs_xattr_security_init(struct btrfs_trans_handle *trans,
+                                    struct inode *inode, struct inode *dir);
 
 #endif /* __XATTR__ */