Merge tag 'for-6.0-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 20 Sep 2022 17:23:24 +0000 (10:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 20 Sep 2022 17:23:24 +0000 (10:23 -0700)
Pull btrfs fixes from David Sterba:

 - two fixes for hangs in the umount sequence where threads depend on
   each other and the work must be finished in the right order

 - in zoned mode, wait for flushing all block group metadata IO before
   finishing the zone

* tag 'for-6.0-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: zoned: wait for extent buffer IOs before finishing a zone
  btrfs: fix hang during unmount when stopping a space reclaim worker
  btrfs: fix hang during unmount when stopping block group reclaim worker

1  2 
fs/btrfs/disk-io.c

diff --combined fs/btrfs/disk-io.c
index 1af28b066b42a1a54c78951de8a0839b6a545532,28ba93d4cf232a16d7ecb2beb8b0f4b35b93b40a..2633137c3e9f1efc4d07bd262152104a3633e32a
@@@ -785,28 -785,28 +785,28 @@@ void btrfs_submit_metadata_bio(struct i
  }
  
  #ifdef CONFIG_MIGRATION
 -static int btree_migratepage(struct address_space *mapping,
 -                      struct page *newpage, struct page *page,
 -                      enum migrate_mode mode)
 +static int btree_migrate_folio(struct address_space *mapping,
 +              struct folio *dst, struct folio *src, enum migrate_mode mode)
  {
        /*
         * we can't safely write a btree page from here,
         * we haven't done the locking hook
         */
 -      if (PageDirty(page))
 +      if (folio_test_dirty(src))
                return -EAGAIN;
        /*
         * Buffers may be managed in a filesystem specific way.
         * We must have no buffers or drop them.
         */
 -      if (page_has_private(page) &&
 -          !try_to_release_page(page, GFP_KERNEL))
 +      if (folio_get_private(src) &&
 +          !filemap_release_folio(src, GFP_KERNEL))
                return -EAGAIN;
 -      return migrate_page(mapping, newpage, page, mode);
 +      return migrate_folio(mapping, dst, src, mode);
  }
 +#else
 +#define btree_migrate_folio NULL
  #endif
  
 -
  static int btree_writepages(struct address_space *mapping,
                            struct writeback_control *wbc)
  {
@@@ -906,8 -906,10 +906,8 @@@ static const struct address_space_opera
        .writepages     = btree_writepages,
        .release_folio  = btree_release_folio,
        .invalidate_folio = btree_invalidate_folio,
 -#ifdef CONFIG_MIGRATION
 -      .migratepage    = btree_migratepage,
 -#endif
 -      .dirty_folio = btree_dirty_folio,
 +      .migrate_folio  = btree_migrate_folio,
 +      .dirty_folio    = btree_dirty_folio,
  };
  
  struct extent_buffer *btrfs_find_create_tree_block(
@@@ -4474,6 -4476,17 +4474,17 @@@ void __cold close_ctree(struct btrfs_fs
  
        set_bit(BTRFS_FS_CLOSING_START, &fs_info->flags);
  
+       /*
+        * If we had UNFINISHED_DROPS we could still be processing them, so
+        * clear that bit and wake up relocation so it can stop.
+        * We must do this before stopping the block group reclaim task, because
+        * at btrfs_relocate_block_group() we wait for this bit, and after the
+        * wait we stop with -EINTR if btrfs_fs_closing() returns non-zero - we
+        * have just set BTRFS_FS_CLOSING_START, so btrfs_fs_closing() will
+        * return 1.
+        */
+       btrfs_wake_unfinished_drop(fs_info);
        /*
         * We may have the reclaim task running and relocating a data block group,
         * in which case it may create delayed iputs. So stop it before we park
         */
        kthread_park(fs_info->cleaner_kthread);
  
-       /*
-        * If we had UNFINISHED_DROPS we could still be processing them, so
-        * clear that bit and wake up relocation so it can stop.
-        */
-       btrfs_wake_unfinished_drop(fs_info);
        /* wait for the qgroup rescan worker to stop */
        btrfs_qgroup_wait_for_completion(fs_info, false);
  
        /* clear out the rbtree of defraggable inodes */
        btrfs_cleanup_defrag_inodes(fs_info);
  
+       /*
+        * After we parked the cleaner kthread, ordered extents may have
+        * completed and created new delayed iputs. If one of the async reclaim
+        * tasks is running and in the RUN_DELAYED_IPUTS flush state, then we
+        * can hang forever trying to stop it, because if a delayed iput is
+        * added after it ran btrfs_run_delayed_iputs() and before it called
+        * btrfs_wait_on_delayed_iputs(), it will hang forever since there is
+        * no one else to run iputs.
+        *
+        * So wait for all ongoing ordered extents to complete and then run
+        * delayed iputs. This works because once we reach this point no one
+        * can either create new ordered extents nor create delayed iputs
+        * through some other means.
+        *
+        * Also note that btrfs_wait_ordered_roots() is not safe here, because
+        * it waits for BTRFS_ORDERED_COMPLETE to be set on an ordered extent,
+        * but the delayed iput for the respective inode is made only when doing
+        * the final btrfs_put_ordered_extent() (which must happen at
+        * btrfs_finish_ordered_io() when we are unmounting).
+        */
+       btrfs_flush_workqueue(fs_info->endio_write_workers);
+       /* Ordered extents for free space inodes. */
+       btrfs_flush_workqueue(fs_info->endio_freespace_worker);
+       btrfs_run_delayed_iputs(fs_info);
        cancel_work_sync(&fs_info->async_reclaim_work);
        cancel_work_sync(&fs_info->async_data_reclaim_work);
        cancel_work_sync(&fs_info->preempt_reclaim_work);