md/raid10: fix null-ptr-deref of mreplace in raid10_sync_request
[ Upstream commit 34817a2441747b48e444cb0e05d84e14bc9443da ]
There are two check of 'mreplace' in raid10_sync_request(). In the first
check, 'need_replace' will be set and 'mreplace' will be used later if
no-Faulty 'mreplace' exists, In the second check, 'mreplace' will be
set to NULL if it is Faulty, but 'need_replace' will not be changed
accordingly. null-ptr-deref occurs if Faulty is set between two check.
Fix it by merging two checks into one. And replace 'need_replace' with
'mreplace' because their values are always the same.
Fixes: ee37d7314a
("md/raid10: Fix raid10 replace hang when new added disk faulty")
Signed-off-by: Li Nan <linan122@huawei.com>
Reviewed-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230527072218.2365857-2-linan666@huaweicloud.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
b1d8f38310
commit
2990e2ece1
@@ -3037,7 +3037,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|||||||
int must_sync;
|
int must_sync;
|
||||||
int any_working;
|
int any_working;
|
||||||
int need_recover = 0;
|
int need_recover = 0;
|
||||||
int need_replace = 0;
|
|
||||||
struct raid10_info *mirror = &conf->mirrors[i];
|
struct raid10_info *mirror = &conf->mirrors[i];
|
||||||
struct md_rdev *mrdev, *mreplace;
|
struct md_rdev *mrdev, *mreplace;
|
||||||
|
|
||||||
@@ -3049,11 +3048,10 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|||||||
!test_bit(Faulty, &mrdev->flags) &&
|
!test_bit(Faulty, &mrdev->flags) &&
|
||||||
!test_bit(In_sync, &mrdev->flags))
|
!test_bit(In_sync, &mrdev->flags))
|
||||||
need_recover = 1;
|
need_recover = 1;
|
||||||
if (mreplace != NULL &&
|
if (mreplace && test_bit(Faulty, &mreplace->flags))
|
||||||
!test_bit(Faulty, &mreplace->flags))
|
mreplace = NULL;
|
||||||
need_replace = 1;
|
|
||||||
|
|
||||||
if (!need_recover && !need_replace) {
|
if (!need_recover && !mreplace) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -3069,8 +3067,6 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (mreplace && test_bit(Faulty, &mreplace->flags))
|
|
||||||
mreplace = NULL;
|
|
||||||
/* Unless we are doing a full sync, or a replacement
|
/* Unless we are doing a full sync, or a replacement
|
||||||
* we only need to recover the block if it is set in
|
* we only need to recover the block if it is set in
|
||||||
* the bitmap
|
* the bitmap
|
||||||
@@ -3193,11 +3189,11 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
|
|||||||
bio = r10_bio->devs[1].repl_bio;
|
bio = r10_bio->devs[1].repl_bio;
|
||||||
if (bio)
|
if (bio)
|
||||||
bio->bi_end_io = NULL;
|
bio->bi_end_io = NULL;
|
||||||
/* Note: if need_replace, then bio
|
/* Note: if replace is not NULL, then bio
|
||||||
* cannot be NULL as r10buf_pool_alloc will
|
* cannot be NULL as r10buf_pool_alloc will
|
||||||
* have allocated it.
|
* have allocated it.
|
||||||
*/
|
*/
|
||||||
if (!need_replace)
|
if (!mreplace)
|
||||||
break;
|
break;
|
||||||
bio->bi_next = biolist;
|
bio->bi_next = biolist;
|
||||||
biolist = bio;
|
biolist = bio;
|
||||||
|
Reference in New Issue
Block a user