md/raid5: fix a potential deadlock of raid5 reshape
PATCH 1/1 md/raid5: fix a potential deadlock of raid5 reshape
There is a potential deadlock if mount/umount happens when raid5_finish_reshape() tries to grow the size of emulated disk.
How the deadlock happens?
1) The raid5 resync thread finished reshape (expanding array).
2) The mount or umount thread holds VFS sb->s_umount lock and tries to write through critical data into raid5 emulated block device. So it waits for raid5 kernel thread handling stripes in order to finish it I/Os.
3) In the routine of raid5 kernel thread, md_check_recovery() will be called first in order to reap the raid5 resync thread. That is, raid5_finish_reshape() will be called. In this function, it will try to update conf and call VFS revalidate_disk() to grow the raid5 emulated block device. It will try to acquire VFS sb->s_umount lock.
The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished, mount/umount will not release sb->s_umount lock. The deadlock happens.
The raid5 kernel thread is an emulated block device. It is responible to handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results.
For solving this potential deadlock, we can put the size growth of the emulated block device as the final step of reshape thread.
--- drivers/md/md.c | 13 +++++++++++++ drivers/md/raid5.c | 8 +------- 2 files changed, 14 insertions(+), 7 deletions(-)
drivers/md/md.c +13 -0
@@ -8527,6 +8527,19 @@ void md_do_sync(struct md_thread *thread)* raid */ set_mask_bits (&mddev->sb_flags,0 ,BIT (MD_SB_CHANGE_PENDING ) |BIT (MD_SB_CHANGE_DEVS )); + +if (test_bit (MD_RECOVERY_RESHAPE , &mddev->recovery) && + !test_bit (MD_RECOVERY_INTR , &mddev->recovery) && + mddev->delta_disks >0 && + mddev->pers->finish_reshape && + mddev->pers->size && + mddev->queue) { +mddev_lock_nointr (mddev); +md_set_array_sectors (mddev, mddev->pers->size (mddev,0 ,0 )); +mddev_unlock (mddev); +set_capacity (mddev->gendisk, mddev->array_sectors); +revalidate_disk (mddev->gendisk); + }spin_lock (&mddev->lock);if (!test_bit (MD_RECOVERY_INTR , &mddev->recovery)) {
drivers/md/raid5.c +1 -7
@@ -8001,13 +8001,7 @@ static void raid5_finish_reshape(struct mddev *mddev)if (!test_bit (MD_RECOVERY_INTR , &mddev->recovery)) { -if (mddev->delta_disks >0 ) { -md_set_array_sectors (mddev,raid5_size (mddev,0 ,0 )); -if (mddev->queue) { -set_capacity (mddev->gendisk, mddev->array_sectors); -revalidate_disk (mddev->gendisk); - } - }else { +if (mddev->delta_disks <=0 ) {int d;spin_lock_irq (&conf->device_lock); mddev->degraded =raid5_calc_degraded (conf);
Signature · 1 line
2.7.4
Quoted 26 lines · bingjingc
There is a potential deadlock if mount/umount happens when
raid5_finish_reshape()tries to grow the size of emulated disk.How the deadlock happens?
1) The raid5 resync thread finished reshape (expanding array).
2) The mount or umount thread holds VFSsb->s_umountlock and tries to write through critical data into raid5 emulated block device. So it waits for raid5 kernel thread handling stripes in order to finish it I/Os.
3) In the routine of raid5 kernel thread,md_check_recovery()will be called first in order to reap the raid5 resync thread. That is,raid5_finish_reshape()will be called. In this function, it will try to update conf and call VFSrevalidate_disk()to grow the raid5 emulated block device. It will try to acquire VFSsb->s_umountlock. The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished, mount/umount will not releasesb->s_umountlock. The deadlock happens.The raid5 kernel thread is an emulated block device. It is responible to handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results.
Quoted 2 lines
For solving this potential deadlock, we can put the size growth of the emulated block device as the final step of reshape thread.
Maybe another way to avoid the deadlock is to ensure the reshaping array can't be mount at all. One reason is, if the reshaping is finished, but fs still don't know about the new array size since metadata is not refreshed. Just my $0.02.
Quoted 9 lines
Reported-by Alex Wu <[email protected]>Reviewed-by Alex Wu <[email protected]>Reviewed-by Chung-Chiang Cheng <[email protected]>Signed-off-by BingJing Chang <[email protected]>---
drivers/md/md.c | 13 +++++++++++++
drivers/md/raid5.c | 8 +-------2 files changed, 14 insertions(+), 7 deletions(-)
I think raid10 has the similar issue, so at least you need to change raid10 either.
Thanks,
Guoqing
Quoted 45 lines
drivers/md/md.c +13
-0@@ -8527,6 +8527,19 @@ void md_do_sync(struct md_thread *thread)* raid */ set_mask_bits(&mddev->sb_flags, 0, BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS)); + + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && + mddev->delta_disks > 0 && + mddev->pers->finish_reshape && + mddev->pers->size && + mddev->queue) { + mddev_lock_nointr(mddev); + md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0)); + mddev_unlock(mddev); + set_capacity(mddev->gendisk, mddev->array_sectors); + revalidate_disk(mddev->gendisk); + } spin_lock(&mddev->lock); if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {drivers/md/raid5.c +1
-7@@ -8001,13 +8001,7 @@ static void raid5_finish_reshape(struct mddev *mddev) if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { - if (mddev->delta_disks > 0) { - md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); - if (mddev->queue) { - set_capacity(mddev->gendisk, mddev->array_sectors); - revalidate_disk(mddev->gendisk); - } - } else { + if (mddev->delta_disks <= 0) { int d; spin_lock_irq(&conf->device_lock);
mddev->degraded=raid5_calc_degraded(conf);
Guoqing Jiang 於 2017-12-28 15:59 寫到:
Quoted 27 lines · bingjingc
Quoted 26 lines
There is a potential deadlock if mount/umount happens when
raid5_finish_reshape()tries to grow the size of emulated disk.How the deadlock happens?
1) The raid5 resync thread finished reshape (expanding array).
2) The mount or umount thread holds VFSsb->s_umountlock and tries to write through critical data into raid5 emulated block device. So it waits for raid5 kernel thread handling stripes in order to finish it I/Os.
3) In the routine of raid5 kernel thread,md_check_recovery()will be called first in order to reap the raid5 resync thread. That is,raid5_finish_reshape()will be called. In this function, it will try to update conf and call VFSrevalidate_disk()to grow the raid5 emulated block device. It will try to acquire VFSsb->s_umountlock. The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished, mount/umount will not releasesb->s_umountlock. The deadlock happens.The raid5 kernel thread is an emulated block device. It is responible to handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results.
Quoted 8 lines
Quoted 2 lines
For solving this potential deadlock, we can put the size growth of the emulated block device as the final step of reshape thread.
Maybe another way to avoid the deadlock is to ensure the reshaping array can't be mount at all. One reason is, if the reshaping is finished, but fs still don't know about the new array size since metadata is not refreshed. Just my $0.02.
It may take hours or couples of days to expand an array. So I bet that it's a feature that an expanding array can still serve fs requests. Once it finished, the new array size for metadata can be passed to fs layer via revalidate_disk(). From then, fs is able to be expanded, too. There are no needs to restart that array. Based on this point, I don't want to break this feature.
Quoted 10 lines
Quoted 9 lines
Reported-by Alex Wu <[email protected]>Reviewed-by Alex Wu <[email protected]>Reviewed-by Chung-Chiang Cheng <[email protected]>Signed-off-by BingJing Chang <[email protected]>---
drivers/md/md.c | 13 +++++++++++++
drivers/md/raid5.c | 8 +-------2 files changed, 14 insertions(+), 7 deletions(-)
Quoted 2 lines
I think raid10 has the similar issue, so at least you need to change raid10 either.
Thank you for your notice. It should be a similar issue. Let me verify whether it is/isn't really reproducible in raid10 first. And we will provide a fix for it.
Thanks,
BingJing
Quoted 49 lines
Thanks,
GuoqingQuoted 45 lines
drivers/md/md.c +13
-0@@ -8527,6 +8527,19 @@ void md_do_sync(struct md_thread *thread)* raid */ set_mask_bits(&mddev->sb_flags, 0, BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS)); + + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && + mddev->delta_disks > 0 && + mddev->pers->finish_reshape && + mddev->pers->size && + mddev->queue) { + mddev_lock_nointr(mddev); + md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0)); + mddev_unlock(mddev); + set_capacity(mddev->gendisk, mddev->array_sectors); + revalidate_disk(mddev->gendisk); + } spin_lock(&mddev->lock); if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {drivers/md/raid5.c +1
-7@@ -8001,13 +8001,7 @@ static void raid5_finish_reshape(struct mddev *mddev) if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { - if (mddev->delta_disks > 0) { - md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); - if (mddev->queue) { - set_capacity(mddev->gendisk, mddev->array_sectors); - revalidate_disk(mddev->gendisk); - } - } else { + if (mddev->delta_disks <= 0) { int d; spin_lock_irq(&conf->device_lock);
mddev->degraded=raid5_calc_degraded(conf);
Quoted 38 lines · bingjingc
Guoqing Jiang 於 2017-12-28 15:59 寫到:
Quoted 27 lines · bingjingc
Quoted 26 lines
There is a potential deadlock if mount/umount happens when
raid5_finish_reshape()tries to grow the size of emulated disk.How the deadlock happens?
1) The raid5 resync thread finished reshape (expanding array).
2) The mount or umount thread holds VFSsb->s_umountlock and tries to write through critical data into raid5 emulated block device. So it waits for raid5 kernel thread handling stripes in order to finish it I/Os.
3) In the routine of raid5 kernel thread,md_check_recovery()will be called first in order to reap the raid5 resync thread. That is,raid5_finish_reshape()will be called. In this function, it will try to update conf and call VFSrevalidate_disk()to grow the raid5 emulated block device. It will try to acquire VFSsb->s_umountlock. The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished, mount/umount will not releasesb->s_umountlock. The deadlock happens.The raid5 kernel thread is an emulated block device. It is responible to handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results.
Quoted 8 lines
Quoted 2 lines
For solving this potential deadlock, we can put the size growth of the emulated block device as the final step of reshape thread.
Maybe another way to avoid the deadlock is to ensure the reshaping array can't be mount at all. One reason is, if the reshaping is finished, but fs still don't know about the new array size since metadata is not refreshed. Just my $0.02.
Quoted 5 lines
It may take hours or couples of days to expand an array. So I bet that it's a feature that an expanding array can still serve fs requests. Once it finished, the new array size for metadata can be passed to fs layer via
revalidate_disk(). From then, fs is able to be expanded, too. There are no needs to restart that array. Based on this point, I don't want to break this feature.
Sorry, the metadata which I mentioned before is the metadata for file system. How fs know about the new size without update fs's metadata? Pls see the wiki:
https://raid.wiki.kernel.org/index.php/Growing#Extending_the_filesystem
Thanks,
Guoqing
Subject: [PATCH] md: fix a potential deadlock of raid5/raid10 reshape
There is a potential deadlock if mount/umount happens when raid5_finish_reshape() tries to grow the size of emulated disk.
How the deadlock happens?
1) The raid5 resync thread finished reshape (expanding array).
2) The mount or umount thread holds VFS sb->s_umount lock and tries to write through critical data into raid5 emulated block device. So it waits for raid5 kernel thread handling stripes in order to finish it I/Os.
3) In the routine of raid5 kernel thread, md_check_recovery() will be called first in order to reap the raid5 resync thread. That is, raid5_finish_reshape() will be called. In this function, it will try to update conf and call VFS revalidate_disk() to grow the raid5 emulated block device. It will try to acquire VFS sb->s_umount lock.
The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished, mount/umount will not release sb->s_umount lock. The deadlock happens.
The raid5 kernel thread is an emulated block device. It is responible to handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results.
For solving this potential deadlock, we can put the size growth of the emulated block device as the final step of reshape thread.
2017/12/29:
Thanks to Guoqing Jiang <[email protected]>,
we confirmed that there is the same deadlock issue in raid10. It's reproducible and can be fixed by this patch. For raid10.c, we can remove the similar code to prevent deadlock as well since they has been called before.
--- drivers/md/md.c | 13 +++++++++++++ drivers/md/raid10.c | 8 +------- drivers/md/raid5.c | 8 +------- 3 files changed, 15 insertions(+), 14 deletions(-)
drivers/md/md.c +13 -0
@@ -8528,6 +8528,19 @@ void md_do_sync(struct md_thread *thread)set_mask_bits (&mddev->sb_flags,0 ,BIT (MD_SB_CHANGE_PENDING ) |BIT (MD_SB_CHANGE_DEVS )); +if (test_bit (MD_RECOVERY_RESHAPE , &mddev->recovery) && + !test_bit (MD_RECOVERY_INTR , &mddev->recovery) && + mddev->delta_disks >0 && + mddev->pers->finish_reshape && + mddev->pers->size && + mddev->queue) { +mddev_lock_nointr (mddev); +md_set_array_sectors (mddev, mddev->pers->size (mddev,0 ,0 )); +mddev_unlock (mddev); +set_capacity (mddev->gendisk, mddev->array_sectors); +revalidate_disk (mddev->gendisk); + } +spin_lock (&mddev->lock);if (!test_bit (MD_RECOVERY_INTR , &mddev->recovery)) {/* We completed so min/max setting can be forgotten if used. */
drivers/md/raid10.c +1 -7
@@ -4818,17 +4818,11 @@ static void raid10_finish_reshape(struct mddev *mddev)return ;if (mddev->delta_disks >0 ) { -sector_t size =raid10_size (mddev,0 ,0 ); -md_set_array_sectors (mddev, size);if (mddev->recovery_cp > mddev->resync_max_sectors) { mddev->recovery_cp = mddev->resync_max_sectors;set_bit (MD_RECOVERY_NEEDED , &mddev->recovery); } - mddev->resync_max_sectors = size; -if (mddev->queue) { -set_capacity (mddev->gendisk, mddev->array_sectors); -revalidate_disk (mddev->gendisk); - } + mddev->resync_max_sectors = mddev->array_sectors; }else {int d;rcu_read_lock ();
drivers/md/raid5.c +1 -7
@@ -8001,13 +8001,7 @@ static void raid5_finish_reshape(struct mddev *mddev)if (!test_bit (MD_RECOVERY_INTR , &mddev->recovery)) { -if (mddev->delta_disks >0 ) { -md_set_array_sectors (mddev,raid5_size (mddev,0 ,0 )); -if (mddev->queue) { -set_capacity (mddev->gendisk, mddev->array_sectors); -revalidate_disk (mddev->gendisk); - } - }else { +if (mddev->delta_disks <=0 ) {int d;spin_lock_irq (&conf->device_lock); mddev->degraded =raid5_calc_degraded (conf);
Signature · 5 lines
2.7.4 Guoqing Jiang 於 2017-12-29 14:42 寫到:
Quoted 45 lines · bingjingc
Quoted 38 lines
Guoqing Jiang 於 2017-12-28 15:59 寫到:
Quoted 27 lines · bingjingc
Quoted 26 lines
There is a potential deadlock if mount/umount happens when
raid5_finish_reshape()tries to grow the size of emulated disk.How the deadlock happens?
1) The raid5 resync thread finished reshape (expanding array).
2) The mount or umount thread holds VFSsb->s_umountlock and tries to write through critical data into raid5 emulated block device. So it waits for raid5 kernel thread handling stripes in order to finish it I/Os.
3) In the routine of raid5 kernel thread,md_check_recovery()will be called first in order to reap the raid5 resync thread. That is,raid5_finish_reshape()will be called. In this function, it will try to update conf and call VFSrevalidate_disk()to grow the raid5 emulated block device. It will try to acquire VFSsb->s_umountlock. The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished, mount/umount will not releasesb->s_umountlock. The deadlock happens.The raid5 kernel thread is an emulated block device. It is responible to handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results.
Quoted 8 lines
Quoted 2 lines
For solving this potential deadlock, we can put the size growth of the emulated block device as the final step of reshape thread.
Maybe another way to avoid the deadlock is to ensure the reshaping array can't be mount at all. One reason is, if the reshaping is finished, but fs still don't know about the new array size since metadata is not refreshed. Just my $0.02.
Quoted 5 lines
It may take hours or couples of days to expand an array. So I bet that it's a feature that an expanding array can still serve fs requests. Once it finished, the new array size for metadata can be passed to fs layer via
revalidate_disk(). From then, fs is able to be expanded, too. There are no needs to restart that array. Based on this point, I don't want to break this feature.
Quoted 3 lines
Sorry, the metadata which I mentioned before is the metadata for file system. How fs know about the new size without update fs's metadata? Pls see the wiki:
https://raid.wiki.kernel.org/index.php/Growing#Extending_the_filesystem
Sorry, you're right. It requires few more commands to grow the filesystem's size. I used wrong wordings. In fact, what I want to mention is the metadata of the emulated disk. In fs/block_dev.c, revalidate_disk() will call check_disk_size_change(disk, bdev) to adjust the monitored block device size. I guess that these structures belong to VFS. So for MD, it keeps the same behavior to issue the upper layer about the size change.
Thanks,
BingJing
Quoted 3 lines
Thanks,
Guoqing
Quoted 37 lines · bingjingc
Subject: [PATCH] md: fix a potential deadlock of raid5/raid10 reshape
There is a potential deadlock if mount/umount happens when
raid5_finish_reshape()tries to grow the size of emulated disk.How the deadlock happens?
1) The raid5 resync thread finished reshape (expanding array).
2) The mount or umount thread holds VFSsb->s_umountlock and tries to write through critical data into raid5 emulated block device. So it waits for raid5 kernel thread handling stripes in order to finish it I/Os.
3) In the routine of raid5 kernel thread,md_check_recovery()will be called first in order to reap the raid5 resync thread. That is,raid5_finish_reshape()will be called. In this function, it will try to update conf and call VFSrevalidate_disk()to grow the raid5 emulated block device. It will try to acquire VFSsb->s_umountlock.
The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished, mount/umount will not releasesb->s_umountlock. The deadlock happens.The raid5 kernel thread is an emulated block device. It is responible to handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results.
For solving this potential deadlock, we can put the size growth of the emulated block device as the final step of reshape thread.
2017/12/29:
Thanks to Guoqing Jiang <[email protected]>,
we confirmed that there is the same deadlock issue in raid10. It's reproducible and can be fixed by this patch. Forraid10.c, we can remove the similar code to prevent deadlock as well since they has been called before.
Quoted 4 lines
Reported-by Alex Wu <[email protected]>Reviewed-by Alex Wu <[email protected]>Reviewed-by Chung-Chiang Cheng <[email protected]>Signed-off-by BingJing Chang <[email protected]>
can you resend this patch? it doesn't apply.
Quoted 162 lines
--- drivers/md/md.c | 13 +++++++++++++ drivers/md/raid10.c | 8 +------- drivers/md/raid5.c | 8 +------- 3 files changed, 15 insertions(+), 14 deletions(-)drivers/md/md.c +13
-0@@ -8528,6 +8528,19 @@ void md_do_sync(struct md_thread *thread)set_mask_bits (&mddev->sb_flags,0 ,BIT (MD_SB_CHANGE_PENDING ) |BIT (MD_SB_CHANGE_DEVS )); +if (test_bit (MD_RECOVERY_RESHAPE , &mddev->recovery) && + !test_bit (MD_RECOVERY_INTR , &mddev->recovery) && + mddev->delta_disks >0 && + mddev->pers->finish_reshape && + mddev->pers->size && + mddev->queue) { +mddev_lock_nointr (mddev); +md_set_array_sectors (mddev, mddev->pers->size (mddev,0 ,0 )); +mddev_unlock (mddev); +set_capacity (mddev->gendisk, mddev->array_sectors); +revalidate_disk (mddev->gendisk); + } +spin_lock (&mddev->lock);if (!test_bit (MD_RECOVERY_INTR , &mddev->recovery)) {/* We completed so min/max setting can be forgotten if used. */ drivers/md/raid10.c +1
-7@@ -4818,17 +4818,11 @@ static void raid10_finish_reshape(struct mddev *mddev)return ;if (mddev->delta_disks >0 ) { -sector_t size =raid10_size (mddev,0 ,0 ); -md_set_array_sectors (mddev, size);if (mddev->recovery_cp > mddev->resync_max_sectors) { mddev->recovery_cp = mddev->resync_max_sectors;set_bit (MD_RECOVERY_NEEDED , &mddev->recovery); } - mddev->resync_max_sectors = size; -if (mddev->queue) { -set_capacity (mddev->gendisk, mddev->array_sectors); -revalidate_disk (mddev->gendisk); - } + mddev->resync_max_sectors = mddev->array_sectors; }else {int d;drivers/md/raid10.c +0
-0rcu_read_lock ();drivers/md/raid5.c +1
-7@@ -8001,13 +8001,7 @@ static void raid5_finish_reshape(struct mddev *mddev)if (!test_bit (MD_RECOVERY_INTR , &mddev->recovery)) { -if (mddev->delta_disks >0 ) { -md_set_array_sectors (mddev,raid5_size (mddev,0 ,0 )); -if (mddev->queue) { -set_capacity (mddev->gendisk, mddev->array_sectors); -revalidate_disk (mddev->gendisk); - } - }else { +if (mddev->delta_disks <=0 ) {int d;spin_lock_irq (&conf->device_lock); mddev->degraded =raid5_calc_degraded (conf);Signature · 5 lines
2.7.4 Guoqing Jiang 於 2017-12-29 14:42 寫到:Quoted 63 lines · bingjingc
Quoted 52 lines
Guoqing Jiang 於 2017-12-28 15:59 寫到:
Quoted 41 lines · bingjingc
Quoted 36 lines
There is a potential deadlock if mount/umount happens when
raid5_finish_reshape()tries to grow the size of emulated disk.How the deadlock happens?
1) The raid5 resync thread finished reshape (expanding array).
2) The mount or umount thread holds VFSsb->s_umountlock and tries to
write through critical data into raid5 emulated block device. So it
waits for raid5 kernel thread handling stripes in order to finish it
I/Os.
3) In the routine of raid5 kernel thread,md_check_recovery()will be
called first in order to reap the raid5 resync thread. That is,raid5_finish_reshape()will be called. In this function, it will try
to update conf and call VFSrevalidate_disk()to grow the raid5 emulated block device. It will try to acquire VFSsb->s_umountlock.
The raid5 kernel thread cannot continue, so no one can handle mount/ umount I/Os (stripes). Once the write-through I/Os cannot be finished,
mount/umount will not releasesb->s_umountlock. The deadlock happens.The raid5 kernel thread is an emulated block device. It is responible to
handle I/Os (stripes) from upper layers. The emulated block device should not request any I/Os on itself. That is, it should not call VFS
layer functions. (If it did, it will try to acquire VFS locks to guarantee the I/Os sequence.) So we have the resync thread to send resync I/O requests and to wait for the results.Quoted 3 lines
For solving this potential deadlock, we can put the size growth of the
emulated block device as the final step of reshape thread.Quoted 8 lines
Maybe another way to avoid the deadlock is to ensure the reshaping array
can't be mount at all. One reason is, if the reshaping is finished, but fs still
don't know about the new array size since metadata is not refreshed. Just
my $0.02.Quoted 9 lines
It may take hours or couples of days to expand an array. So I bet that it's a
feature that an expanding array can still serve fs requests. Once it finished,
the new array size for metadata can be passed to fs layer viarevalidate_disk().
From then, fs is able to be expanded, too. There are no needs to restart that
array. Based on this point, I don't want to break this feature.Quoted 5 lines
Sorry, the metadata which I mentioned before is the metadata for file system.
How fs know about the new size without update fs's metadata? Pls see the wiki:
https://raid.wiki.kernel.org/index.php/Growing#Extending_the_filesystemSorry, you're right. It requires few more commands to grow the filesystem's size. I used wrong wordings. In fact, what I want to mention is the metadata of the emulated disk. In
fs/block_dev.c,revalidate_disk()will callcheck_disk_size_change(disk, bdev)to adjust the monitored block device size. I guess that these structures belong to VFS. So for MD, it keeps the same behavior to issue the upper layer about the size change.Thanks,
BingJingQuoted 3 lines
Thanks,
Guoqing