summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-05-18 09:28:43 +1000
committerNeilBrown <neilb@suse.de>2010-05-18 15:28:01 +1000
commita8707c08f4f718bb0ed65499d3f43201f6e41455 (patch)
tree8fc3ea9ea924ebc4f28012c11f3c1e70ad60bcb2
parent7b0bb5368a7195606eca475d9f4e291ab7227052 (diff)
md: simplify updating of event count to sometimes avoid updating spares.
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>
-rw-r--r--drivers/md/md.c26
-rw-r--r--drivers/md/md.h6
2 files changed, 12 insertions, 20 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index fec4abcb9bb..9ef21d9b8e2 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -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;
@@ -2141,28 +2140,14 @@ repeat:
* 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) {
@@ -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;
diff --git a/drivers/md/md.h b/drivers/md/md.h
index a536f545809..7ab5ea15545 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -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];