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

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
Loading
Loading
Loading
Loading
+19 −11
Original line number Diff line number Diff line
@@ -2615,6 +2615,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
			if (atomic_read(&mddev->writes_pending) == 0) {
				if (mddev->in_sync == 0) {
					mddev->in_sync = 1;
					if (mddev->safemode == 1)
						mddev->safemode = 0;
					if (mddev->persistent)
						set_bit(MD_CHANGE_CLEAN,
							&mddev->flags);
@@ -5392,6 +5394,8 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
		md_wakeup_thread(mddev->sync_thread);
	}
	atomic_inc(&mddev->writes_pending);
	if (mddev->safemode == 1)
		mddev->safemode = 0;
	if (mddev->in_sync) {
		spin_lock_irq(&mddev->write_lock);
		if (mddev->in_sync) {
@@ -5816,7 +5820,7 @@ void md_check_recovery(mddev_t *mddev)
		return;

	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",
			       mdname(mddev));
			mddev->safemode = 2;
@@ -5828,7 +5832,7 @@ void md_check_recovery(mddev_t *mddev)
		(mddev->flags && !mddev->external) ||
		test_bit(MD_RECOVERY_NEEDED, &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->in_sync && mddev->recovery_cp == MaxSector)
		))
@@ -5837,9 +5841,12 @@ void md_check_recovery(mddev_t *mddev)
	if (mddev_trylock(mddev)) {
		int spares = 0;

		if (!mddev->external) {
			spin_lock_irq(&mddev->write_lock);
		if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
		    !mddev->in_sync && mddev->recovery_cp == MaxSector) {
			if (mddev->safemode &&
			    !atomic_read(&mddev->writes_pending) &&
			    !mddev->in_sync &&
			    mddev->recovery_cp == MaxSector) {
				mddev->in_sync = 1;
				if (mddev->persistent)
					set_bit(MD_CHANGE_CLEAN, &mddev->flags);
@@ -5847,6 +5854,7 @@ void md_check_recovery(mddev_t *mddev)
			if (mddev->safemode == 1)
				mddev->safemode = 0;
			spin_unlock_irq(&mddev->write_lock);
		}

		if (mddev->flags)
			md_update_sb(mddev, 0);