Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4454a621 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Alasdair G Kergon
Browse files

dm exception store: add merge specific methods



Add functions that decide how many consecutive chunks of snapshot to
merge back into the origin next and to update the metadata afterwards.

prepare_merge provides a pointer to the most recent still-to-be-merged
chunk and returns how many previous ones are consecutive and can be
processed together.

commit_merge removes the nr_merged most-recent chunks permanently from
the exception store.  The number must not exceed that returned by
prepare_merge.

Introduce NUM_SNAPSHOT_HDR_CHUNKS to show where the snapshot header
chunk is accounted for.

Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Reviewed-by: default avatarMike Snitzer <snitzer@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent 615d1eb9
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -74,6 +74,23 @@ struct dm_exception_store_type {
				  void (*callback) (void *, int success),
				  void *callback_context);

	/*
	 * Returns 0 if the exception store is empty.
	 *
	 * If there are exceptions still to be merged, sets
	 * *last_old_chunk and *last_new_chunk to the most recent
	 * still-to-be-merged chunk and returns the number of
	 * consecutive previous ones.
	 */
	int (*prepare_merge) (struct dm_exception_store *store,
			      chunk_t *last_old_chunk, chunk_t *last_new_chunk);

	/*
	 * Clear the last n exceptions.
	 * nr_merged must be <= the value returned by prepare_merge.
	 */
	int (*commit_merge) (struct dm_exception_store *store, int nr_merged);

	/*
	 * The snapshot is invalid, note this in the metadata.
	 */
+112 −2
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@
 */
#define SNAPSHOT_DISK_VERSION 1

#define NUM_SNAPSHOT_HDR_CHUNKS 1

struct disk_header {
	uint32_t magic;

@@ -120,7 +122,22 @@ struct pstore {

	/*
	 * The next free chunk for an exception.
	 *
	 * When creating exceptions, all the chunks here and above are
	 * free.  It holds the next chunk to be allocated.  On rare
	 * occasions (e.g. after a system crash) holes can be left in
	 * the exception store because chunks can be committed out of
	 * order.
	 *
	 * When merging exceptions, it does not necessarily mean all the
	 * chunks here and above are free.  It holds the value it would
	 * have held if all chunks had been committed in order of
	 * allocation.  Consequently the value may occasionally be
	 * slightly too low, but since it's only used for 'status' and
	 * it can never reach its minimum value too early this doesn't
	 * matter.
	 */

	chunk_t next_free;

	/*
@@ -409,6 +426,15 @@ static void write_exception(struct pstore *ps,
	e->new_chunk = cpu_to_le64(de->new_chunk);
}

static void clear_exception(struct pstore *ps, uint32_t index)
{
	struct disk_exception *e = get_exception(ps, index);

	/* clear it */
	e->old_chunk = 0;
	e->new_chunk = 0;
}

/*
 * Registers the exceptions that are present in the current area.
 * 'full' is filled in to indicate if the area has been
@@ -505,7 +531,8 @@ static void persistent_usage(struct dm_exception_store *store,
	 * Then there are (ps->current_area + 1) metadata chunks, each one
	 * separated from the next by ps->exceptions_per_area data chunks.
	 */
	*metadata_sectors = (ps->current_area + 2) * store->chunk_size;
	*metadata_sectors = (ps->current_area + 1 + NUM_SNAPSHOT_HDR_CHUNKS) *
			    store->chunk_size;
}

static void persistent_dtr(struct dm_exception_store *store)
@@ -680,6 +707,85 @@ static void persistent_commit_exception(struct dm_exception_store *store,
	ps->callback_count = 0;
}

static int persistent_prepare_merge(struct dm_exception_store *store,
				    chunk_t *last_old_chunk,
				    chunk_t *last_new_chunk)
{
	struct pstore *ps = get_info(store);
	struct disk_exception de;
	int nr_consecutive;
	int r;

	/*
	 * When current area is empty, move back to preceding area.
	 */
	if (!ps->current_committed) {
		/*
		 * Have we finished?
		 */
		if (!ps->current_area)
			return 0;

		ps->current_area--;
		r = area_io(ps, READ);
		if (r < 0)
			return r;
		ps->current_committed = ps->exceptions_per_area;
	}

	read_exception(ps, ps->current_committed - 1, &de);
	*last_old_chunk = de.old_chunk;
	*last_new_chunk = de.new_chunk;

	/*
	 * Find number of consecutive chunks within the current area,
	 * working backwards.
	 */
	for (nr_consecutive = 1; nr_consecutive < ps->current_committed;
	     nr_consecutive++) {
		read_exception(ps, ps->current_committed - 1 - nr_consecutive,
			       &de);
		if (de.old_chunk != *last_old_chunk - nr_consecutive ||
		    de.new_chunk != *last_new_chunk - nr_consecutive)
			break;
	}

	return nr_consecutive;
}

static int persistent_commit_merge(struct dm_exception_store *store,
				   int nr_merged)
{
	int r, i;
	struct pstore *ps = get_info(store);

	BUG_ON(nr_merged > ps->current_committed);

	for (i = 0; i < nr_merged; i++)
		clear_exception(ps, ps->current_committed - 1 - i);

	r = area_io(ps, WRITE);
	if (r < 0)
		return r;

	ps->current_committed -= nr_merged;

	/*
	 * At this stage, only persistent_usage() uses ps->next_free, so
	 * we make no attempt to keep ps->next_free strictly accurate
	 * as exceptions may have been committed out-of-order originally.
	 * Once a snapshot has become merging, we set it to the value it
	 * would have held had all the exceptions been committed in order.
	 *
	 * ps->current_area does not get reduced by prepare_merge() until
	 * after commit_merge() has removed the nr_merged previous exceptions.
	 */
	ps->next_free = (area_location(ps, ps->current_area) - 1) +
			(ps->current_committed + 1) + NUM_SNAPSHOT_HDR_CHUNKS;

	return 0;
}

static void persistent_drop_snapshot(struct dm_exception_store *store)
{
	struct pstore *ps = get_info(store);
@@ -705,7 +811,7 @@ static int persistent_ctr(struct dm_exception_store *store,
	ps->area = NULL;
	ps->zero_area = NULL;
	ps->header_area = NULL;
	ps->next_free = 2;	/* skipping the header and first area */
	ps->next_free = NUM_SNAPSHOT_HDR_CHUNKS + 1; /* header and 1st area */
	ps->current_committed = 0;

	ps->callback_count = 0;
@@ -748,6 +854,8 @@ static struct dm_exception_store_type _persistent_type = {
	.read_metadata = persistent_read_metadata,
	.prepare_exception = persistent_prepare_exception,
	.commit_exception = persistent_commit_exception,
	.prepare_merge = persistent_prepare_merge,
	.commit_merge = persistent_commit_merge,
	.drop_snapshot = persistent_drop_snapshot,
	.usage = persistent_usage,
	.status = persistent_status,
@@ -761,6 +869,8 @@ static struct dm_exception_store_type _persistent_compat_type = {
	.read_metadata = persistent_read_metadata,
	.prepare_exception = persistent_prepare_exception,
	.commit_exception = persistent_commit_exception,
	.prepare_merge = persistent_prepare_merge,
	.commit_merge = persistent_commit_merge,
	.drop_snapshot = persistent_drop_snapshot,
	.usage = persistent_usage,
	.status = persistent_status,