]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
mdmon: periodically checkpoint recovery
authorDan Williams <dan.j.williams@intel.com>
Sat, 15 May 2010 00:42:49 +0000 (17:42 -0700)
committerDan Williams <dan.j.williams@intel.com>
Sat, 15 May 2010 00:42:49 +0000 (17:42 -0700)
The kernel updates and notifies md/sync_completed when it is time to
take a checkpoint.  When this occurs (at 1/16 array size intervals)
write 'idle' to md/sync_action to have the current recovery position
updated in recovery_start and resync_start.

Requires the metadata handler to reset ->last_checkpoint when it has
determined that recovery has ended.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
managemon.c
mdmon.h
monitor.c
super-intel.c

index 454c39dc7e4193d52e48c149689604d9997ca7f1..d5ba6d6d30be6a42c23ad5fc8bbef509fa201490 100644 (file)
@@ -540,6 +540,7 @@ static void manage_new(struct mdstat_ent *mdstat,
        new->info.state_fd = sysfs_open(new->devnum, NULL, "array_state");
        new->resync_start_fd = sysfs_open(new->devnum, NULL, "resync_start");
        new->metadata_fd = sysfs_open(new->devnum, NULL, "metadata_version");
+       new->sync_completed_fd = sysfs_open(new->devnum, NULL, "sync_completed");
        dprintf("%s: inst: %d action: %d state: %d\n", __func__, atoi(inst),
                new->action_fd, new->info.state_fd);
 
diff --git a/mdmon.h b/mdmon.h
index 20a0a013c54eadd76325cc95e3504a0075ebc7ae..5c515663f4a4225d1c23ec6c38c571537eca9cb2 100644 (file)
--- a/mdmon.h
+++ b/mdmon.h
@@ -32,6 +32,15 @@ struct active_array {
        int action_fd;
        int resync_start_fd;
        int metadata_fd; /* for monitoring rw/ro status */
+       int sync_completed_fd; /* for checkpoint notification events */
+       unsigned long long last_checkpoint; /* sync_completed fires for many
+                                            * reasons this field makes sure the
+                                            * kernel has made progress before
+                                            * moving the checkpoint.  It is
+                                            * cleared by the metadata handler
+                                            * when it determines recovery is
+                                            * terminated.
+                                            */
 
        enum array_state prev_state, curr_state, next_state;
        enum sync_action prev_action, curr_action, next_action;
index e43e545ce196f1370ad68b78c9b02dac67ae89f9..12f8d3e6237c8bef698b15dc7f884630f1dc110c 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -80,6 +80,24 @@ static unsigned long long read_resync_start(int fd)
                return strtoull(buf, NULL, 10);
 }
 
+static unsigned long long read_sync_completed(int fd)
+{
+       unsigned long long val;
+       char buf[50];
+       int n;
+       char *ep;
+
+       n = read_attr(buf, 50, fd);
+
+       if (n <= 0)
+               return 0;
+       buf[n] = 0;
+       val = strtoull(buf, &ep, 0);
+       if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
+               return 0;
+       return val;
+}
+
 static enum array_state read_state(int fd)
 {
        char buf[20];
@@ -195,6 +213,7 @@ static void signal_manager(void)
 
 static int read_and_act(struct active_array *a)
 {
+       unsigned long long sync_completed;
        int check_degraded = 0;
        int deactivate = 0;
        struct mdinfo *mdi;
@@ -206,6 +225,7 @@ static int read_and_act(struct active_array *a)
        a->curr_state = read_state(a->info.state_fd);
        a->curr_action = read_action(a->action_fd);
        a->info.resync_start = read_resync_start(a->resync_start_fd);
+       sync_completed = read_sync_completed(a->sync_completed_fd);
        for (mdi = a->info.devs; mdi ; mdi = mdi->next) {
                mdi->next_state = 0;
                if (mdi->state_fd >= 0) {
@@ -307,6 +327,18 @@ static int read_and_act(struct active_array *a)
                }
        }
 
+       /* Check for recovery checkpoint notifications.  We need to be a
+        * minimum distance away from the last checkpoint to prevent
+        * over checkpointing.  Note reshape checkpointing is not
+        * handled here.
+        */
+       if (sync_completed > a->last_checkpoint &&
+           sync_completed - a->last_checkpoint > a->info.component_size >> 4 &&
+           a->curr_action > reshape && a->next_action == bad_action) {
+               a->last_checkpoint = sync_completed;
+               a->next_action = idle;
+       }
+
        a->container->ss->sync_metadata(a->container);
        dprintf("%s(%d): state:%s action:%s next(", __func__, a->info.container_member,
                array_states[a->curr_state], sync_actions[a->curr_action]);
@@ -461,6 +493,7 @@ static int wait_and_act(struct supertype *container, int nowait)
 
                add_fd(&rfds, &maxfd, a->info.state_fd);
                add_fd(&rfds, &maxfd, a->action_fd);
+               add_fd(&rfds, &maxfd, a->sync_completed_fd);
                for (mdi = a->info.devs ; mdi ; mdi = mdi->next)
                        add_fd(&rfds, &maxfd, mdi->state_fd);
 
index 677396c64a9ab2eb953e915a0230299c81941f7e..394ace419dbf8c13e2547057c4b7187f562b3d89 100644 (file)
@@ -4384,6 +4384,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
                        dprintf("imsm: mark resync done\n");
                        end_migration(dev, map_state);
                        super->updates_pending++;
+                       a->last_checkpoint = 0;
                }
        } else if (!is_resyncing(dev) && !failed) {
                /* mark the start of the init process if nothing is failed */
@@ -4476,17 +4477,20 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
                map = get_imsm_map(dev, 0);
                map->failed_disk_num = ~0;
                super->updates_pending++;
+               a->last_checkpoint = 0;
        } else if (map_state == IMSM_T_STATE_DEGRADED &&
                   map->map_state != map_state &&
                   !dev->vol.migr_state) {
                dprintf("imsm: mark degraded\n");
                map->map_state = map_state;
                super->updates_pending++;
+               a->last_checkpoint = 0;
        } else if (map_state == IMSM_T_STATE_FAILED &&
                   map->map_state != map_state) {
                dprintf("imsm: mark failed\n");
                end_migration(dev, map_state);
                super->updates_pending++;
+               a->last_checkpoint = 0;
        }
 }