Skip to content

Commit

Permalink
md/raid1-10: limit the number of plugged bio
Browse files Browse the repository at this point in the history
bio can be added to plug infinitely, and following writeback test can
trigger huge amount of plugged bio:

Test script:
modprobe brd rd_nr=4 rd_size=10485760
mdadm -CR /dev/md0 -l10 -n4 /dev/ram[0123] --assume-clean --bitmap=internal
echo 0 > /proc/sys/vm/dirty_background_ratio
fio -filename=/dev/md0 -ioengine=libaio -rw=write -bs=4k -numjobs=1 -iodepth=128 -name=test

Test result:
Monitor /sys/block/md0/inflight will found that inflight keep increasing
until fio finish writing, after running for about 2 minutes:

[root@fedora ~]# cat /sys/block/md0/inflight
       0  4474191

Fix the problem by limiting the number of plugged bio based on the number
of copies for original bio.

Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230529131106.2123367-8-yukuai1@huaweicloud.com
  • Loading branch information
Yu Kuai authored and Song Liu committed Jun 13, 2023
1 parent 9efcc2c commit 460af1f
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 3 deletions.
9 changes: 8 additions & 1 deletion drivers/md/raid1-10.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define IO_MADE_GOOD ((struct bio *)2)

#define BIO_SPECIAL(bio) ((unsigned long)bio <= 2)
#define MAX_PLUG_BIO 32

/* for managing resync I/O pages */
struct resync_pages {
Expand All @@ -31,6 +32,7 @@ struct resync_pages {
struct raid1_plug_cb {
struct blk_plug_cb cb;
struct bio_list pending;
unsigned int count;
};

static void rbio_pool_free(void *rbio, void *data)
Expand Down Expand Up @@ -129,7 +131,7 @@ static inline void raid1_submit_write(struct bio *bio)
}

static inline bool raid1_add_bio_to_plug(struct mddev *mddev, struct bio *bio,
blk_plug_cb_fn unplug)
blk_plug_cb_fn unplug, int copies)
{
struct raid1_plug_cb *plug = NULL;
struct blk_plug_cb *cb;
Expand All @@ -149,6 +151,11 @@ static inline bool raid1_add_bio_to_plug(struct mddev *mddev, struct bio *bio,

plug = container_of(cb, struct raid1_plug_cb, cb);
bio_list_add(&plug->pending, bio);
if (++plug->count / MAX_PLUG_BIO >= copies) {
list_del(&cb->list);
cb->callback(cb, false);
}


return true;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/raid1.c
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
r1_bio->sector);
/* flush_pending_writes() needs access to the rdev so...*/
mbio->bi_bdev = (void *)rdev;
if (!raid1_add_bio_to_plug(mddev, mbio, raid1_unplug)) {
if (!raid1_add_bio_to_plug(mddev, mbio, raid1_unplug, disks)) {
spin_lock_irqsave(&conf->device_lock, flags);
bio_list_add(&conf->pending_bio_list, mbio);
spin_unlock_irqrestore(&conf->device_lock, flags);
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/raid10.c
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,7 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,

atomic_inc(&r10_bio->remaining);

if (!raid1_add_bio_to_plug(mddev, mbio, raid10_unplug)) {
if (!raid1_add_bio_to_plug(mddev, mbio, raid10_unplug, conf->copies)) {
spin_lock_irqsave(&conf->device_lock, flags);
bio_list_add(&conf->pending_bio_list, mbio);
spin_unlock_irqrestore(&conf->device_lock, flags);
Expand Down

0 comments on commit 460af1f

Please sign in to comment.