Commit f34f57a3 authored by Yan, Zheng's avatar Yan, Zheng Committed by Chris Mason

Btrfs: Pass transaction handle to security and ACL initialization functions

Pass transaction handle down to security and ACL initialization
functions, so we can avoid starting nested transactions
Signed-off-by: default avatarYan Zheng <zheng.yan@oracle.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 8082510e
...@@ -94,7 +94,8 @@ static int btrfs_xattr_get_acl(struct inode *inode, int type, ...@@ -94,7 +94,8 @@ static int btrfs_xattr_get_acl(struct inode *inode, int type,
/* /*
* Needs to be called with fs_mutex held * 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; int ret, size = 0;
const char *name; const char *name;
...@@ -140,8 +141,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ...@@ -140,8 +141,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
goto out; goto out;
} }
ret = __btrfs_setxattr(inode, name, value, size, 0); ret = __btrfs_setxattr(trans, inode, name, value, size, 0);
out: out:
kfree(value); kfree(value);
...@@ -154,7 +154,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ...@@ -154,7 +154,7 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
static int btrfs_xattr_set_acl(struct inode *inode, int type, static int btrfs_xattr_set_acl(struct inode *inode, int type,
const void *value, size_t size) const void *value, size_t size)
{ {
int ret = 0; int ret;
struct posix_acl *acl = NULL; struct posix_acl *acl = NULL;
if (value) { if (value) {
...@@ -167,7 +167,7 @@ static int btrfs_xattr_set_acl(struct inode *inode, int type, ...@@ -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); posix_acl_release(acl);
...@@ -221,7 +221,8 @@ int btrfs_check_acl(struct inode *inode, int mask) ...@@ -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 * stuff has been fixed to work with that. If the locking stuff changes, we
* need to re-evaluate the acl locking stuff. * 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 *acl = NULL;
int ret = 0; int ret = 0;
...@@ -246,7 +247,8 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir) ...@@ -246,7 +247,8 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
mode_t mode; mode_t mode;
if (S_ISDIR(inode->i_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) if (ret)
goto failed; goto failed;
} }
...@@ -261,7 +263,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir) ...@@ -261,7 +263,7 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
inode->i_mode = mode; inode->i_mode = mode;
if (ret > 0) { if (ret > 0) {
/* we need an acl */ /* we need an acl */
ret = btrfs_set_acl(inode, clone, ret = btrfs_set_acl(trans, inode, clone,
ACL_TYPE_ACCESS); ACL_TYPE_ACCESS);
} }
} }
...@@ -294,7 +296,7 @@ int btrfs_acl_chmod(struct inode *inode) ...@@ -294,7 +296,7 @@ int btrfs_acl_chmod(struct inode *inode)
ret = posix_acl_chmod_masq(clone, inode->i_mode); ret = posix_acl_chmod_masq(clone, inode->i_mode);
if (!ret) 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); posix_acl_release(clone);
...@@ -320,7 +322,8 @@ int btrfs_acl_chmod(struct inode *inode) ...@@ -320,7 +322,8 @@ int btrfs_acl_chmod(struct inode *inode)
return 0; 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; return 0;
} }
......
...@@ -310,6 +310,9 @@ struct btrfs_header { ...@@ -310,6 +310,9 @@ struct btrfs_header {
#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item) - \ sizeof(struct btrfs_item) - \
sizeof(struct btrfs_file_extent_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, ...@@ -2201,9 +2204,10 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
struct btrfs_path *path, struct btrfs_path *path,
struct btrfs_dir_item *di); struct btrfs_dir_item *di);
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, const char *name, struct btrfs_root *root,
u16 name_len, const void *data, u16 data_len, struct btrfs_path *path, u64 objectid,
u64 dir); 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_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, u64 dir, struct btrfs_path *path, u64 dir,
...@@ -2382,7 +2386,8 @@ int btrfs_check_acl(struct inode *inode, int mask); ...@@ -2382,7 +2386,8 @@ int btrfs_check_acl(struct inode *inode, int mask);
#else #else
#define btrfs_check_acl NULL #define btrfs_check_acl NULL
#endif #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); int btrfs_acl_chmod(struct inode *inode);
/* relocation.c */ /* relocation.c */
......
...@@ -68,12 +68,12 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle ...@@ -68,12 +68,12 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
* into the tree * into the tree
*/ */
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
struct btrfs_root *root, const char *name, struct btrfs_root *root,
u16 name_len, const void *data, u16 data_len, struct btrfs_path *path, u64 objectid,
u64 dir) const char *name, u16 name_len,
const void *data, u16 data_len)
{ {
int ret = 0; int ret = 0;
struct btrfs_path *path;
struct btrfs_dir_item *dir_item; struct btrfs_dir_item *dir_item;
unsigned long name_ptr, data_ptr; unsigned long name_ptr, data_ptr;
struct btrfs_key key, location; struct btrfs_key key, location;
...@@ -81,15 +81,11 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, ...@@ -81,15 +81,11 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
struct extent_buffer *leaf; struct extent_buffer *leaf;
u32 data_size; 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); btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
key.offset = btrfs_name_hash(name, name_len); 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; data_size = sizeof(*dir_item) + name_len + data_len;
dir_item = insert_with_overflow(trans, root, path, &key, data_size, 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, ...@@ -117,7 +113,6 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
write_extent_buffer(leaf, data, data_ptr, data_len); write_extent_buffer(leaf, data, data_ptr, data_len);
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_free_path(path);
return ret; return ret;
} }
......
...@@ -88,13 +88,14 @@ static noinline int cow_file_range(struct inode *inode, ...@@ -88,13 +88,14 @@ static noinline int cow_file_range(struct inode *inode,
u64 start, u64 end, int *page_started, u64 start, u64 end, int *page_started,
unsigned long *nr_written, int unlock); 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; int err;
err = btrfs_init_acl(inode, dir); err = btrfs_init_acl(trans, inode, dir);
if (!err) if (!err)
err = btrfs_xattr_security_init(inode, dir); err = btrfs_xattr_security_init(trans, inode, dir);
return err; return err;
} }
...@@ -4296,7 +4297,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -4296,7 +4297,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_unlock; goto out_unlock;
err = btrfs_init_inode_security(inode, dir); err = btrfs_init_inode_security(trans, inode, dir);
if (err) { if (err) {
drop_inode = 1; drop_inode = 1;
goto out_unlock; goto out_unlock;
...@@ -4367,7 +4368,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, ...@@ -4367,7 +4368,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_unlock; goto out_unlock;
err = btrfs_init_inode_security(inode, dir); err = btrfs_init_inode_security(trans, inode, dir);
if (err) { if (err) {
drop_inode = 1; drop_inode = 1;
goto out_unlock; goto out_unlock;
...@@ -4500,7 +4501,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -4500,7 +4501,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
drop_on_err = 1; drop_on_err = 1;
err = btrfs_init_inode_security(inode, dir); err = btrfs_init_inode_security(trans, inode, dir);
if (err) if (err)
goto out_fail; goto out_fail;
...@@ -5660,7 +5661,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -5660,7 +5661,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_unlock; goto out_unlock;
err = btrfs_init_inode_security(inode, dir); err = btrfs_init_inode_security(trans, inode, dir);
if (err) { if (err) {
drop_inode = 1; drop_inode = 1;
goto out_unlock; goto out_unlock;
......
...@@ -85,22 +85,23 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name, ...@@ -85,22 +85,23 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
return ret; return ret;
} }
int __btrfs_setxattr(struct inode *inode, const char *name, static int do_setxattr(struct btrfs_trans_handle *trans,
const void *value, size_t size, int flags) struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{ {
struct btrfs_dir_item *di; struct btrfs_dir_item *di;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
struct btrfs_path *path; 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(); path = btrfs_alloc_path();
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
trans = btrfs_join_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
/* first lets see if we already have this xattr */ /* first lets see if we already have this xattr */
di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name, di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
strlen(name), -1); strlen(name), -1);
...@@ -118,15 +119,12 @@ int __btrfs_setxattr(struct inode *inode, const char *name, ...@@ -118,15 +119,12 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
} }
ret = btrfs_delete_one_dir_name(trans, root, path, di); ret = btrfs_delete_one_dir_name(trans, root, path, di);
if (ret) BUG_ON(ret);
goto out;
btrfs_release_path(root, path); btrfs_release_path(root, path);
/* if we don't have a value then we are removing the xattr */ /* if we don't have a value then we are removing the xattr */
if (!value) { if (!value)
mod = 1;
goto out; goto out;
}
} else { } else {
btrfs_release_path(root, path); btrfs_release_path(root, path);
...@@ -138,20 +136,45 @@ int __btrfs_setxattr(struct inode *inode, const char *name, ...@@ -138,20 +136,45 @@ int __btrfs_setxattr(struct inode *inode, const char *name,
} }
/* ok we have to create a completely new xattr */ /* ok we have to create a completely new xattr */
ret = btrfs_insert_xattr_item(trans, root, name, strlen(name), ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino,
value, size, 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) if (ret)
goto out; return ret;
mod = 1;
out: trans = btrfs_start_transaction(root, 1);
if (mod) { if (!trans) {
inode->i_ctime = CURRENT_TIME; ret = -ENOMEM;
ret = btrfs_update_inode(trans, root, inode); goto out;
} }
btrfs_set_trans_block_group(trans, inode);
btrfs_end_transaction(trans, root); ret = do_setxattr(trans, inode, name, value, size, flags);
btrfs_free_path(path); 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; return ret;
} }
...@@ -314,7 +337,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, ...@@ -314,7 +337,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
if (size == 0) if (size == 0)
value = ""; /* empty EA, do not remove */ 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) int btrfs_removexattr(struct dentry *dentry, const char *name)
...@@ -329,10 +354,13 @@ 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)) if (!btrfs_is_valid_xattr(name))
return -EOPNOTSUPP; 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; int err;
size_t len; size_t len;
...@@ -354,7 +382,7 @@ int btrfs_xattr_security_init(struct inode *inode, struct inode *dir) ...@@ -354,7 +382,7 @@ int btrfs_xattr_security_init(struct inode *inode, struct inode *dir)
} else { } else {
strcpy(name, XATTR_SECURITY_PREFIX); strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix); 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); kfree(name);
} }
......
...@@ -27,15 +27,16 @@ extern struct xattr_handler *btrfs_xattr_handlers[]; ...@@ -27,15 +27,16 @@ extern struct xattr_handler *btrfs_xattr_handlers[];
extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name, extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
void *buffer, size_t size); void *buffer, size_t size);
extern int __btrfs_setxattr(struct inode *inode, const char *name, extern int __btrfs_setxattr(struct btrfs_trans_handle *trans,
const void *value, size_t size, int flags); 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, extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
void *buffer, size_t size); void *buffer, size_t size);
extern int btrfs_setxattr(struct dentry *dentry, const char *name, extern int btrfs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags); const void *value, size_t size, int flags);
extern int btrfs_removexattr(struct dentry *dentry, const char *name); 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__ */ #endif /* __XATTR__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment