]> git.hungrycats.org Git - linux/commitdiff
btrfs: unlock inode and extent in caller when uring read extent fails
authorYang Xiuwei <yangxiuwei@kylinos.cn>
Wed, 19 Aug 2026 02:54:34 +0000 (10:54 +0800)
committerDavid Sterba <dsterba@suse.com>
Thu, 17 Sep 2026 17:48:19 +0000 (19:48 +0200)
btrfs_uring_read_extent() runs only after btrfs_encoded_read() has
taken the inode shared lock and the extent lock.  On failure it used to
unlock in out_fail, and a pages-array allocation failure returned
-ENOMEM without unlocking at all.

Unlock in the caller instead on all failure returns, matching the
copy_to_user() error path.  The deferred -EIOCBQUEUED path still unlocks
in btrfs_uring_read_finished().

Fixes: 34310c442e17 ("btrfs: add io_uring command for encoded reads (ENCODED_READ ioctl)")
Suggested-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ioctl.c

index 64ccfa5fefdabf99f60a8b80aebce36e14519eb4..588c25d1968879d6c21013d03896afcbba814adb 100644 (file)
@@ -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])
@@ -4867,6 +4864,8 @@ static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd, unsigned int issue
                                              data->iov, cmd);
                if (ret == -EIOCBQUEUED)
                        goto out_acct;
+               btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
+               btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
        }
 
 out_free: