Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bcache: remove incremental dirty sector counting for bch_sectors_dirty_init()

After making bch_sectors_dirty_init() being multithreaded, the existing
incremental dirty sector counting in bch_root_node_dirty_init() doesn't
release btree occupation after iterating 500000 (INIT_KEYS_EACH_TIME)
bkeys. Because a read lock is added on btree root node to prevent the
btree to be split during the dirty sectors counting, other I/O requester
has no chance to gain the write lock even restart bcache_btree().

That is to say, the incremental dirty sectors counting is incompatible
to the multhreaded bch_sectors_dirty_init(). We have to choose one and
drop another one.

In my testing, with 512 bytes random writes, I generate 1.2T dirty data
and a btree with 400K nodes. With single thread and incremental dirty
sectors counting, it takes 30+ minites to register the backing device.
And with multithreaded dirty sectors counting, the backing device
registration can be accomplished within 2 minutes.

The 30+ minutes V.S. 2- minutes difference makes me decide to keep
multithreaded bch_sectors_dirty_init() and drop the incremental dirty
sectors counting. This is what this patch does.

But INIT_KEYS_EACH_TIME is kept, in sectors_dirty_init_fn() the CPU
will be released by cond_resched() after every INIT_KEYS_EACH_TIME keys
iterated. This is to avoid the watchdog reports a bogus soft lockup
warning.

Fixes: b144e45fc576 ("bcache: make bch_sectors_dirty_init() to be multithreaded")
Signed-off-by: Coly Li <colyli@suse.de>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20220524102336.10684-4-colyli@suse.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Coly Li and committed by
Jens Axboe
80db4e47 4dc34ae1

+12 -27
+12 -27
drivers/md/bcache/writeback.c
··· 805 805 806 806 /* Init */ 807 807 #define INIT_KEYS_EACH_TIME 500000 808 - #define INIT_KEYS_SLEEP_MS 100 809 808 810 809 struct sectors_dirty_init { 811 810 struct btree_op op; 812 811 unsigned int inode; 813 812 size_t count; 814 - struct bkey start; 815 813 }; 816 814 817 815 static int sectors_dirty_init_fn(struct btree_op *_op, struct btree *b, ··· 825 827 KEY_START(k), KEY_SIZE(k)); 826 828 827 829 op->count++; 828 - if (atomic_read(&b->c->search_inflight) && 829 - !(op->count % INIT_KEYS_EACH_TIME)) { 830 - bkey_copy_key(&op->start, k); 831 - return -EAGAIN; 832 - } 830 + if (!(op->count % INIT_KEYS_EACH_TIME)) 831 + cond_resched(); 833 832 834 833 return MAP_CONTINUE; 835 834 } ··· 841 846 bch_btree_op_init(&op.op, -1); 842 847 op.inode = d->id; 843 848 op.count = 0; 844 - op.start = KEY(op.inode, 0, 0); 845 849 846 - do { 847 - ret = bcache_btree(map_keys_recurse, 848 - k, 849 - c->root, 850 - &op.op, 851 - &op.start, 852 - sectors_dirty_init_fn, 853 - 0); 854 - if (ret == -EAGAIN) 855 - schedule_timeout_interruptible( 856 - msecs_to_jiffies(INIT_KEYS_SLEEP_MS)); 857 - else if (ret < 0) { 858 - pr_warn("sectors dirty init failed, ret=%d!\n", ret); 859 - break; 860 - } 861 - } while (ret == -EAGAIN); 850 + ret = bcache_btree(map_keys_recurse, 851 + k, 852 + c->root, 853 + &op.op, 854 + &KEY(op.inode, 0, 0), 855 + sectors_dirty_init_fn, 856 + 0); 857 + if (ret < 0) 858 + pr_warn("sectors dirty init failed, ret=%d!\n", ret); 862 859 863 860 return ret; 864 861 } ··· 894 907 goto out; 895 908 } 896 909 skip_nr--; 897 - cond_resched(); 898 910 } 899 911 900 912 if (p) { ··· 903 917 904 918 p = NULL; 905 919 prev_idx = cur_idx; 906 - cond_resched(); 907 920 } 908 921 909 922 out: ··· 941 956 bch_btree_op_init(&op.op, -1); 942 957 op.inode = d->id; 943 958 op.count = 0; 944 - op.start = KEY(op.inode, 0, 0); 945 959 946 960 for_each_key_filter(&c->root->keys, 947 961 k, &iter, bch_ptr_invalid) 948 962 sectors_dirty_init_fn(&op.op, c->root, k); 963 + 949 964 rw_unlock(0, c->root); 950 965 return; 951 966 }