forked from Minki/linux
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: Jonathan Brassow <jbrassow@redhat.com> Acked-by: Heinz Mauelshagen <heinzm@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:
parent
b2a1146529
commit
7513c2a761
@ -588,6 +588,9 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
|
||||
int state;
|
||||
struct bio *bio;
|
||||
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)
|
||||
return;
|
||||
@ -598,10 +601,18 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
|
||||
bio_list_init(&sync);
|
||||
bio_list_init(&nosync);
|
||||
bio_list_init(&recover);
|
||||
bio_list_init(&requeue);
|
||||
|
||||
while ((bio = bio_list_pop(writes))) {
|
||||
state = dm_rh_get_state(ms->rh,
|
||||
dm_rh_bio_to_region(ms->rh, bio), 1);
|
||||
region = dm_rh_bio_to_region(ms->rh, bio);
|
||||
|
||||
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) {
|
||||
case DM_RH_CLEAN:
|
||||
case DM_RH_DIRTY:
|
||||
@ -620,6 +631,16 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
|
||||
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
|
||||
* be written to (writes to recover regions are going to
|
||||
|
@ -116,6 +116,16 @@ struct dm_dirty_log_type {
|
||||
*/
|
||||
int (*status)(struct dm_dirty_log *log, status_type_t status_type,
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user