|
@@ -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);
|
|
|
}
|
|
|
|