bcachefs: for_each_online_member_rcu()
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 19 Apr 2025 02:11:15 +0000 (22:11 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:14:26 +0000 (20:14 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_foreground.c
fs/bcachefs/bcachefs.h
fs/bcachefs/chardev.c
fs/bcachefs/fs.c
fs/bcachefs/sb-members.h
fs/bcachefs/super.c

index d56cee7e8cb5a360b6b3d6c41d0c861d10abe421..e87b95f609c53794b0539cba9a739598017753d2 100644 (file)
@@ -1645,7 +1645,12 @@ static noinline void bch2_print_allocator_stuck(struct bch_fs *c)
        printbuf_indent_sub(&buf, 2);
        prt_newline(&buf);
 
-       for_each_online_member(c, ca) {
+       bch2_printbuf_make_room(&buf, 4096);
+
+       rcu_read_lock();
+       buf.atomic++;
+
+       for_each_online_member_rcu(c, ca) {
                prt_printf(&buf, "Dev %u:\n", ca->dev_idx);
                printbuf_indent_add(&buf, 2);
                bch2_dev_alloc_debug_to_text(&buf, ca);
@@ -1653,6 +1658,9 @@ static noinline void bch2_print_allocator_stuck(struct bch_fs *c)
                prt_newline(&buf);
        }
 
+       --buf.atomic;
+       rcu_read_unlock();
+
        prt_printf(&buf, "Copygc debug:\n");
        printbuf_indent_add(&buf, 2);
        bch2_copygc_wait_to_text(&buf, c);
index 4fd0963497906bc6156e022a400f26d3a0368b1d..1597259b708c0a6cc44fb106faf45d0971e1bbd2 100644 (file)
@@ -891,6 +891,7 @@ struct bch_fs {
        struct workqueue_struct *write_ref_wq;
 
        /* ALLOCATION */
+       struct bch_devs_mask    online_devs;
        struct bch_devs_mask    rw_devs[BCH_DATA_NR];
        unsigned long           rw_devs_change_count;
 
index 5891b3a1e61ce23c01b08198f5098a66849d5b22..4066946b26bce6afa464cdf7d2072e8c2c9233d9 100644 (file)
@@ -613,11 +613,13 @@ static long bch2_ioctl_disk_get_idx(struct bch_fs *c,
        if (!dev)
                return -EINVAL;
 
-       for_each_online_member(c, ca)
+       rcu_read_lock();
+       for_each_online_member_rcu(c, ca)
                if (ca->dev == dev) {
-                       percpu_ref_put(&ca->io_ref[READ]);
+                       rcu_read_unlock();
                        return ca->dev_idx;
                }
+       rcu_read_unlock();
 
        return -BCH_ERR_ENOENT_dev_idx_not_found;
 }
index 17a27d6d8c9d3c79d1ad909b06336f57258c403f..cdf84180829a045ca4ab80df2f92c040caa9edd3 100644 (file)
@@ -2327,12 +2327,14 @@ static int bch2_show_devname(struct seq_file *seq, struct dentry *root)
        struct bch_fs *c = root->d_sb->s_fs_info;
        bool first = true;
 
-       for_each_online_member(c, ca) {
+       rcu_read_lock();
+       for_each_online_member_rcu(c, ca) {
                if (!first)
                        seq_putc(seq, ':');
                first = false;
                seq_puts(seq, ca->disk_sb.sb_name);
        }
+       rcu_read_unlock();
 
        return 0;
 }
@@ -2529,15 +2531,16 @@ got_sb:
 
        sb->s_bdi->ra_pages             = VM_READAHEAD_PAGES;
 
-       for_each_online_member(c, ca) {
+       rcu_read_lock();
+       for_each_online_member_rcu(c, ca) {
                struct block_device *bdev = ca->disk_sb.bdev;
 
                /* XXX: create an anonymous device for multi device filesystems */
                sb->s_bdev      = bdev;
                sb->s_dev       = bdev->bd_dev;
-               percpu_ref_put(&ca->io_ref[READ]);
                break;
        }
+       rcu_read_unlock();
 
        c->dev = sb->s_dev;
 
index 424143f5e33011cef96626cb161d63d68504db64..28c6fc25c32cf4d5ad8dd0cab251696d8ea25a95 100644 (file)
@@ -104,6 +104,9 @@ static inline struct bch_dev *__bch2_next_dev(struct bch_fs *c, struct bch_dev *
        for (struct bch_dev *_ca = NULL;                                \
             (_ca = __bch2_next_dev((_c), _ca, (_mask)));)
 
+#define for_each_online_member_rcu(_c, _ca)                            \
+       for_each_member_device_rcu(_c, _ca, &(_c)->online_devs)
+
 static inline void bch2_dev_get(struct bch_dev *ca)
 {
 #ifdef CONFIG_BCACHEFS_DEBUG
@@ -307,17 +310,6 @@ static inline struct bch_dev *bch2_dev_get_ioref(struct bch_fs *c, unsigned dev,
        return NULL;
 }
 
-/* XXX kill, move to struct bch_fs */
-static inline struct bch_devs_mask bch2_online_devs(struct bch_fs *c)
-{
-       struct bch_devs_mask devs;
-
-       memset(&devs, 0, sizeof(devs));
-       for_each_online_member(c, ca)
-               __set_bit(ca->dev_idx, devs.d);
-       return devs;
-}
-
 extern const struct bch_sb_field_ops bch_sb_field_ops_members_v1;
 extern const struct bch_sb_field_ops bch_sb_field_ops_members_v2;
 
index 839b1582c1f1e8954a56b8df169e954e45d4d5a2..834c68a273b48b4455fc4c22a7bede0e30825b9c 100644 (file)
@@ -1105,7 +1105,7 @@ static bool bch2_fs_may_start(struct bch_fs *c)
                break;
        }
 
-       return bch2_have_enough_devs(c, bch2_online_devs(c), flags, true);
+       return bch2_have_enough_devs(c, c->online_devs, flags, true);
 }
 
 int bch2_fs_start(struct bch_fs *c)
@@ -1138,8 +1138,11 @@ int bch2_fs_start(struct bch_fs *c)
                goto err;
        }
 
-       for_each_online_member(c, ca)
-               bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx)->last_mount = cpu_to_le64(now);
+       rcu_read_lock();
+       for_each_online_member_rcu(c, ca)
+               bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx)->last_mount =
+               cpu_to_le64(now);
+       rcu_read_unlock();
 
        /*
         * Dno't write superblock yet: recovery might have to downgrade
@@ -1294,6 +1297,9 @@ static int bch2_dev_in_fs(struct bch_sb_handle *fs,
 
 static void bch2_dev_io_ref_stop(struct bch_dev *ca, int rw)
 {
+       if (rw == READ)
+               clear_bit(ca->dev_idx, ca->fs->online_devs.d);
+
        if (!percpu_ref_is_zero(&ca->io_ref[rw])) {
                reinit_completion(&ca->io_ref_completion[rw]);
                percpu_ref_kill(&ca->io_ref[rw]);
@@ -1577,6 +1583,8 @@ static int bch2_dev_attach_bdev(struct bch_fs *c, struct bch_sb_handle *sb)
        if (ret)
                return ret;
 
+       set_bit(ca->dev_idx, c->online_devs.d);
+
        bch2_dev_sysfs_online(c, ca);
 
        struct printbuf name = PRINTBUF;
@@ -1634,7 +1642,7 @@ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca,
                        return true;
 
                /* do we have enough devices to read from?  */
-               new_online_devs = bch2_online_devs(c);
+               new_online_devs = c->online_devs;
                __clear_bit(ca->dev_idx, new_online_devs.d);
 
                return bch2_have_enough_devs(c, new_online_devs, flags, false);