]> git.ipfire.org Git - people/ms/linux.git/blobdiff - fs/btrfs/disk-io.c
Merge branch 'for-6.0/dax' into libnvdimm-fixes
[people/ms/linux.git] / fs / btrfs / disk-io.c
index 4ba005c4198368214fb4b055fd15d02af19e3b06..1af28b066b42a1a54c78951de8a0839b6a545532 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/fs.h>
 #include <linux/blkdev.h>
+#include <linux/radix-tree.h>
 #include <linux/writeback.h>
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
@@ -50,7 +51,6 @@
                                 BTRFS_SUPER_FLAG_METADUMP |\
                                 BTRFS_SUPER_FLAG_METADUMP_V2)
 
-static void end_workqueue_fn(struct btrfs_work *work);
 static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
 static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                                      struct btrfs_fs_info *fs_info);
@@ -63,40 +63,6 @@ static int btrfs_destroy_pinned_extent(struct btrfs_fs_info *fs_info,
 static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info);
 static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info);
 
-/*
- * btrfs_end_io_wq structs are used to do processing in task context when an IO
- * is complete.  This is used during reads to verify checksums, and it is used
- * by writes to insert metadata for new file extents after IO is complete.
- */
-struct btrfs_end_io_wq {
-       struct bio *bio;
-       bio_end_io_t *end_io;
-       void *private;
-       struct btrfs_fs_info *info;
-       blk_status_t status;
-       enum btrfs_wq_endio_type metadata;
-       struct btrfs_work work;
-};
-
-static struct kmem_cache *btrfs_end_io_wq_cache;
-
-int __init btrfs_end_io_wq_init(void)
-{
-       btrfs_end_io_wq_cache = kmem_cache_create("btrfs_end_io_wq",
-                                       sizeof(struct btrfs_end_io_wq),
-                                       0,
-                                       SLAB_MEM_SPREAD,
-                                       NULL);
-       if (!btrfs_end_io_wq_cache)
-               return -ENOMEM;
-       return 0;
-}
-
-void __cold btrfs_end_io_wq_exit(void)
-{
-       kmem_cache_destroy(btrfs_end_io_wq_cache);
-}
-
 static void btrfs_free_csum_hash(struct btrfs_fs_info *fs_info)
 {
        if (fs_info->csum_shash)
@@ -120,88 +86,6 @@ struct async_submit_bio {
        blk_status_t status;
 };
 
-/*
- * Lockdep class keys for extent_buffer->lock's in this root.  For a given
- * eb, the lockdep key is determined by the btrfs_root it belongs to and
- * the level the eb occupies in the tree.
- *
- * Different roots are used for different purposes and may nest inside each
- * other and they require separate keysets.  As lockdep keys should be
- * static, assign keysets according to the purpose of the root as indicated
- * by btrfs_root->root_key.objectid.  This ensures that all special purpose
- * roots have separate keysets.
- *
- * Lock-nesting across peer nodes is always done with the immediate parent
- * node locked thus preventing deadlock.  As lockdep doesn't know this, use
- * subclass to avoid triggering lockdep warning in such cases.
- *
- * The key is set by the readpage_end_io_hook after the buffer has passed
- * csum validation but before the pages are unlocked.  It is also set by
- * btrfs_init_new_buffer on freshly allocated blocks.
- *
- * We also add a check to make sure the highest level of the tree is the
- * same as our lockdep setup here.  If BTRFS_MAX_LEVEL changes, this code
- * needs update as well.
- */
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# if BTRFS_MAX_LEVEL != 8
-#  error
-# endif
-
-#define DEFINE_LEVEL(stem, level)                                      \
-       .names[level] = "btrfs-" stem "-0" #level,
-
-#define DEFINE_NAME(stem)                                              \
-       DEFINE_LEVEL(stem, 0)                                           \
-       DEFINE_LEVEL(stem, 1)                                           \
-       DEFINE_LEVEL(stem, 2)                                           \
-       DEFINE_LEVEL(stem, 3)                                           \
-       DEFINE_LEVEL(stem, 4)                                           \
-       DEFINE_LEVEL(stem, 5)                                           \
-       DEFINE_LEVEL(stem, 6)                                           \
-       DEFINE_LEVEL(stem, 7)
-
-static struct btrfs_lockdep_keyset {
-       u64                     id;             /* root objectid */
-       /* Longest entry: btrfs-free-space-00 */
-       char                    names[BTRFS_MAX_LEVEL][20];
-       struct lock_class_key   keys[BTRFS_MAX_LEVEL];
-} btrfs_lockdep_keysets[] = {
-       { .id = BTRFS_ROOT_TREE_OBJECTID,       DEFINE_NAME("root")     },
-       { .id = BTRFS_EXTENT_TREE_OBJECTID,     DEFINE_NAME("extent")   },
-       { .id = BTRFS_CHUNK_TREE_OBJECTID,      DEFINE_NAME("chunk")    },
-       { .id = BTRFS_DEV_TREE_OBJECTID,        DEFINE_NAME("dev")      },
-       { .id = BTRFS_CSUM_TREE_OBJECTID,       DEFINE_NAME("csum")     },
-       { .id = BTRFS_QUOTA_TREE_OBJECTID,      DEFINE_NAME("quota")    },
-       { .id = BTRFS_TREE_LOG_OBJECTID,        DEFINE_NAME("log")      },
-       { .id = BTRFS_TREE_RELOC_OBJECTID,      DEFINE_NAME("treloc")   },
-       { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, DEFINE_NAME("dreloc")   },
-       { .id = BTRFS_UUID_TREE_OBJECTID,       DEFINE_NAME("uuid")     },
-       { .id = BTRFS_FREE_SPACE_TREE_OBJECTID, DEFINE_NAME("free-space") },
-       { .id = 0,                              DEFINE_NAME("tree")     },
-};
-
-#undef DEFINE_LEVEL
-#undef DEFINE_NAME
-
-void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb,
-                                   int level)
-{
-       struct btrfs_lockdep_keyset *ks;
-
-       BUG_ON(level >= ARRAY_SIZE(ks->keys));
-
-       /* find the matching keyset, id 0 is the default entry */
-       for (ks = btrfs_lockdep_keysets; ks->id; ks++)
-               if (ks->id == objectid)
-                       break;
-
-       lockdep_set_class_and_name(&eb->lock,
-                                  &ks->keys[level], ks->names[level]);
-}
-
-#endif
-
 /*
  * Compute the csum of a btree block and store the result to provided buffer.
  */
@@ -255,8 +139,8 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
                goto out;
        }
        btrfs_err_rl(eb->fs_info,
-               "parent transid verify failed on %llu wanted %llu found %llu",
-                       eb->start,
+"parent transid verify failed on logical %llu mirror %u wanted %llu found %llu",
+                       eb->start, eb->read_mirror,
                        parent_transid, btrfs_header_generation(eb));
        ret = 1;
        clear_extent_buffer_uptodate(eb);
@@ -485,7 +369,7 @@ static int csum_dirty_subpage_buffers(struct btrfs_fs_info *fs_info,
                uptodate = btrfs_subpage_test_uptodate(fs_info, page, cur,
                                                       fs_info->nodesize);
 
-               /* A dirty eb shouldn't disappear from extent_buffers */
+               /* A dirty eb shouldn't disappear from buffer_radix */
                if (WARN_ON(!eb))
                        return -EUCLEAN;
 
@@ -586,21 +470,23 @@ static int validate_extent_buffer(struct extent_buffer *eb)
 
        found_start = btrfs_header_bytenr(eb);
        if (found_start != eb->start) {
-               btrfs_err_rl(fs_info, "bad tree block start, want %llu have %llu",
-                            eb->start, found_start);
+               btrfs_err_rl(fs_info,
+                       "bad tree block start, mirror %u want %llu have %llu",
+                            eb->read_mirror, eb->start, found_start);
                ret = -EIO;
                goto out;
        }
        if (check_tree_block_fsid(eb)) {
-               btrfs_err_rl(fs_info, "bad fsid on block %llu",
-                            eb->start);
+               btrfs_err_rl(fs_info, "bad fsid on logical %llu mirror %u",
+                            eb->start, eb->read_mirror);
                ret = -EIO;
                goto out;
        }
        found_level = btrfs_header_level(eb);
        if (found_level >= BTRFS_MAX_LEVEL) {
-               btrfs_err(fs_info, "bad tree block level %d on %llu",
-                         (int)btrfs_header_level(eb), eb->start);
+               btrfs_err(fs_info,
+                       "bad tree block level, mirror %u level %d on logical %llu",
+                       eb->read_mirror, btrfs_header_level(eb), eb->start);
                ret = -EIO;
                goto out;
        }
@@ -611,8 +497,8 @@ static int validate_extent_buffer(struct extent_buffer *eb)
 
        if (memcmp(result, header_csum, csum_size) != 0) {
                btrfs_warn_rl(fs_info,
-       "checksum verify failed on %llu wanted " CSUM_FMT " found " CSUM_FMT " level %d",
-                             eb->start,
+"checksum verify failed on logical %llu mirror %u wanted " CSUM_FMT " found " CSUM_FMT " level %d",
+                             eb->start, eb->read_mirror,
                              CSUM_FMT_VALUE(csum_size, header_csum),
                              CSUM_FMT_VALUE(csum_size, result),
                              btrfs_header_level(eb));
@@ -637,8 +523,8 @@ static int validate_extent_buffer(struct extent_buffer *eb)
                set_extent_buffer_uptodate(eb);
        else
                btrfs_err(fs_info,
-                         "block=%llu read time tree block corruption detected",
-                         eb->start);
+               "read time tree block corruption detected on logical %llu mirror %u",
+                         eb->start, eb->read_mirror);
 out:
        return ret;
 }
@@ -739,58 +625,6 @@ err:
        return ret;
 }
 
-static void end_workqueue_bio(struct bio *bio)
-{
-       struct btrfs_end_io_wq *end_io_wq = bio->bi_private;
-       struct btrfs_fs_info *fs_info;
-       struct btrfs_workqueue *wq;
-
-       fs_info = end_io_wq->info;
-       end_io_wq->status = bio->bi_status;
-
-       if (btrfs_op(bio) == BTRFS_MAP_WRITE) {
-               if (end_io_wq->metadata == BTRFS_WQ_ENDIO_METADATA)
-                       wq = fs_info->endio_meta_write_workers;
-               else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_FREE_SPACE)
-                       wq = fs_info->endio_freespace_worker;
-               else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56)
-                       wq = fs_info->endio_raid56_workers;
-               else
-                       wq = fs_info->endio_write_workers;
-       } else {
-               if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56)
-                       wq = fs_info->endio_raid56_workers;
-               else if (end_io_wq->metadata)
-                       wq = fs_info->endio_meta_workers;
-               else
-                       wq = fs_info->endio_workers;
-       }
-
-       btrfs_init_work(&end_io_wq->work, end_workqueue_fn, NULL, NULL);
-       btrfs_queue_work(wq, &end_io_wq->work);
-}
-
-blk_status_t btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio,
-                       enum btrfs_wq_endio_type metadata)
-{
-       struct btrfs_end_io_wq *end_io_wq;
-
-       end_io_wq = kmem_cache_alloc(btrfs_end_io_wq_cache, GFP_NOFS);
-       if (!end_io_wq)
-               return BLK_STS_RESOURCE;
-
-       end_io_wq->private = bio->bi_private;
-       end_io_wq->end_io = bio->bi_end_io;
-       end_io_wq->info = info;
-       end_io_wq->status = 0;
-       end_io_wq->bio = bio;
-       end_io_wq->metadata = metadata;
-
-       bio->bi_private = end_io_wq;
-       bio->bi_end_io = end_workqueue_bio;
-       return 0;
-}
-
 static void run_one_async_start(struct btrfs_work *work)
 {
        struct async_submit_bio *async;
@@ -815,7 +649,6 @@ static void run_one_async_done(struct btrfs_work *work)
 {
        struct async_submit_bio *async;
        struct inode *inode;
-       blk_status_t ret;
 
        async = container_of(work, struct  async_submit_bio, work);
        inode = async->inode;
@@ -833,11 +666,7 @@ static void run_one_async_done(struct btrfs_work *work)
         * This changes nothing when cgroups aren't in use.
         */
        async->bio->bi_opf |= REQ_CGROUP_PUNT;
-       ret = btrfs_map_bio(btrfs_sb(inode->i_sb), async->bio, async->mirror_num);
-       if (ret) {
-               async->bio->bi_status = ret;
-               bio_endio(async->bio);
-       }
+       btrfs_submit_bio(btrfs_sb(inode->i_sb), async->bio, async->mirror_num);
 }
 
 static void run_one_async_free(struct btrfs_work *work)
@@ -848,16 +677,23 @@ static void run_one_async_free(struct btrfs_work *work)
        kfree(async);
 }
 
-blk_status_t btrfs_wq_submit_bio(struct inode *inode, struct bio *bio,
-                                int mirror_num, u64 dio_file_offset,
-                                extent_submit_bio_start_t *submit_bio_start)
+/*
+ * Submit bio to an async queue.
+ *
+ * Retrun:
+ * - true if the work has been succesfuly submitted
+ * - false in case of error
+ */
+bool btrfs_wq_submit_bio(struct inode *inode, struct bio *bio, int mirror_num,
+                        u64 dio_file_offset,
+                        extent_submit_bio_start_t *submit_bio_start)
 {
        struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
        struct async_submit_bio *async;
 
        async = kmalloc(sizeof(*async), GFP_NOFS);
        if (!async)
-               return BLK_STS_RESOURCE;
+               return false;
 
        async->inode = inode;
        async->bio = bio;
@@ -875,7 +711,7 @@ blk_status_t btrfs_wq_submit_bio(struct inode *inode, struct bio *bio,
                btrfs_queue_work(fs_info->hipri_workers, &async->work);
        else
                btrfs_queue_work(fs_info->workers, &async->work);
-       return 0;
+       return true;
 }
 
 static blk_status_t btree_csum_one_bio(struct bio *bio)
@@ -901,7 +737,7 @@ static blk_status_t btree_submit_bio_start(struct inode *inode, struct bio *bio,
 {
        /*
         * when we're called for a write, we're already in the async
-        * submission context.  Just jump into btrfs_map_bio
+        * submission context.  Just jump into btrfs_submit_bio.
         */
        return btree_csum_one_bio(bio);
 }
@@ -923,57 +759,54 @@ void btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio, int mirror_
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        blk_status_t ret;
 
+       bio->bi_opf |= REQ_META;
+
        if (btrfs_op(bio) != BTRFS_MAP_WRITE) {
-               /*
-                * called for a read, do the setup so that checksum validation
-                * can happen in the async kernel threads
-                */
-               ret = btrfs_bio_wq_end_io(fs_info, bio,
-                                         BTRFS_WQ_ENDIO_METADATA);
-               if (!ret)
-                       ret = btrfs_map_bio(fs_info, bio, mirror_num);
-       } else if (!should_async_write(fs_info, BTRFS_I(inode))) {
-               ret = btree_csum_one_bio(bio);
-               if (!ret)
-                       ret = btrfs_map_bio(fs_info, bio, mirror_num);
-       } else {
-               /*
-                * kthread helpers are used to submit writes so that
-                * checksumming can happen in parallel across all CPUs
-                */
-               ret = btrfs_wq_submit_bio(inode, bio, mirror_num, 0,
-                                         btree_submit_bio_start);
+               btrfs_submit_bio(fs_info, bio, mirror_num);
+               return;
        }
 
+       /*
+        * Kthread helpers are used to submit writes so that checksumming can
+        * happen in parallel across all CPUs.
+        */
+       if (should_async_write(fs_info, BTRFS_I(inode)) &&
+           btrfs_wq_submit_bio(inode, bio, mirror_num, 0, btree_submit_bio_start))
+               return;
+
+       ret = btree_csum_one_bio(bio);
        if (ret) {
                bio->bi_status = ret;
                bio_endio(bio);
+               return;
        }
+
+       btrfs_submit_bio(fs_info, bio, mirror_num);
 }
 
 #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)
 {
@@ -1073,10 +906,8 @@ static const struct address_space_operations btree_aops = {
        .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(
@@ -1158,7 +989,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        root->nr_delalloc_inodes = 0;
        root->nr_ordered_extents = 0;
        root->inode_tree = RB_ROOT;
-       xa_init_flags(&root->delayed_nodes, GFP_ATOMIC);
+       INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC);
 
        btrfs_init_root_block_rsv(root);
 
@@ -1210,9 +1041,9 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        btrfs_qgroup_init_swapped_blocks(&root->swapped_blocks);
 #ifdef CONFIG_BTRFS_DEBUG
        INIT_LIST_HEAD(&root->leak_list);
-       spin_lock(&fs_info->fs_roots_lock);
+       spin_lock(&fs_info->fs_roots_radix_lock);
        list_add_tail(&root->leak_list, &fs_info->allocated_roots);
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 #endif
 }
 
@@ -1659,11 +1490,12 @@ static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
 {
        struct btrfs_root *root;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       root = xa_load(&fs_info->fs_roots, (unsigned long)root_id);
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       root = radix_tree_lookup(&fs_info->fs_roots_radix,
+                                (unsigned long)root_id);
        if (root)
                root = btrfs_grab_root(root);
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        return root;
 }
 
@@ -1705,14 +1537,20 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
 {
        int ret;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       ret = xa_insert(&fs_info->fs_roots, (unsigned long)root->root_key.objectid,
-                       root, GFP_NOFS);
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret)
+               return ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       ret = radix_tree_insert(&fs_info->fs_roots_radix,
+                               (unsigned long)root->root_key.objectid,
+                               root);
        if (ret == 0) {
                btrfs_grab_root(root);
-               set_bit(BTRFS_ROOT_REGISTERED, &root->state);
+               set_bit(BTRFS_ROOT_IN_RADIX, &root->state);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
+       radix_tree_preload_end();
 
        return ret;
 }
@@ -1864,7 +1702,7 @@ again:
 fail:
        /*
         * If our caller provided us an anonymous device, then it's his
-        * responsability to free it in case we fail. So we have to set our
+        * responsibility to free it in case we fail. So we have to set our
         * root's anon_dev to 0 to avoid a double free, once by btrfs_put_root()
         * and once again by our caller.
         */
@@ -1947,25 +1785,6 @@ struct btrfs_root *btrfs_get_fs_root_commit_root(struct btrfs_fs_info *fs_info,
        return root;
 }
 
-/*
- * called by the kthread helper functions to finally call the bio end_io
- * functions.  This is where read checksum verification actually happens
- */
-static void end_workqueue_fn(struct btrfs_work *work)
-{
-       struct bio *bio;
-       struct btrfs_end_io_wq *end_io_wq;
-
-       end_io_wq = container_of(work, struct btrfs_end_io_wq, work);
-       bio = end_io_wq->bio;
-
-       bio->bi_status = end_io_wq->status;
-       bio->bi_private = end_io_wq->private;
-       bio->bi_end_io = end_io_wq->end_io;
-       bio_endio(bio);
-       kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq);
-}
-
 static int cleaner_kthread(void *arg)
 {
        struct btrfs_fs_info *fs_info = arg;
@@ -2272,10 +2091,14 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
        btrfs_destroy_workqueue(fs_info->delalloc_workers);
        btrfs_destroy_workqueue(fs_info->hipri_workers);
        btrfs_destroy_workqueue(fs_info->workers);
-       btrfs_destroy_workqueue(fs_info->endio_workers);
-       btrfs_destroy_workqueue(fs_info->endio_raid56_workers);
+       if (fs_info->endio_workers)
+               destroy_workqueue(fs_info->endio_workers);
+       if (fs_info->endio_raid56_workers)
+               destroy_workqueue(fs_info->endio_raid56_workers);
        if (fs_info->rmw_workers)
                destroy_workqueue(fs_info->rmw_workers);
+       if (fs_info->compressed_write_workers)
+               destroy_workqueue(fs_info->compressed_write_workers);
        btrfs_destroy_workqueue(fs_info->endio_write_workers);
        btrfs_destroy_workqueue(fs_info->endio_freespace_worker);
        btrfs_destroy_workqueue(fs_info->delayed_workers);
@@ -2289,8 +2112,8 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
         * the queues used for metadata I/O, since tasks from those other work
         * queues can do metadata I/O operations.
         */
-       btrfs_destroy_workqueue(fs_info->endio_meta_workers);
-       btrfs_destroy_workqueue(fs_info->endio_meta_write_workers);
+       if (fs_info->endio_meta_workers)
+               destroy_workqueue(fs_info->endio_meta_workers);
 }
 
 static void free_root_extent_buffers(struct btrfs_root *root)
@@ -2342,9 +2165,9 @@ void btrfs_put_root(struct btrfs_root *root)
                btrfs_drew_lock_destroy(&root->snapshot_lock);
                free_root_extent_buffers(root);
 #ifdef CONFIG_BTRFS_DEBUG
-               spin_lock(&root->fs_info->fs_roots_lock);
+               spin_lock(&root->fs_info->fs_roots_radix_lock);
                list_del_init(&root->leak_list);
-               spin_unlock(&root->fs_info->fs_roots_lock);
+               spin_unlock(&root->fs_info->fs_roots_radix_lock);
 #endif
                kfree(root);
        }
@@ -2352,21 +2175,28 @@ void btrfs_put_root(struct btrfs_root *root)
 
 void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *root;
-       unsigned long index = 0;
+       int ret;
+       struct btrfs_root *gang[8];
+       int i;
 
        while (!list_empty(&fs_info->dead_roots)) {
-               root = list_entry(fs_info->dead_roots.next,
-                                 struct btrfs_root, root_list);
-               list_del(&root->root_list);
+               gang[0] = list_entry(fs_info->dead_roots.next,
+                                    struct btrfs_root, root_list);
+               list_del(&gang[0]->root_list);
 
-               if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
-                       btrfs_drop_and_free_fs_root(fs_info, root);
-               btrfs_put_root(root);
+               if (test_bit(BTRFS_ROOT_IN_RADIX, &gang[0]->state))
+                       btrfs_drop_and_free_fs_root(fs_info, gang[0]);
+               btrfs_put_root(gang[0]);
        }
 
-       xa_for_each(&fs_info->fs_roots, index, root) {
-               btrfs_drop_and_free_fs_root(fs_info, root);
+       while (1) {
+               ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, 0,
+                                            ARRAY_SIZE(gang));
+               if (!ret)
+                       break;
+               for (i = 0; i < ret; i++)
+                       btrfs_drop_and_free_fs_root(fs_info, gang[i]);
        }
 }
 
@@ -2413,7 +2243,9 @@ static void btrfs_init_btree_inode(struct btrfs_fs_info *fs_info)
        extent_map_tree_init(&BTRFS_I(inode)->extent_tree);
 
        BTRFS_I(inode)->root = btrfs_grab_root(fs_info->tree_root);
-       memset(&BTRFS_I(inode)->location, 0, sizeof(struct btrfs_key));
+       BTRFS_I(inode)->location.objectid = BTRFS_BTREE_INODE_OBJECTID;
+       BTRFS_I(inode)->location.type = 0;
+       BTRFS_I(inode)->location.offset = 0;
        set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags);
        btrfs_insert_inode_hash(inode);
 }
@@ -2462,25 +2294,18 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
        fs_info->fixup_workers =
                btrfs_alloc_workqueue(fs_info, "fixup", flags, 1, 0);
 
-       /*
-        * endios are largely parallel and should have a very
-        * low idle thresh
-        */
        fs_info->endio_workers =
-               btrfs_alloc_workqueue(fs_info, "endio", flags, max_active, 4);
+               alloc_workqueue("btrfs-endio", flags, max_active);
        fs_info->endio_meta_workers =
-               btrfs_alloc_workqueue(fs_info, "endio-meta", flags,
-                                     max_active, 4);
-       fs_info->endio_meta_write_workers =
-               btrfs_alloc_workqueue(fs_info, "endio-meta-write", flags,
-                                     max_active, 2);
+               alloc_workqueue("btrfs-endio-meta", flags, max_active);
        fs_info->endio_raid56_workers =
-               btrfs_alloc_workqueue(fs_info, "endio-raid56", flags,
-                                     max_active, 4);
+               alloc_workqueue("btrfs-endio-raid56", flags, max_active);
        fs_info->rmw_workers = alloc_workqueue("btrfs-rmw", flags, max_active);
        fs_info->endio_write_workers =
                btrfs_alloc_workqueue(fs_info, "endio-write", flags,
                                      max_active, 2);
+       fs_info->compressed_write_workers =
+               alloc_workqueue("btrfs-compressed-write", flags, max_active);
        fs_info->endio_freespace_worker =
                btrfs_alloc_workqueue(fs_info, "freespace-write", flags,
                                      max_active, 0);
@@ -2495,7 +2320,7 @@ static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info)
        if (!(fs_info->workers && fs_info->hipri_workers &&
              fs_info->delalloc_workers && fs_info->flush_workers &&
              fs_info->endio_workers && fs_info->endio_meta_workers &&
-             fs_info->endio_meta_write_workers &&
+             fs_info->compressed_write_workers &&
              fs_info->endio_write_workers && fs_info->endio_raid56_workers &&
              fs_info->endio_freespace_worker && fs_info->rmw_workers &&
              fs_info->caching_workers && fs_info->fixup_workers &&
@@ -2522,6 +2347,9 @@ static int btrfs_init_csum_hash(struct btrfs_fs_info *fs_info, u16 csum_type)
 
        fs_info->csum_shash = csum_shash;
 
+       btrfs_info(fs_info, "using %s (%s) checksum algorithm",
+                       btrfs_super_csum_name(csum_type),
+                       crypto_shash_driver_name(csum_shash));
        return 0;
 }
 
@@ -3134,8 +2962,8 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
 
 void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
 {
-       xa_init_flags(&fs_info->fs_roots, GFP_ATOMIC);
-       xa_init_flags(&fs_info->extent_buffers, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
        INIT_LIST_HEAD(&fs_info->trans_list);
        INIT_LIST_HEAD(&fs_info->dead_roots);
        INIT_LIST_HEAD(&fs_info->delayed_iputs);
@@ -3143,7 +2971,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        INIT_LIST_HEAD(&fs_info->caching_block_groups);
        spin_lock_init(&fs_info->delalloc_root_lock);
        spin_lock_init(&fs_info->trans_lock);
-       spin_lock_init(&fs_info->fs_roots_lock);
+       spin_lock_init(&fs_info->fs_roots_radix_lock);
        spin_lock_init(&fs_info->delayed_iput_lock);
        spin_lock_init(&fs_info->defrag_inodes_lock);
        spin_lock_init(&fs_info->super_lock);
@@ -3247,6 +3075,8 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        fs_info->sectorsize_bits = ilog2(4096);
        fs_info->stripesize = 4096;
 
+       fs_info->max_extent_size = BTRFS_MAX_EXTENT_SIZE;
+
        spin_lock_init(&fs_info->swapfile_pins_lock);
        fs_info->swapfile_pins = RB_ROOT;
 
@@ -3374,7 +3204,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
        /*
         * btrfs_find_orphan_roots() is responsible for finding all the dead
         * roots (with 0 refs), flag them with BTRFS_ROOT_DEAD_TREE and load
-        * them into the fs_info->fs_roots. This must be done before
+        * them into the fs_info->fs_roots_radix tree. This must be done before
         * calling btrfs_orphan_cleanup() on the tree root. If we don't do it
         * first, then btrfs_orphan_cleanup() will delete a dead root's orphan
         * item before the root's tree is deleted - this means that if we unmount
@@ -3578,16 +3408,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
         */
        fs_info->compress_type = BTRFS_COMPRESS_ZLIB;
 
-       /*
-        * Flag our filesystem as having big metadata blocks if they are bigger
-        * than the page size.
-        */
-       if (btrfs_super_nodesize(disk_super) > PAGE_SIZE) {
-               if (!(features & BTRFS_FEATURE_INCOMPAT_BIG_METADATA))
-                       btrfs_info(fs_info,
-                               "flagging fs with big metadata feature");
-               features |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA;
-       }
 
        /* Set up fs_info before parsing mount options */
        nodesize = btrfs_super_nodesize(disk_super);
@@ -3625,8 +3445,12 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
        else if (fs_info->compress_type == BTRFS_COMPRESS_ZSTD)
                features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD;
 
-       if (features & BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA)
-               btrfs_info(fs_info, "has skinny extents");
+       /*
+        * Flag our filesystem as having big metadata blocks if they are bigger
+        * than the page size.
+        */
+       if (btrfs_super_nodesize(disk_super) > PAGE_SIZE)
+               features |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA;
 
        /*
         * mixed block groups end up with duplicate but slightly offset
@@ -3655,6 +3479,20 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
                err = -EINVAL;
                goto fail_alloc;
        }
+       /*
+        * We have unsupported RO compat features, although RO mounted, we
+        * should not cause any metadata write, including log replay.
+        * Or we could screw up whatever the new feature requires.
+        */
+       if (unlikely(features && btrfs_super_log_root(disk_super) &&
+                    !btrfs_test_opt(fs_info, NOLOGREPLAY))) {
+               btrfs_err(fs_info,
+"cannot replay dirty log with unsupported compat_ro features (0x%llx), try rescue=nologreplay",
+                         features);
+               err = -EINVAL;
+               goto fail_alloc;
+       }
+
 
        if (sectorsize < PAGE_SIZE) {
                struct btrfs_subpage_info *subpage_info;
@@ -4499,11 +4337,12 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 {
        bool drop_ref = false;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       xa_erase(&fs_info->fs_roots, (unsigned long)root->root_key.objectid);
-       if (test_and_clear_bit(BTRFS_ROOT_REGISTERED, &root->state))
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       radix_tree_delete(&fs_info->fs_roots_radix,
+                         (unsigned long)root->root_key.objectid);
+       if (test_and_clear_bit(BTRFS_ROOT_IN_RADIX, &root->state))
                drop_ref = true;
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 
        if (BTRFS_FS_ERROR(fs_info)) {
                ASSERT(root->log_root == NULL);
@@ -4519,48 +4358,50 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *roots[8];
-       unsigned long index = 0;
-       int i;
+       u64 root_objectid = 0;
+       struct btrfs_root *gang[8];
+       int i = 0;
        int err = 0;
-       int grabbed;
+       unsigned int ret = 0;
 
        while (1) {
-               struct btrfs_root *root;
-
-               spin_lock(&fs_info->fs_roots_lock);
-               if (!xa_find(&fs_info->fs_roots, &index, ULONG_MAX, XA_PRESENT)) {
-                       spin_unlock(&fs_info->fs_roots_lock);
-                       return err;
+               spin_lock(&fs_info->fs_roots_radix_lock);
+               ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, root_objectid,
+                                            ARRAY_SIZE(gang));
+               if (!ret) {
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
+                       break;
                }
+               root_objectid = gang[ret - 1]->root_key.objectid + 1;
 
-               grabbed = 0;
-               xa_for_each_start(&fs_info->fs_roots, index, root, index) {
-                       /* Avoid grabbing roots in dead_roots */
-                       if (btrfs_root_refs(&root->root_item) > 0)
-                               roots[grabbed++] = btrfs_grab_root(root);
-                       if (grabbed >= ARRAY_SIZE(roots))
-                               break;
+               for (i = 0; i < ret; i++) {
+                       /* Avoid to grab roots in dead_roots */
+                       if (btrfs_root_refs(&gang[i]->root_item) == 0) {
+                               gang[i] = NULL;
+                               continue;
+                       }
+                       /* grab all the search result for later use */
+                       gang[i] = btrfs_grab_root(gang[i]);
                }
-               spin_unlock(&fs_info->fs_roots_lock);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
 
-               for (i = 0; i < grabbed; i++) {
-                       if (!roots[i])
+               for (i = 0; i < ret; i++) {
+                       if (!gang[i])
                                continue;
-                       index = roots[i]->root_key.objectid;
-                       err = btrfs_orphan_cleanup(roots[i]);
+                       root_objectid = gang[i]->root_key.objectid;
+                       err = btrfs_orphan_cleanup(gang[i]);
                        if (err)
-                               goto out;
-                       btrfs_put_root(roots[i]);
+                               break;
+                       btrfs_put_root(gang[i]);
                }
-               index++;
+               root_objectid++;
        }
 
-out:
-       /* Release the roots that remain uncleaned due to error */
-       for (; i < grabbed; i++) {
-               if (roots[i])
-                       btrfs_put_root(roots[i]);
+       /* release the uncleaned roots due to error */
+       for (; i < ret; i++) {
+               if (gang[i])
+                       btrfs_put_root(gang[i]);
        }
        return err;
 }
@@ -4879,28 +4720,31 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
 
 static void btrfs_drop_all_logs(struct btrfs_fs_info *fs_info)
 {
-       unsigned long index = 0;
-       int grabbed = 0;
-       struct btrfs_root *roots[8];
+       struct btrfs_root *gang[8];
+       u64 root_objectid = 0;
+       int ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       while ((ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, root_objectid,
+                                            ARRAY_SIZE(gang))) != 0) {
+               int i;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       while ((grabbed = xa_extract(&fs_info->fs_roots, (void **)roots, index,
-                                    ULONG_MAX, 8, XA_PRESENT))) {
-               for (int i = 0; i < grabbed; i++)
-                       roots[i] = btrfs_grab_root(roots[i]);
-               spin_unlock(&fs_info->fs_roots_lock);
+               for (i = 0; i < ret; i++)
+                       gang[i] = btrfs_grab_root(gang[i]);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
 
-               for (int i = 0; i < grabbed; i++) {
-                       if (!roots[i])
+               for (i = 0; i < ret; i++) {
+                       if (!gang[i])
                                continue;
-                       index = roots[i]->root_key.objectid;
-                       btrfs_free_log(NULL, roots[i]);
-                       btrfs_put_root(roots[i]);
+                       root_objectid = gang[i]->root_key.objectid;
+                       btrfs_free_log(NULL, gang[i]);
+                       btrfs_put_root(gang[i]);
                }
-               index++;
-               spin_lock(&fs_info->fs_roots_lock);
+               root_objectid++;
+               spin_lock(&fs_info->fs_roots_radix_lock);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        btrfs_free_log_root_tree(NULL, fs_info);
 }