#include <linux/debugfs.h>
 
+static void promote_obj_to_text(struct printbuf *out, void *obj)
+{
+       bch2_promote_op_to_text(out, obj);
+}
+
+static void rbio_obj_to_text(struct printbuf *out, void *obj)
+{
+       bch2_read_bio_to_text(out, obj);
+}
+
+static void btree_read_bio_obj_to_text(struct printbuf *out, void *obj)
+{
+       struct btree_read_bio *rbio = obj;
+       bch2_btree_read_bio_to_text(out, rbio);
+}
+
+static void btree_write_bio_obj_to_text(struct printbuf *out, void *obj)
+{
+       struct btree_write_bio *wbio = obj;
+       bch2_bio_to_text(out, &wbio->wbio.bio);
+}
+
 static int bch2_async_obj_list_open(struct inode *inode, struct file *file)
 {
        struct async_obj_list *list = inode->i_private;
        return ret ?: i->ret;
 }
 
-__maybe_unused
 static const struct file_operations async_obj_ops = {
        .owner          = THIS_MODULE,
        .open           = bch2_async_obj_list_open,
 
 #ifndef _BCACHEFS_ASYNC_OBJS_TYPES_H
 #define _BCACHEFS_ASYNC_OBJS_TYPES_H
 
-#define BCH_ASYNC_OBJ_LISTS()
+#define BCH_ASYNC_OBJ_LISTS()                                          \
+       x(promote)                                                      \
+       x(rbio)                                                         \
+       x(btree_read_bio)                                               \
+       x(btree_write_bio)
 
 enum bch_async_obj_lists {
 #define x(n)           BCH_ASYNC_OBJ_LIST_##n,
 
 // SPDX-License-Identifier: GPL-2.0
 
 #include "bcachefs.h"
+#include "async_objs.h"
 #include "bkey_buf.h"
 #include "bkey_methods.h"
 #include "bkey_sort.h"
                }
        }
 
+       async_object_list_del(c, btree_read_bio, rb->list_idx);
        bch2_time_stats_update(&c->times[BCH_TIME_btree_node_read],
                               rb->start_time);
        bio_put(&rb->bio);
        queue_work(c->btree_read_complete_wq, &rb->work);
 }
 
+void bch2_btree_read_bio_to_text(struct printbuf *out, struct btree_read_bio *rbio)
+{
+       bch2_bio_to_text(out, &rbio->bio);
+}
+
 struct btree_node_read_all {
        struct closure          cl;
        struct bch_fs           *c;
        bio->bi_end_io          = btree_node_read_endio;
        bch2_bio_map(bio, b->data, btree_buf_bytes(b));
 
+       async_object_list_add(c, btree_read_bio, rb, &rb->list_idx);
+
        if (rb->have_ioref) {
                this_cpu_add(ca->io_done->sectors[READ][BCH_DATA_btree],
                             bio_sectors(bio));
                        goto err;
        }
 out:
+       async_object_list_del(c, btree_write_bio, wbio->list_idx);
        bio_put(&wbio->wbio.bio);
        btree_node_write_done(c, b, start_time);
        return;
        atomic64_inc(&c->btree_write_stats[type].nr);
        atomic64_add(bytes_to_write, &c->btree_write_stats[type].bytes);
 
+       async_object_list_add(c, btree_write_bio, wbio, &wbio->list_idx);
+
        INIT_WORK(&wbio->work, btree_write_submit);
        queue_work(c->btree_write_submit_wq, &wbio->work);
        return;
 
        u64                     start_time;
        unsigned                have_ioref:1;
        unsigned                idx:7;
+#ifdef CONFIG_BCACHEFS_ASYNC_OBJECT_LISTS
+       unsigned                list_idx;
+#endif
        struct extent_ptr_decoded       pick;
        struct work_struct      work;
        struct bio              bio;
        unsigned                data_bytes;
        unsigned                sector_offset;
        u64                     start_time;
+#ifdef CONFIG_BCACHEFS_ASYNC_OBJECT_LISTS
+       unsigned                list_idx;
+#endif
        struct bch_write_bio    wbio;
 };
 
 int bch2_btree_root_read(struct bch_fs *, enum btree_id,
                         const struct bkey_i *, unsigned);
 
+void bch2_btree_read_bio_to_text(struct printbuf *, struct btree_read_bio *);
+
 int bch2_btree_node_scrub(struct btree_trans *, enum btree_id, unsigned,
                          struct bkey_s_c, unsigned);
 
 
        struct bio_vec          *bvecs;
 };
 
+struct promote_op {
+       struct rcu_head         rcu;
+       u64                     start_time;
+#ifdef CONFIG_BCACHEFS_ASYNC_OBJECT_LISTS
+       unsigned                list_idx;
+#endif
+
+       struct rhash_head       hash;
+       struct bpos             pos;
+
+       struct work_struct      work;
+       struct data_update      write;
+       struct bio_vec          bi_inline_vecs[]; /* must be last */
+};
+
 void bch2_data_update_to_text(struct printbuf *, struct data_update *);
 void bch2_data_update_inflight_to_text(struct printbuf *, struct data_update *);
 
 
 #include "bcachefs.h"
 #include "alloc_background.h"
 #include "alloc_foreground.h"
+#include "async_objs.h"
 #include "btree_update.h"
 #include "buckets.h"
 #include "checksum.h"
 
 /* Cache promotion on read */
 
-struct promote_op {
-       struct rcu_head         rcu;
-       u64                     start_time;
-
-       struct rhash_head       hash;
-       struct bpos             pos;
-
-       struct work_struct      work;
-       struct data_update      write;
-       struct bio_vec          bi_inline_vecs[]; /* must be last */
-};
-
 static const struct rhashtable_params bch_promote_params = {
        .head_offset            = offsetof(struct promote_op, hash),
        .key_offset             = offsetof(struct promote_op, pos),
                                         bch_promote_params);
        BUG_ON(ret);
 
+       async_object_list_del(c, promote, op->list_idx);
+
        bch2_data_update_exit(&op->write);
 
        enumerated_ref_put(&c->writes, BCH_WRITE_REF_promote);
                goto err;
        }
 
+       ret = async_object_list_add(c, promote, op, &op->list_idx);
+       if (ret < 0)
+               goto err_remove_hash;
+
        ret = bch2_data_update_init(trans, NULL, NULL, &op->write,
                        writepoint_hashed((unsigned long) current),
                        &orig->opts,
         * -BCH_ERR_ENOSPC_disk_reservation:
         */
        if (ret)
-               goto err_remove_hash;
+               goto err_remove_list;
 
        rbio_init_fragment(&op->write.rbio.bio, orig);
        op->write.rbio.bounce   = true;
        op->write.op.end_io = promote_done;
 
        return &op->write.rbio;
+err_remove_list:
+       async_object_list_del(c, promote, op->list_idx);
 err_remove_hash:
        BUG_ON(rhashtable_remove_fast(&c->promote_table, &op->hash,
                                      bch_promote_params));
        return NULL;
 }
 
+void bch2_promote_op_to_text(struct printbuf *out, struct promote_op *op)
+{
+       if (!op->write.read_done) {
+               prt_printf(out, "parent read: %px\n", op->write.rbio.parent);
+               printbuf_indent_add(out, 2);
+               bch2_read_bio_to_text(out, op->write.rbio.parent);
+               printbuf_indent_sub(out, 2);
+       }
+
+       bch2_data_update_to_text(out, &op->write);
+}
+
 /* Read */
 
 static int bch2_read_err_msg_trans(struct btree_trans *trans, struct printbuf *out,
                        else
                                promote_free(rbio);
                } else {
+                       async_object_list_del(rbio->c, rbio, rbio->list_idx);
+
                        if (rbio->bounce)
                                bch2_bio_free_pages_pool(rbio->c, &rbio->bio);
 
        rbio->bio.bi_iter.bi_sector = pick.ptr.offset;
        rbio->bio.bi_end_io     = bch2_read_endio;
 
+       async_object_list_add(c, rbio, rbio, &rbio->list_idx);
+
        if (rbio->bounce)
                trace_and_count(c, io_read_bounce, &rbio->bio);
 
 
 
 #include "bkey_buf.h"
 #include "btree_iter.h"
+#include "extents_types.h"
 #include "reflink.h"
 
 struct bch_read_bio {
        u16                     _state;
        };
        s16                     ret;
+#ifdef CONFIG_BCACHEFS_ASYNC_OBJECT_LISTS
+       unsigned                list_idx;
+#endif
 
        struct extent_ptr_decoded pick;
 
        rbio->split             = true;
        rbio->parent            = orig;
        rbio->opts              = orig->opts;
+#ifdef CONFIG_BCACHEFS_ASYNC_OBJECT_LISTS
+       rbio->list_idx  = 0;
+#endif
        return rbio;
 }
 
        rbio->ret               = 0;
        rbio->opts              = opts;
        rbio->bio.bi_end_io     = end_io;
+#ifdef CONFIG_BCACHEFS_ASYNC_OBJECT_LISTS
+       rbio->list_idx  = 0;
+#endif
        return rbio;
 }
 
+struct promote_op;
+void bch2_promote_op_to_text(struct printbuf *, struct promote_op *);
 void bch2_read_bio_to_text(struct printbuf *, struct bch_read_bio *);
 
 void bch2_fs_io_read_exit(struct bch_fs *);