[PATCH] dm snapshot: tidy pe ref counting
authorAlasdair G Kergon <agk@redhat.com>
Tue, 3 Oct 2006 08:15:30 +0000 (01:15 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Tue, 3 Oct 2006 15:04:14 +0000 (08:04 -0700)
Rename sibling_count to ref_count and introduce get and put functions.

Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/md/dm-snap.c

index 1c6485404db4310c2beaafe7aacc328ec00c9b72..638c8d90da0e177aedf44c855c31786165185eaa 100644 (file)
@@ -59,7 +59,7 @@ struct pending_exception {
 
        /*
         * The primary pending_exception is the one that holds
-        * the sibling_count and the list of origin_bios for a
+        * the ref_count and the list of origin_bios for a
         * group of pending_exceptions.  It is always last to get freed.
         * These fields get set up when writing to the origin.
         */
@@ -72,7 +72,7 @@ struct pending_exception {
         * the sibling concerned and not pe->primary_pe->snap->lock unless
         * they are the same.
         */
-       atomic_t sibling_count;
+       atomic_t ref_count;
 
        /* Pointer back to snapshot context */
        struct dm_snapshot *snap;
@@ -653,10 +653,46 @@ static void __invalidate_snapshot(struct dm_snapshot *s,
        dm_table_event(s->table);
 }
 
+static void get_pending_exception(struct pending_exception *pe)
+{
+       atomic_inc(&pe->ref_count);
+}
+
+static struct bio *put_pending_exception(struct pending_exception *pe)
+{
+       struct pending_exception *primary_pe;
+       struct bio *origin_bios = NULL;
+
+       primary_pe = pe->primary_pe;
+
+       /*
+        * If this pe is involved in a write to the origin and
+        * it is the last sibling to complete then release
+        * the bios for the original write to the origin.
+        */
+       if (primary_pe &&
+           atomic_dec_and_test(&primary_pe->ref_count))
+               origin_bios = bio_list_get(&primary_pe->origin_bios);
+
+       /*
+        * Free the pe if it's not linked to an origin write or if
+        * it's not itself a primary pe.
+        */
+       if (!primary_pe || primary_pe != pe)
+               free_pending_exception(pe);
+
+       /*
+        * Free the primary pe if nothing references it.
+        */
+       if (primary_pe && !atomic_read(&primary_pe->ref_count))
+               free_pending_exception(primary_pe);
+
+       return origin_bios;
+}
+
 static void pending_complete(struct pending_exception *pe, int success)
 {
        struct exception *e;
-       struct pending_exception *primary_pe;
        struct dm_snapshot *s = pe->snap;
        struct bio *origin_bios = NULL;
        struct bio *snapshot_bios = NULL;
@@ -695,30 +731,7 @@ static void pending_complete(struct pending_exception *pe, int success)
 
  out:
        snapshot_bios = bio_list_get(&pe->snapshot_bios);
-
-       primary_pe = pe->primary_pe;
-
-       /*
-        * If this pe is involved in a write to the origin and
-        * it is the last sibling to complete then release
-        * the bios for the original write to the origin.
-        */
-       if (primary_pe &&
-           atomic_dec_and_test(&primary_pe->sibling_count))
-               origin_bios = bio_list_get(&primary_pe->origin_bios);
-
-       /*
-        * Free the pe if it's not linked to an origin write or if
-        * it's not itself a primary pe.
-        */
-       if (!primary_pe || primary_pe != pe)
-               free_pending_exception(pe);
-
-       /*
-        * Free the primary pe if nothing references it.
-        */
-       if (primary_pe && !atomic_read(&primary_pe->sibling_count))
-               free_pending_exception(primary_pe);
+       origin_bios = put_pending_exception(pe);
 
        up_write(&s->lock);
 
@@ -829,7 +842,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
        bio_list_init(&pe->origin_bios);
        bio_list_init(&pe->snapshot_bios);
        pe->primary_pe = NULL;
-       atomic_set(&pe->sibling_count, 1);
+       atomic_set(&pe->ref_count, 0);
        pe->snap = s;
        pe->started = 0;
 
@@ -838,6 +851,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
                return NULL;
        }
 
+       get_pending_exception(pe);
        insert_exception(&s->pending, &pe->e);
 
  out:
@@ -1012,7 +1026,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
                 * is already remapped in this snapshot
                 * and trigger an exception if not.
                 *
-                * sibling_count is initialised to 1 so pending_complete()
+                * ref_count is initialised to 1 so pending_complete()
                 * won't destroy the primary_pe while we're inside this loop.
                 */
                e = lookup_exception(&snap->complete, chunk);
@@ -1043,8 +1057,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
                }
 
                if (!pe->primary_pe) {
-                       atomic_inc(&primary_pe->sibling_count);
                        pe->primary_pe = primary_pe;
+                       get_pending_exception(primary_pe);
                }
 
                if (!pe->started) {
@@ -1057,20 +1071,20 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
        }
 
        if (!primary_pe)
-               goto out;
+               return r;
 
        /*
         * If this is the first time we're processing this chunk and
-        * sibling_count is now 1 it means all the pending exceptions
+        * ref_count is now 1 it means all the pending exceptions
         * got completed while we were in the loop above, so it falls to
         * us here to remove the primary_pe and submit any origin_bios.
         */
 
-       if (first && atomic_dec_and_test(&primary_pe->sibling_count)) {
+       if (first && atomic_dec_and_test(&primary_pe->ref_count)) {
                flush_bios(bio_list_get(&primary_pe->origin_bios));
                free_pending_exception(primary_pe);
                /* If we got here, pe_queue is necessarily empty. */
-               goto out;
+               return r;
        }
 
        /*
@@ -1079,7 +1093,6 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
        list_for_each_entry_safe(pe, next_pe, &pe_queue, list)
                start_copy(pe);
 
- out:
        return r;
 }