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: Yan Zheng <zheng.yan@oracle.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
8082510e71
commit
f34f57a3ab
6 changed files with 96 additions and 63 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
return ret;
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
if (!trans) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
btrfs_set_trans_block_group(trans, inode);
|
||||
|
||||
ret = do_setxattr(trans, inode, name, value, size, flags);
|
||||
if (ret)
|
||||
goto out;
|
||||
mod = 1;
|
||||
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
BUG_ON(ret);
|
||||
out:
|
||||
if (mod) {
|
||||
inode->i_ctime = CURRENT_TIME;
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
}
|
||||
|
||||
btrfs_end_transaction(trans, root);
|
||||
btrfs_free_path(path);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in a new issue