dm raid1: add is_remote_recovering hook for clusters
authorJonathan Brassow <jbrassow@redhat.com>
Thu, 2 Apr 2009 18:55:30 +0000 (19:55 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Thu, 2 Apr 2009 18:55:30 +0000 (19:55 +0100)
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>
drivers/md/dm-raid1.c
include/linux/dm-dirty-log.h

index 62d5948..536ef0b 100644 (file)
@@ -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).
index 727602b..5e8b11d 100644 (file)
@@ -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);