summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-07 15:58:48 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-07 15:58:48 +0200
commit7b63ef2d55f24519e7e9e5f4d15dbea03f126e40 (patch)
tree9e842d00ac35cf317b27afc0867f8eb632e4c9aa
parent0f2732620d6ec49d3e6c06831575eaec6bc99d42 (diff)
parent41c8899d59898f6fa51ceebd2b6e55257191a8ee (diff)
Merge tag 'for-7.3-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linuxHEADmaster
Pull btrfs fixes from David Sterba: - fix command queuing and cleanup in encoded read/write ioctls - fix root and transaction association to avoid unnecessary lock contention and transaction start - properly handle replacing multiple xattrs in the same item - in scrub, fix root reference leak after reporting an unresolved file path * tag 'for-7.3-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix lost error return value in btrfs_listxattr() btrfs: fix xattr replace when multiple xattrs are packed in the same item btrfs: don't stash io_uring encoded data across -EAGAIN btrfs: unlock inode and extent in caller when io_uring read extent fails btrfs: free iov when btrfs_uring_read_extent() fails btrfs: always return -EIOCBQUEUED after btrfs_uring_read_extent_endio btrfs: scrub: fix local_root reference leak in scrub_print_warning_inode() btrfs: clear BTRFS_ROOT_IN_TRANS_SETUP on early exit from record_root_in_trans()
-rw-r--r--fs/btrfs/inode.c7
-rw-r--r--fs/btrfs/ioctl.c31
-rw-r--r--fs/btrfs/scrub.c4
-rw-r--r--fs/btrfs/transaction.c1
-rw-r--r--fs/btrfs/xattr.c15
5 files changed, 34 insertions, 24 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 558b4a3f9633..faf6ed7deb18 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -9623,7 +9623,6 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
struct completion sync_reads;
unsigned long i = 0;
struct btrfs_bio *bbio;
- int ret;
/*
* Fast path for synchronous reads which completes in this call, io_uring
@@ -9670,10 +9669,10 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
if (uring_ctx) {
if (refcount_dec_and_test(&priv->pending_refs)) {
- ret = blk_status_to_errno(READ_ONCE(priv->status));
- btrfs_uring_read_extent_endio(uring_ctx, ret);
+ int error = blk_status_to_errno(READ_ONCE(priv->status));
+
+ btrfs_uring_read_extent_endio(uring_ctx, error);
kfree(priv);
- return ret;
}
return -EIOCBQUEUED;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index e4b2da31a0d5..576cd76ca0bf 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -4601,7 +4601,7 @@ static void btrfs_uring_read_finished(struct io_tw_req tw_req, io_tw_token_t tw)
size_t page_offset;
ssize_t ret;
- /* The inode lock has already been acquired in btrfs_uring_read_extent. */
+ /* The inode lock has already been acquired in btrfs_encoded_read(). */
btrfs_lockdep_inode_acquire(inode, i_rwsem);
if (priv->err) {
@@ -4667,7 +4667,6 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,
struct iovec *iov, struct io_uring_cmd *cmd)
{
struct btrfs_inode *inode = BTRFS_I(file_inode(iocb->ki_filp));
- struct extent_io_tree *io_tree = &inode->io_tree;
struct page **pages = NULL;
struct btrfs_uring_priv *priv = NULL;
unsigned long nr_pages;
@@ -4723,8 +4722,6 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,
return -EIOCBQUEUED;
out_fail:
- btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
- btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
kfree(priv);
for (int i = 0; i < nr_pages; i++) {
if (pages[i])
@@ -4837,7 +4834,7 @@ static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd, unsigned int issue
ret = btrfs_encoded_read(&kiocb, &data->iter, &data->args, &cached_state,
&disk_bytenr, &disk_io_size);
if (ret == -EAGAIN)
- goto out_acct;
+ goto out_free;
if (ret < 0 && ret != -EIOCBQUEUED)
goto out_free;
@@ -4865,8 +4862,10 @@ static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd, unsigned int issue
cached_state, disk_bytenr, disk_io_size,
count, data->args.compression,
data->iov, cmd);
-
- goto out_acct;
+ if (ret == -EIOCBQUEUED)
+ goto out_acct;
+ btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
+ btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
}
out_free:
@@ -4877,8 +4876,10 @@ out_acct:
add_rchar(current, ret);
inc_syscr(current);
- if (ret != -EIOCBQUEUED && ret != -EAGAIN)
+ if (ret != -EIOCBQUEUED) {
kfree(data);
+ bc->data = NULL;
+ }
return ret;
}
@@ -4907,6 +4908,11 @@ static int btrfs_uring_encoded_write(struct io_uring_cmd *cmd, unsigned int issu
goto out_acct;
}
+ if (issue_flags & IO_URING_F_NONBLOCK) {
+ ret = -EAGAIN;
+ goto out_acct;
+ }
+
if (!data) {
data = kzalloc_obj(*data, GFP_NOFS);
if (!data) {
@@ -4975,11 +4981,6 @@ static int btrfs_uring_encoded_write(struct io_uring_cmd *cmd, unsigned int issu
}
}
- if (issue_flags & IO_URING_F_NONBLOCK) {
- ret = -EAGAIN;
- goto out_acct;
- }
-
pos = data->args.offset;
ret = rw_verify_area(WRITE, file, &pos, data->args.len);
if (ret < 0)
@@ -5005,8 +5006,8 @@ out_acct:
add_wchar(current, ret);
inc_syscw(current);
- if (ret != -EAGAIN)
- kfree(data);
+ kfree(data);
+ bc->data = NULL;
return ret;
}
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index c09d4213ad89..479c0e037015 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -536,8 +536,10 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 num_bytes,
}
ret = paths_from_inode(inum, ipath);
- if (ret < 0)
+ if (ret < 0) {
+ btrfs_put_root(local_root);
goto err;
+ }
/*
* we deliberately ignore the bit ipath might have been too small to
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 6802b94ed76f..11b38133f737 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -432,6 +432,7 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
spin_lock(&fs_info->fs_roots_radix_lock);
if (btrfs_get_root_last_trans(root) == trans->transid && !force) {
spin_unlock(&fs_info->fs_roots_radix_lock);
+ clear_bit(BTRFS_ROOT_IN_TRANS_SETUP, &root->state);
return 0;
}
radix_tree_tag_set(&fs_info->fs_roots_radix,
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index ab55d10bd71f..cb001a211f55 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -161,6 +161,7 @@ int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode,
const u16 old_data_len = btrfs_dir_data_len(leaf, di);
const u32 item_size = btrfs_item_size(leaf, slot);
const u32 data_size = sizeof(*di) + name_len + size;
+ unsigned long name_ptr;
unsigned long data_ptr;
char *ptr;
@@ -189,8 +190,16 @@ int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode,
ptr = btrfs_item_ptr(leaf, slot, char);
ptr += btrfs_item_size(leaf, slot) - data_size;
di = (struct btrfs_dir_item *)ptr;
+ memzero_extent_buffer(leaf, (unsigned long)ptr +
+ offsetof(struct btrfs_dir_item, location),
+ sizeof(struct btrfs_disk_key));
+ btrfs_set_dir_flags(leaf, di, BTRFS_FT_XATTR);
+ btrfs_set_dir_transid(leaf, di, trans->transid);
+ btrfs_set_dir_name_len(leaf, di, name_len);
btrfs_set_dir_data_len(leaf, di, size);
+ name_ptr = (unsigned long)(di + 1);
data_ptr = ((unsigned long)(di + 1)) + name_len;
+ write_extent_buffer(leaf, name, name_ptr, name_len);
write_extent_buffer(leaf, value, data_ptr, size);
} else {
/*
@@ -320,10 +329,8 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
if (!size)
goto next;
- if (!buffer || (name_len + 1) > size_left) {
- iter_ret = -ERANGE;
- break;
- }
+ if (!buffer || (name_len + 1) > size_left)
+ return -ERANGE;
read_extent_buffer(leaf, buffer, name_ptr, name_len);
buffer[name_len] = '\0';