Commit 7513c2a7 authored by Jonathan Brassow's avatar Jonathan Brassow Committed by Alasdair G Kergon

dm raid1: add is_remote_recovering hook for clusters

The logging API needs an extra function to make cluster mirroring
possible.  This new function allows us to check whether a mirror
region is being recovered on another machine in the cluster.  This
helps us prevent simultaneous recovery I/O and process I/O to the
same locations on disk.

Cluster-aware log modules will implement this function.  Single
machine log modules will not.  So, there is no performance
penalty for single machine mirrors.
Signed-off-by: default avatarJonathan Brassow <jbrassow@redhat.com>
Acked-by: default avatarHeinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent b2a11465
...@@ -588,6 +588,9 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) ...@@ -588,6 +588,9 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
int state; int state;
struct bio *bio; struct bio *bio;
struct bio_list sync, nosync, recover, *this_list = NULL; struct bio_list sync, nosync, recover, *this_list = NULL;
struct bio_list requeue;
struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
region_t region;
if (!writes->head) if (!writes->head)
return; return;
...@@ -598,10 +601,18 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) ...@@ -598,10 +601,18 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
bio_list_init(&sync); bio_list_init(&sync);
bio_list_init(&nosync); bio_list_init(&nosync);
bio_list_init(&recover); bio_list_init(&recover);
bio_list_init(&requeue);
while ((bio = bio_list_pop(writes))) { while ((bio = bio_list_pop(writes))) {
state = dm_rh_get_state(ms->rh, region = dm_rh_bio_to_region(ms->rh, bio);
dm_rh_bio_to_region(ms->rh, bio), 1);
if (log->type->is_remote_recovering &&
log->type->is_remote_recovering(log, region)) {
bio_list_add(&requeue, bio);
continue;
}
state = dm_rh_get_state(ms->rh, region, 1);
switch (state) { switch (state) {
case DM_RH_CLEAN: case DM_RH_CLEAN:
case DM_RH_DIRTY: case DM_RH_DIRTY:
...@@ -620,6 +631,16 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) ...@@ -620,6 +631,16 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
bio_list_add(this_list, bio); bio_list_add(this_list, bio);
} }
/*
* Add bios that are delayed due to remote recovery
* back on to the write queue
*/
if (unlikely(requeue.head)) {
spin_lock_irq(&ms->lock);
bio_list_merge(&ms->writes, &requeue);
spin_unlock_irq(&ms->lock);
}
/* /*
* Increment the pending counts for any regions that will * Increment the pending counts for any regions that will
* be written to (writes to recover regions are going to * be written to (writes to recover regions are going to
......
...@@ -116,6 +116,16 @@ struct dm_dirty_log_type { ...@@ -116,6 +116,16 @@ struct dm_dirty_log_type {
*/ */
int (*status)(struct dm_dirty_log *log, status_type_t status_type, int (*status)(struct dm_dirty_log *log, status_type_t status_type,
char *result, unsigned maxlen); char *result, unsigned maxlen);
/*
* is_remote_recovering is necessary for cluster mirroring. It provides
* a way to detect recovery on another node, so we aren't writing
* concurrently. This function is likely to block (when a cluster log
* is used).
*
* Returns: 0, 1
*/
int (*is_remote_recovering)(struct dm_dirty_log *log, region_t region);
}; };
int dm_dirty_log_type_register(struct dm_dirty_log_type *type); int dm_dirty_log_type_register(struct dm_dirty_log_type *type);
......
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