mdmon: periodically checkpoint recovery
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>
This commit is contained in:
parent
63b4aae33e
commit
484240d8a3
|
@ -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);
|
||||
|
||||
|
|
9
mdmon.h
9
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;
|
||||
|
|
33
monitor.c
33
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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue