From 5fa4f8bac9516b988d2ccd3f05f4267f8da24269 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 25 Oct 2019 09:08:56 +0200 Subject: [PATCH 1/3] md/raid1: avoid soft lockup under high load As all I/O is being pushed through a kernel thread the softlockup watchdog might be triggered under high load. Signed-off-by: Hannes Reinecke Signed-off-by: Song Liu --- drivers/md/raid1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index bb29aeefcbd0..a409ab6f30bc 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -819,6 +819,7 @@ static void flush_bio_list(struct r1conf *conf, struct bio *bio) else generic_make_request(bio); bio = next; + cond_resched(); } } From 228fc7d76db68732677230a3c64337908fd298e3 Mon Sep 17 00:00:00 2001 From: Yufen Yu Date: Wed, 30 Oct 2019 18:47:02 +0800 Subject: [PATCH 2/3] md: avoid invalid memory access for array sb->dev_roles we need to gurantee 'desc_nr' valid before access array of sb->dev_roles. In addition, we should avoid .load_super always return '0' when level is LEVEL_MULTIPATH, which is not expected. Reported-by: coverity-bot Addresses-Coverity-ID: 1487373 ("Memory - illegal accesses") Fixes: 6a5cb53aaa4e ("md: no longer compare spare disk superblock events in super_load") Signed-off-by: Yufen Yu Signed-off-by: Song Liu --- drivers/md/md.c | 51 +++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 6f0ecfe8eab2..805b33e27496 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1105,6 +1105,7 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; mdp_super_t *sb; int ret; + bool spare_disk = true; /* * Calculate the position of the superblock (512byte sectors), @@ -1155,13 +1156,15 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor else rdev->desc_nr = sb->this_disk.number; + /* not spare disk, or LEVEL_MULTIPATH */ + if (sb->level == LEVEL_MULTIPATH || + (rdev->desc_nr >= 0 && + sb->disks[rdev->desc_nr].state & + ((1<disks[rdev->desc_nr].state & ( - (1<disks[rdev->desc_nr].state & ( - (1< ev2)) + if (!spare_disk && ev1 > ev2) ret = 1; else ret = 0; @@ -1547,7 +1544,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_ sector_t sectors; char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; int bmask; - __u64 role; + bool spare_disk = true; /* * Calculate the position of the superblock in 512byte sectors. @@ -1681,17 +1678,16 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_ sb->level != 0) return -EINVAL; - role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]); + /* not spare disk, or LEVEL_MULTIPATH */ + if (sb->level == cpu_to_le32(LEVEL_MULTIPATH) || + (rdev->desc_nr >= 0 && + rdev->desc_nr < le32_to_cpu(sb->max_dev) && + (le16_to_cpu(sb->dev_roles[rdev->desc_nr]) < MD_DISK_ROLE_MAX || + le16_to_cpu(sb->dev_roles[rdev->desc_nr]) == MD_DISK_ROLE_JOURNAL))) + spare_disk = false; if (!refdev) { - /* - * Insist of good event counter while assembling, except for - * spares (which don't need an event count) - */ - if (rdev->desc_nr >= 0 && - rdev->desc_nr < le32_to_cpu(sb->max_dev) && - (role < MD_DISK_ROLE_MAX || - role == MD_DISK_ROLE_JOURNAL)) + if (!spare_disk) ret = 1; else ret = 0; @@ -1711,14 +1707,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_ ev1 = le64_to_cpu(sb->events); ev2 = le64_to_cpu(refsb->events); - /* - * Insist of good event counter while assembling, except for - * spares (which don't need an event count) - */ - if (rdev->desc_nr >= 0 && - rdev->desc_nr < le32_to_cpu(sb->max_dev) && - (role < MD_DISK_ROLE_MAX || - role == MD_DISK_ROLE_JOURNAL) && ev1 > ev2) + if (!spare_disk && ev1 > ev2) ret = 1; else ret = 0; From 45422b704db392a6d79d07ee3e3670b11048bd53 Mon Sep 17 00:00:00 2001 From: John Pittman Date: Mon, 11 Nov 2019 16:43:20 -0800 Subject: [PATCH 3/3] md/raid10: prevent access of uninitialized resync_pages offset Due to unneeded multiplication in the out_free_pages portion of r10buf_pool_alloc(), when using a 3-copy raid10 layout, it is possible to access a resync_pages offset that has not been initialized. This access translates into a crash of the system within resync_free_pages() while passing a bad pointer to put_page(). Remove the multiplication, preventing access to the uninitialized area. Fixes: f0250618361db ("md: raid10: don't use bio's vec table to manage resync pages") Cc: stable@vger.kernel.org # 4.12+ Signed-off-by: John Pittman Suggested-by: David Jeffery Reviewed-by: Laurence Oberman Signed-off-by: Song Liu --- drivers/md/raid10.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 2eca0a81a8c9..ec136e44aef7 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -191,7 +191,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data) out_free_pages: while (--j >= 0) - resync_free_pages(&rps[j * 2]); + resync_free_pages(&rps[j]); j = 0; out_free_bio: