]> Git Repo - J-linux.git/commitdiff
Merge tag 'for-6.13-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <[email protected]>
Tue, 3 Dec 2024 19:02:17 +0000 (11:02 -0800)
committerLinus Torvalds <[email protected]>
Tue, 3 Dec 2024 19:02:17 +0000 (11:02 -0800)
Pull btrfs fixes from David Sterba:

 - add lockdep annotations for io_uring/encoded read integration, inode
   lock is held when returning to userspace

 - properly reflect experimental config option to sysfs

 - handle NULL root in case the rescue mode accepts invalid/damaged tree
   roots (rescue=ibadroot)

 - regression fix of a deadlock between transaction and extent locks

 - fix pending bio accounting bug in encoded read ioctl

 - fix NOWAIT mode when checking references for NOCOW files

 - fix use-after-free in a rb-tree cleanup in ref-verify debugging tool

* tag 'for-6.13-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: fix lockdep warnings on io_uring encoded reads
  btrfs: ref-verify: fix use-after-free after invalid ref action
  btrfs: add a sanity check for btrfs root in btrfs_search_slot()
  btrfs: don't loop for nowait writes when checking for cross references
  btrfs: sysfs: advertise experimental features only if CONFIG_BTRFS_EXPERIMENTAL=y
  btrfs: fix deadlock between transaction commits and extent locks
  btrfs: fix use-after-free in btrfs_encoded_read_endio()

1  2 
fs/btrfs/inode.c
fs/btrfs/ioctl.c

diff --combined fs/btrfs/inode.c
index 03fe0de2cd0dd137f7841f7ff134d14af22be2c1,659a5940a5b2ba91870652056e34a905230213d2..fa648ab6fe80664212fb27db58a7a89e567a7519
@@@ -1481,7 -1481,7 +1481,7 @@@ static noinline int cow_file_range(stru
                 * (which the caller expects to stay locked), don't clear any
                 * dirty bits and don't set any writeback bits
                 *
 -               * Do set the Ordered (Private2) bit so we know this page was
 +               * Do set the Ordered flag so we know this page was
                 * properly setup for writepage.
                 */
                page_ops = (keep_locked ? 0 : PAGE_UNLOCK);
@@@ -1698,7 -1698,7 +1698,7 @@@ static bool run_delalloc_compressed(str
                         * need full accuracy.  Just account the whole thing
                         * against the first page.
                         */
 -                      wbc_account_cgroup_owner(wbc, &locked_folio->page,
 +                      wbc_account_cgroup_owner(wbc, locked_folio,
                                                 cur_end - start);
                        async_chunk[i].locked_folio = locked_folio;
                        locked_folio = NULL;
@@@ -3063,6 -3063,19 +3063,19 @@@ int btrfs_finish_one_ordered(struct btr
                        goto out;
        }
  
+       /*
+        * If it's a COW write we need to lock the extent range as we will be
+        * inserting/replacing file extent items and unpinning an extent map.
+        * This must be taken before joining a transaction, as it's a higher
+        * level lock (like the inode's VFS lock), otherwise we can run into an
+        * ABBA deadlock with other tasks (transactions work like a lock,
+        * depending on their current state).
+        */
+       if (!test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
+               clear_bits |= EXTENT_LOCKED;
+               lock_extent(io_tree, start, end, &cached_state);
+       }
        if (freespace_inode)
                trans = btrfs_join_transaction_spacecache(root);
        else
                goto out;
        }
  
-       clear_bits |= EXTENT_LOCKED;
-       lock_extent(io_tree, start, end, &cached_state);
        if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
                compress_type = ordered_extent->compress_type;
        if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
@@@ -7274,7 -7284,7 +7284,7 @@@ static void btrfs_invalidate_folio(stru
         *
         * But already submitted bio can still be finished on this folio.
         * Furthermore, endio function won't skip folio which has Ordered
 -       * (Private2) already cleared, so it's possible for endio and
 +       * already cleared, so it's possible for endio and
         * invalidate_folio to do the same ordered extent accounting twice
         * on one folio.
         *
                range_len = range_end + 1 - cur;
                if (!btrfs_folio_test_ordered(fs_info, folio, cur, range_len)) {
                        /*
 -                       * If Ordered (Private2) is cleared, it means endio has
 +                       * If Ordered is cleared, it means endio has
                         * already been executed for the range.
                         * We can't delete the extent states as
                         * btrfs_finish_ordered_io() may still use some of them.
@@@ -7413,7 -7423,7 +7423,7 @@@ next
        }
        /*
         * We have iterated through all ordered extents of the page, the page
 -       * should not have Ordered (Private2) anymore, or the above iteration
 +       * should not have Ordered anymore, or the above iteration
         * did something wrong.
         */
        ASSERT(!folio_test_ordered(folio));
@@@ -9089,7 -9099,7 +9099,7 @@@ static void btrfs_encoded_read_endio(st
                 */
                WRITE_ONCE(priv->status, bbio->bio.bi_status);
        }
-       if (atomic_dec_return(&priv->pending) == 0) {
+       if (atomic_dec_and_test(&priv->pending)) {
                int err = blk_status_to_errno(READ_ONCE(priv->status));
  
                if (priv->uring_ctx) {
diff --combined fs/btrfs/ioctl.c
index c9302d1931870dca5916ac66b218eeb28a4357ff,f8680e7cc974f9fda3c5c19b9ff96352401526df..3af8bb0c8d75d79a74abcd36891f6aa2dd57dcac
@@@ -1306,9 -1306,9 +1306,9 @@@ static noinline int __btrfs_ioctl_snap_
                ret = btrfs_mksubvol(&file->f_path, idmap, name,
                                     namelen, NULL, readonly, inherit);
        } else {
 -              struct fd src = fdget(fd);
 +              CLASS(fd, src)(fd);
                struct inode *src_inode;
 -              if (!fd_file(src)) {
 +              if (fd_empty(src)) {
                        ret = -EINVAL;
                        goto out_drop_write;
                }
                                               BTRFS_I(src_inode)->root,
                                               readonly, inherit);
                }
 -              fdput(src);
        }
  out_drop_write:
        mnt_drop_write_file(file);
@@@ -4751,6 -4752,9 +4751,9 @@@ static void btrfs_uring_read_finished(s
        size_t page_offset;
        ssize_t ret;
  
+       /* The inode lock has already been acquired in btrfs_uring_read_extent.  */
+       btrfs_lockdep_inode_acquire(inode, i_rwsem);
        if (priv->err) {
                ret = priv->err;
                goto out;
@@@ -4859,6 -4863,13 +4862,13 @@@ static int btrfs_uring_read_extent(stru
         * and inode and freeing the allocations.
         */
  
+       /*
+        * We're returning to userspace with the inode lock held, and that's
+        * okay - it'll get unlocked in a worker thread.  Call
+        * btrfs_lockdep_inode_release() to avoid confusing lockdep.
+        */
+       btrfs_lockdep_inode_release(inode, i_rwsem);
        return -EIOCBQUEUED;
  
  out_fail:
This page took 0.086218 seconds and 4 git commands to generate.