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

[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
Loading
Loading
Loading
Loading
+48 −35
Original line number Diff line number Diff line
@@ -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;
}