[dm-devel] [PATCH 18/18] dm-exstore-persistent-allow-metadata-reread
Mike Snitzer
snitzer at redhat.com
Tue Sep 29 22:53:43 UTC 2009
From: Jon Brassow <jbrassow at redhat.com>
This patch allows the persistent exception store to re-read
exception data from disk without adding duplicate entries
to the cache. Being able to re-read the metadata is especially
useful when trying to pick-up new data that may have been added.
This means the persistent exception store can be used as the
starting point for a cluster-aware exception store, which leads
to shared-storage cluster-aware snapshots.
Signed-off-by: Jonathan Brassow <jbrassow at redhat.com>
---
drivers/md/dm-snap-persistent.c | 129 +++++++++++++++++++++++++++++++-------
1 files changed, 105 insertions(+), 24 deletions(-)
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index d920f69..528832a 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -299,7 +299,7 @@ static int zero_disk_area(struct pstore *ps, chunk_t area)
return chunk_io(ps, ps->zero_area, area_location(ps, area), WRITE, 0);
}
-static int read_header(struct pstore *ps, int *new_snapshot)
+static int initial_read_header(struct pstore *ps, int *new_snapshot)
{
int r;
struct disk_header *dh;
@@ -344,7 +344,6 @@ static int read_header(struct pstore *ps, int *new_snapshot)
goto bad;
}
- *new_snapshot = 0;
ps->valid = le32_to_cpu(dh->valid);
ps->version = le32_to_cpu(dh->version);
chunk_size = le32_to_cpu(dh->chunk_size);
@@ -382,6 +381,51 @@ bad:
return r;
}
+/*
+ * Re-reading the header is all about checking the 'valid'
+ * field to ensure that this exception store has not been
+ * marked invalid. We can also do some sanity checks while
+ * we are at it.
+ */
+static int reread_header(struct pstore *ps)
+{
+ int r;
+ struct disk_header *dh;
+
+ r = chunk_io(ps, ps->header_area, 0, READ, 1);
+ if (r)
+ return r;
+
+ dh = (struct disk_header *) ps->header_area;
+
+ /*
+ * If any of these conditions is true it means that the
+ * exception store underneath us has changed in ways we
+ * cannot handle. What's worse, if we proceed, we can
+ * corrupt the exception store.
+ */
+ if ((le32_to_cpu(dh->magic) != SNAP_MAGIC) ||
+ (ps->version != le32_to_cpu(dh->version)) ||
+ (ps->store->chunk_size != le32_to_cpu(dh->chunk_size))) {
+ DMERR("Exception store parameters changed while in use.");
+ ps->valid = 0;
+ return -EINVAL;
+ }
+
+ ps->valid = le32_to_cpu(dh->valid);
+
+ return 0;
+}
+
+static int read_header(struct pstore *ps, int *new_snapshot)
+{
+ *new_snapshot = 0;
+ if (ps->io_client)
+ return reread_header(ps);
+
+ return initial_read_header(ps, new_snapshot);
+}
+
static int write_header(struct pstore *ps)
{
struct disk_header *dh;
@@ -457,7 +501,18 @@ static int insert_exceptions(struct pstore *ps, int *full)
/* presume the area is full */
*full = 1;
- for (i = 0; i < ps->exceptions_per_area; i++) {
+ /*
+ * We start the loop at ps->current_committed. If this is a full
+ * read of the metadata area, it will be zero until we
+ * are finished reading. If this is a partial read to catch
+ * any updates to the metadata area, then we will start at
+ * the position that was last known to be empty. (We must reset
+ * ps->current_committed, otherwise metadata updates involving
+ * more than one area will skip over some exceptions.
+ */
+ i = ps->current_committed;
+ ps->current_committed = 0;
+ for (; i < ps->exceptions_per_area; i++) {
read_exception(ps, i, &de);
/*
@@ -494,10 +549,12 @@ static int read_exceptions(struct pstore *ps)
int r, full = 1;
/*
- * Keeping reading chunks and inserting exceptions until
- * we find a partially full area.
+ * We start from 'ps->current_area' and keep reading chunks
+ * and inserting exceptions until we find a partially full
+ * area. ('ps->current_area' must be initialized to 0 for the
+ * first complete read.)
*/
- for (ps->current_area = 0; full; ps->current_area++) {
+ for (; full; ps->current_area++) {
r = area_io(ps, READ);
if (r)
return r;
@@ -543,23 +600,17 @@ static void persistent_dtr(struct dm_exception_store *store)
kfree(ps);
}
-static int persistent_read_metadata(struct dm_exception_store *store)
+static int do_initial_metadata_read(struct dm_exception_store *store,
+ int new_snapshot)
{
- int r, uninitialized_var(new_snapshot);
+ int r;
struct pstore *ps = get_info(store);
/*
- * Read the snapshot header.
- */
- r = read_header(ps, &new_snapshot);
- if (r)
- return r;
-
- /*
* Now we know correct chunk_size, complete the initialisation.
*/
ps->exceptions_per_area = (ps->store->chunk_size << SECTOR_SHIFT) /
- sizeof(struct disk_exception);
+ sizeof(struct disk_exception);
ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
sizeof(*ps->callbacks));
if (!ps->callbacks)
@@ -572,24 +623,48 @@ static int persistent_read_metadata(struct dm_exception_store *store)
r = write_header(ps);
if (r) {
DMWARN("write_header failed");
- return r;
+ goto fail;
}
ps->current_area = 0;
zero_memory_area(ps);
r = zero_disk_area(ps, 0);
- if (r)
+ if (r) {
DMWARN("zero_disk_area(0) failed");
- return r;
+ goto fail;
+ }
}
+
/*
* Sanity checks.
*/
- if (ps->version != SNAPSHOT_DISK_VERSION) {
- DMWARN("unable to handle snapshot disk version %d",
- ps->version);
- return -EINVAL;
- }
+ if (ps->version == SNAPSHOT_DISK_VERSION)
+ return 0;
+
+ DMWARN("unable to handle snapshot disk version %d",
+ ps->version);
+ r = -EINVAL;
+
+fail:
+ vfree(ps->callbacks);
+ ps->callbacks = NULL;
+ ps->exceptions_per_area = 0;
+ ps->valid = 0;
+
+ return r;
+}
+
+static int persistent_read_metadata(struct dm_exception_store *store)
+{
+ int r, uninitialized_var(new_snapshot);
+ struct pstore *ps = get_info(store);
+
+ /*
+ * Read the snapshot header.
+ */
+ r = read_header(ps, &new_snapshot);
+ if (r)
+ return r;
/*
* Metadata are valid, but snapshot is invalidated
@@ -597,6 +672,12 @@ static int persistent_read_metadata(struct dm_exception_store *store)
if (!ps->valid)
return 1;
+ if (!ps->callbacks) {
+ r = do_initial_metadata_read(store, new_snapshot);
+ if (r)
+ return r;
+ }
+
/*
* Read the metadata.
*/
--
1.6.2.5
More information about the dm-devel
mailing list