Skip to content

Commit

Permalink
md: simplify updating of event count to sometimes avoid updating spares.
Browse files Browse the repository at this point in the history
When updating the event count for a simple clean <-> dirty transition,
we try to avoid updating the spares so they can safely spin-down.
As the event_counts across an array must be +/- 1, this means
decrementing the event_count on a dirty->clean transition.
This is not always safe and we have to avoid the unsafe time.
We current do this with a misguided idea about it being safe or
not depending on whether the event_count is odd or even.  This
approach only works reliably in a few common instances, but easily
falls down.

So instead, simply keep internal state concerning whether it is safe
or not, and always assume it is not safe when an array is first
assembled.

Signed-off-by: NeilBrown <neilb@suse.de>
  • Loading branch information
NeilBrown committed May 18, 2010
1 parent 7b0bb53 commit a8707c0
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 20 deletions.
26 changes: 6 additions & 20 deletions drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -2088,7 +2088,6 @@ static void sync_sbs(mddev_t * mddev, int nospares)
if (rdev->sb_events == mddev->events ||
(nospares &&
rdev->raid_disk < 0 &&
(rdev->sb_events&1)==0 &&
rdev->sb_events+1 == mddev->events)) {
/* Don't update this superblock */
rdev->sb_loaded = 2;
Expand Down Expand Up @@ -2141,28 +2140,14 @@ static void md_update_sb(mddev_t * mddev, int force_change)
* and 'events' is odd, we can roll back to the previous clean state */
if (nospares
&& (mddev->in_sync && mddev->recovery_cp == MaxSector)
&& (mddev->events & 1)
&& mddev->events != 1)
&& mddev->can_decrease_events
&& mddev->events != 1) {
mddev->events--;
else {
mddev->can_decrease_events = 0;
} 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, an 'even' event must also go
* to spares. */
if ((mddev->events&1)==0) {
nospares = 0;
sync_req = 2; /* force a second update to get the
* even/odd in sync */
}
} else {
/* otherwise an 'odd' event must go to spares */
if ((mddev->events&1)) {
nospares = 0;
sync_req = 2; /* force a second update to get the
* even/odd in sync */
}
}
mddev->can_decrease_events = nospares;
}

if (!mddev->events) {
Expand Down Expand Up @@ -4606,6 +4591,7 @@ static void md_clean(mddev_t *mddev)
mddev->layout = 0;
mddev->max_disks = 0;
mddev->events = 0;
mddev->can_decrease_events = 0;
mddev->delta_disks = 0;
mddev->new_level = LEVEL_NONE;
mddev->new_layout = 0;
Expand Down
6 changes: 6 additions & 0 deletions drivers/md/md.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ struct mddev_s
int external_size; /* size managed
* externally */
__u64 events;
/* If the last 'event' was simply a clean->dirty transition, and
* we didn't write it to the spares, then it is safe and simple
* to just decrement the event count on a dirty->clean transition.
* So we record that possibility here.
*/
int can_decrease_events;

char uuid[16];

Expand Down

0 comments on commit a8707c0

Please sign in to comment.