Commit 31a59e34 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

md: fix 'safemode' handling for external metadata.

'safemode' relates to marking an array as 'clean' if there has been no write
traffic for a while (a couple of seconds), to reduce the chance of the array
being found dirty on reboot.

->safemode is set to '1' when there have been no write for a while, and it
gets set to '0' when the superblock is updates with the 'clean' flag set.

This requires a few fixes for 'external' metadata:
 - When an array is set to 'clean' via sysfs, 'safemode' must be cleared.
 - when we write to an array that has 'safemode' set (there must have been
        some delay in updating the metadata), we need to clear safemode.
 - Don't try to update external metadata in md_check_recovery for safemode
        transitions - it won't work.

Also, don't try to support "immediate safe mode" (safemode==2) for external
metadata, it cannot really work (the safemode timeout can be set very low if
this is really needed).
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d897dbf9
...@@ -2615,6 +2615,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) ...@@ -2615,6 +2615,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
if (atomic_read(&mddev->writes_pending) == 0) { if (atomic_read(&mddev->writes_pending) == 0) {
if (mddev->in_sync == 0) { if (mddev->in_sync == 0) {
mddev->in_sync = 1; mddev->in_sync = 1;
if (mddev->safemode == 1)
mddev->safemode = 0;
if (mddev->persistent) if (mddev->persistent)
set_bit(MD_CHANGE_CLEAN, set_bit(MD_CHANGE_CLEAN,
&mddev->flags); &mddev->flags);
...@@ -5392,6 +5394,8 @@ void md_write_start(mddev_t *mddev, struct bio *bi) ...@@ -5392,6 +5394,8 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
md_wakeup_thread(mddev->sync_thread); md_wakeup_thread(mddev->sync_thread);
} }
atomic_inc(&mddev->writes_pending); atomic_inc(&mddev->writes_pending);
if (mddev->safemode == 1)
mddev->safemode = 0;
if (mddev->in_sync) { if (mddev->in_sync) {
spin_lock_irq(&mddev->write_lock); spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync) { if (mddev->in_sync) {
...@@ -5816,7 +5820,7 @@ void md_check_recovery(mddev_t *mddev) ...@@ -5816,7 +5820,7 @@ void md_check_recovery(mddev_t *mddev)
return; return;
if (signal_pending(current)) { if (signal_pending(current)) {
if (mddev->pers->sync_request) { if (mddev->pers->sync_request && !mddev->external) {
printk(KERN_INFO "md: %s in immediate safe mode\n", printk(KERN_INFO "md: %s in immediate safe mode\n",
mdname(mddev)); mdname(mddev));
mddev->safemode = 2; mddev->safemode = 2;
...@@ -5828,7 +5832,7 @@ void md_check_recovery(mddev_t *mddev) ...@@ -5828,7 +5832,7 @@ void md_check_recovery(mddev_t *mddev)
(mddev->flags && !mddev->external) || (mddev->flags && !mddev->external) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
(mddev->safemode == 1) || (mddev->external == 0 && mddev->safemode == 1) ||
(mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending) (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
&& !mddev->in_sync && mddev->recovery_cp == MaxSector) && !mddev->in_sync && mddev->recovery_cp == MaxSector)
)) ))
...@@ -5837,16 +5841,20 @@ void md_check_recovery(mddev_t *mddev) ...@@ -5837,16 +5841,20 @@ void md_check_recovery(mddev_t *mddev)
if (mddev_trylock(mddev)) { if (mddev_trylock(mddev)) {
int spares = 0; int spares = 0;
spin_lock_irq(&mddev->write_lock); if (!mddev->external) {
if (mddev->safemode && !atomic_read(&mddev->writes_pending) && spin_lock_irq(&mddev->write_lock);
!mddev->in_sync && mddev->recovery_cp == MaxSector) { if (mddev->safemode &&
mddev->in_sync = 1; !atomic_read(&mddev->writes_pending) &&
if (mddev->persistent) !mddev->in_sync &&
set_bit(MD_CHANGE_CLEAN, &mddev->flags); mddev->recovery_cp == MaxSector) {
mddev->in_sync = 1;
if (mddev->persistent)
set_bit(MD_CHANGE_CLEAN, &mddev->flags);
}
if (mddev->safemode == 1)
mddev->safemode = 0;
spin_unlock_irq(&mddev->write_lock);
} }
if (mddev->safemode == 1)
mddev->safemode = 0;
spin_unlock_irq(&mddev->write_lock);
if (mddev->flags) if (mddev->flags)
md_update_sb(mddev, 0); md_update_sb(mddev, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment