Commit 4b832e8d authored by Alasdair G Kergon's avatar Alasdair G Kergon Committed by Linus Torvalds

[PATCH] dm snapshot: tidy pe ref counting

Rename sibling_count to ref_count and introduce get and put functions.
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ca3a931f
...@@ -59,7 +59,7 @@ struct pending_exception { ...@@ -59,7 +59,7 @@ struct pending_exception {
/* /*
* The primary pending_exception is the one that holds * 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. * group of pending_exceptions. It is always last to get freed.
* These fields get set up when writing to the origin. * These fields get set up when writing to the origin.
*/ */
...@@ -72,7 +72,7 @@ struct pending_exception { ...@@ -72,7 +72,7 @@ struct pending_exception {
* the sibling concerned and not pe->primary_pe->snap->lock unless * the sibling concerned and not pe->primary_pe->snap->lock unless
* they are the same. * they are the same.
*/ */
atomic_t sibling_count; atomic_t ref_count;
/* Pointer back to snapshot context */ /* Pointer back to snapshot context */
struct dm_snapshot *snap; struct dm_snapshot *snap;
...@@ -653,10 +653,46 @@ static void __invalidate_snapshot(struct dm_snapshot *s, ...@@ -653,10 +653,46 @@ static void __invalidate_snapshot(struct dm_snapshot *s,
dm_table_event(s->table); 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) static void pending_complete(struct pending_exception *pe, int success)
{ {
struct exception *e; struct exception *e;
struct pending_exception *primary_pe;
struct dm_snapshot *s = pe->snap; struct dm_snapshot *s = pe->snap;
struct bio *origin_bios = NULL; struct bio *origin_bios = NULL;
struct bio *snapshot_bios = NULL; struct bio *snapshot_bios = NULL;
...@@ -695,30 +731,7 @@ static void pending_complete(struct pending_exception *pe, int success) ...@@ -695,30 +731,7 @@ static void pending_complete(struct pending_exception *pe, int success)
out: out:
snapshot_bios = bio_list_get(&pe->snapshot_bios); snapshot_bios = bio_list_get(&pe->snapshot_bios);
origin_bios = put_pending_exception(pe);
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);
up_write(&s->lock); up_write(&s->lock);
...@@ -829,7 +842,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) ...@@ -829,7 +842,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
bio_list_init(&pe->origin_bios); bio_list_init(&pe->origin_bios);
bio_list_init(&pe->snapshot_bios); bio_list_init(&pe->snapshot_bios);
pe->primary_pe = NULL; pe->primary_pe = NULL;
atomic_set(&pe->sibling_count, 1); atomic_set(&pe->ref_count, 0);
pe->snap = s; pe->snap = s;
pe->started = 0; pe->started = 0;
...@@ -838,6 +851,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) ...@@ -838,6 +851,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
return NULL; return NULL;
} }
get_pending_exception(pe);
insert_exception(&s->pending, &pe->e); insert_exception(&s->pending, &pe->e);
out: out:
...@@ -1012,7 +1026,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) ...@@ -1012,7 +1026,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
* is already remapped in this snapshot * is already remapped in this snapshot
* and trigger an exception if not. * 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. * won't destroy the primary_pe while we're inside this loop.
*/ */
e = lookup_exception(&snap->complete, chunk); e = lookup_exception(&snap->complete, chunk);
...@@ -1043,8 +1057,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) ...@@ -1043,8 +1057,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
} }
if (!pe->primary_pe) { if (!pe->primary_pe) {
atomic_inc(&primary_pe->sibling_count);
pe->primary_pe = primary_pe; pe->primary_pe = primary_pe;
get_pending_exception(primary_pe);
} }
if (!pe->started) { if (!pe->started) {
...@@ -1057,20 +1071,20 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) ...@@ -1057,20 +1071,20 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
} }
if (!primary_pe) if (!primary_pe)
goto out; return r;
/* /*
* If this is the first time we're processing this chunk and * 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 * 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. * 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)); flush_bios(bio_list_get(&primary_pe->origin_bios));
free_pending_exception(primary_pe); free_pending_exception(primary_pe);
/* If we got here, pe_queue is necessarily empty. */ /* 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) ...@@ -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) list_for_each_entry_safe(pe, next_pe, &pe_queue, list)
start_copy(pe); start_copy(pe);
out:
return r; return r;
} }
......
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