diff options
| author | Jonathan Brassow <jbrassow@redhat.com> | 2009-04-02 19:55:30 +0100 | 
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2009-04-02 19:55:30 +0100 | 
| commit | 7513c2a761d69d2a93f17146b3563527d3618ba0 (patch) | |
| tree | 375a14998a60a47b83962d5a497139112ec6e8e4 | |
| parent | b2a114652940ccf7e9668ad447ca78bf16a31139 (diff) | |
| download | olio-linux-3.10-7513c2a761d69d2a93f17146b3563527d3618ba0.tar.xz olio-linux-3.10-7513c2a761d69d2a93f17146b3563527d3618ba0.zip  | |
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>
| -rw-r--r-- | drivers/md/dm-raid1.c | 25 | ||||
| -rw-r--r-- | include/linux/dm-dirty-log.h | 10 | 
2 files changed, 33 insertions, 2 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 62d594889ac..536ef0bef15 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -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: @@ -621,6 +632,16 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)  	}  	/* +	 * 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  	 * be delayed). diff --git a/include/linux/dm-dirty-log.h b/include/linux/dm-dirty-log.h index 727602b686d..5e8b11d88f6 100644 --- a/include/linux/dm-dirty-log.h +++ b/include/linux/dm-dirty-log.h @@ -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);  |