[PATCH] dm snapshot: tidy pe ref counting
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>
This commit is contained in:
committed by
Linus Torvalds
parent
ca3a931fd3
commit
4b832e8de2
@@ -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 {
|
|||||||
* 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,
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user