Commit 42543769 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] md: Don't write dirty/clean update to spares - leave them alone

- record the 'event' count on each individual device (they
  might sometimes be slightly different now)
- add a new value for 'sb_dirty': '3' means that the super
  block only needs to be updated to record a clean<->dirty
  transition.
- Prefer odd event numbers for dirty states and even numbers
  for clean states
- Using all the above, don't update the superblock on
  a spare device if the update is just doing a clean-dirty
  transition.  To accomodate this, a transition from
  dirty back to clean might now decrement the events counter
  if nothing else has changed.

The net effect of this is that spare drives will not see any IO requests
during normal running of the array, so they can go to sleep if that is what
they want to do.
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 07d84d10
...@@ -1558,15 +1558,30 @@ static void md_print_devices(void) ...@@ -1558,15 +1558,30 @@ static void md_print_devices(void)
} }
static void sync_sbs(mddev_t * mddev) static void sync_sbs(mddev_t * mddev, int nospares)
{ {
/* Update each superblock (in-memory image), but
* if we are allowed to, skip spares which already
* have the right event counter, or have one earlier
* (which would mean they aren't being marked as dirty
* with the rest of the array)
*/
mdk_rdev_t *rdev; mdk_rdev_t *rdev;
struct list_head *tmp; struct list_head *tmp;
ITERATE_RDEV(mddev,rdev,tmp) { ITERATE_RDEV(mddev,rdev,tmp) {
super_types[mddev->major_version]. if (rdev->sb_events == mddev->events ||
sync_super(mddev, rdev); (nospares &&
rdev->sb_loaded = 1; rdev->raid_disk < 0 &&
(rdev->sb_events&1)==0 &&
rdev->sb_events+1 == mddev->events)) {
/* Don't update this superblock */
rdev->sb_loaded = 2;
} else {
super_types[mddev->major_version].
sync_super(mddev, rdev);
rdev->sb_loaded = 1;
}
} }
} }
...@@ -1576,12 +1591,42 @@ void md_update_sb(mddev_t * mddev) ...@@ -1576,12 +1591,42 @@ void md_update_sb(mddev_t * mddev)
struct list_head *tmp; struct list_head *tmp;
mdk_rdev_t *rdev; mdk_rdev_t *rdev;
int sync_req; int sync_req;
int nospares = 0;
repeat: repeat:
spin_lock_irq(&mddev->write_lock); spin_lock_irq(&mddev->write_lock);
sync_req = mddev->in_sync; sync_req = mddev->in_sync;
mddev->utime = get_seconds(); mddev->utime = get_seconds();
mddev->events ++; if (mddev->sb_dirty == 3)
/* just a clean<-> dirty transition, possibly leave spares alone,
* though if events isn't the right even/odd, we will have to do
* spares after all
*/
nospares = 1;
/* If this is just a dirty<->clean transition, and the array is clean
* and 'events' is odd, we can roll back to the previous clean state */
if (mddev->sb_dirty == 3
&& (mddev->in_sync && mddev->recovery_cp == MaxSector)
&& (mddev->events & 1))
mddev->events--;
else {
/* otherwise we have to go forward and ... */
mddev->events ++;
if (!mddev->in_sync || mddev->recovery_cp != MaxSector) { /* not clean */
/* .. if the array isn't clean, insist on an odd 'events' */
if ((mddev->events&1)==0) {
mddev->events++;
nospares = 0;
}
} else {
/* otherwise insist on an even 'events' (for clean states) */
if ((mddev->events&1)) {
mddev->events++;
nospares = 0;
}
}
}
if (!mddev->events) { if (!mddev->events) {
/* /*
...@@ -1593,7 +1638,7 @@ void md_update_sb(mddev_t * mddev) ...@@ -1593,7 +1638,7 @@ void md_update_sb(mddev_t * mddev)
mddev->events --; mddev->events --;
} }
mddev->sb_dirty = 2; mddev->sb_dirty = 2;
sync_sbs(mddev); sync_sbs(mddev, nospares);
/* /*
* do not write anything to disk if using * do not write anything to disk if using
...@@ -1615,6 +1660,8 @@ void md_update_sb(mddev_t * mddev) ...@@ -1615,6 +1660,8 @@ void md_update_sb(mddev_t * mddev)
ITERATE_RDEV(mddev,rdev,tmp) { ITERATE_RDEV(mddev,rdev,tmp) {
char b[BDEVNAME_SIZE]; char b[BDEVNAME_SIZE];
dprintk(KERN_INFO "md: "); dprintk(KERN_INFO "md: ");
if (rdev->sb_loaded != 1)
continue; /* no noise on spare devices */
if (test_bit(Faulty, &rdev->flags)) if (test_bit(Faulty, &rdev->flags))
dprintk("(skipping faulty "); dprintk("(skipping faulty ");
...@@ -1626,6 +1673,7 @@ void md_update_sb(mddev_t * mddev) ...@@ -1626,6 +1673,7 @@ void md_update_sb(mddev_t * mddev)
dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
bdevname(rdev->bdev,b), bdevname(rdev->bdev,b),
(unsigned long long)rdev->sb_offset); (unsigned long long)rdev->sb_offset);
rdev->sb_events = mddev->events;
} else } else
dprintk(")\n"); dprintk(")\n");
...@@ -1895,6 +1943,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi ...@@ -1895,6 +1943,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
rdev->desc_nr = -1; rdev->desc_nr = -1;
rdev->flags = 0; rdev->flags = 0;
rdev->data_offset = 0; rdev->data_offset = 0;
rdev->sb_events = 0;
atomic_set(&rdev->nr_pending, 0); atomic_set(&rdev->nr_pending, 0);
atomic_set(&rdev->read_errors, 0); atomic_set(&rdev->read_errors, 0);
atomic_set(&rdev->corrected_errors, 0); atomic_set(&rdev->corrected_errors, 0);
...@@ -4708,7 +4757,7 @@ void md_write_start(mddev_t *mddev, struct bio *bi) ...@@ -4708,7 +4757,7 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
spin_lock_irq(&mddev->write_lock); spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync) { if (mddev->in_sync) {
mddev->in_sync = 0; mddev->in_sync = 0;
mddev->sb_dirty = 1; mddev->sb_dirty = 3;
md_wakeup_thread(mddev->thread); md_wakeup_thread(mddev->thread);
} }
spin_unlock_irq(&mddev->write_lock); spin_unlock_irq(&mddev->write_lock);
...@@ -5055,7 +5104,7 @@ void md_check_recovery(mddev_t *mddev) ...@@ -5055,7 +5104,7 @@ void md_check_recovery(mddev_t *mddev)
if (mddev->safemode && !atomic_read(&mddev->writes_pending) && if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
!mddev->in_sync && mddev->recovery_cp == MaxSector) { !mddev->in_sync && mddev->recovery_cp == MaxSector) {
mddev->in_sync = 1; mddev->in_sync = 1;
mddev->sb_dirty = 1; mddev->sb_dirty = 3;
} }
if (mddev->safemode == 1) if (mddev->safemode == 1)
mddev->safemode = 0; mddev->safemode = 0;
......
...@@ -58,6 +58,7 @@ struct mdk_rdev_s ...@@ -58,6 +58,7 @@ struct mdk_rdev_s
struct page *sb_page; struct page *sb_page;
int sb_loaded; int sb_loaded;
__u64 sb_events;
sector_t data_offset; /* start of data in array */ sector_t data_offset; /* start of data in array */
sector_t sb_offset; sector_t sb_offset;
int sb_size; /* bytes in the superblock */ int sb_size; /* bytes in the superblock */
......
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