[dm-devel] Re: [linux-lvm] snapshot with 2.6.5 kernel
Dave Olien
dmo at osdl.org
Thu May 13 01:32:22 UTC 2004
Sorry, I forgot to include the patch... here it is..
On Wed, May 12, 2004 at 06:24:02PM -0700, Dave Olien wrote:
>
> Here's the patch I have come up with. If you can give it a try, that'd
> be good.
diff -ur linux-2.6.6-udm1-original/drivers/md/dm-exception-store.c linux-2.6.6-udm1-patched/drivers/md/dm-exception-store.c
--- linux-2.6.6-udm1-original/drivers/md/dm-exception-store.c 2004-05-07 14:28:31.000000000 -0700
+++ linux-2.6.6-udm1-patched/drivers/md/dm-exception-store.c 2004-05-12 15:41:36.000000000 -0700
@@ -118,9 +118,12 @@
*/
uint32_t current_committed;
- atomic_t pending_count;
+ uint32_t pending_count;
uint32_t callback_count;
struct commit_callback *callbacks;
+ wait_queue_head_t pstore_wait_queue;
+ spinlock_t pstore_lock;
+ int pstore_area_write;
};
static inline unsigned int sectors_to_pages(unsigned int sectors)
@@ -131,7 +134,7 @@
static int alloc_area(struct pstore *ps)
{
int r = -ENOMEM;
- size_t len, nr_pages;
+ size_t len;
len = ps->chunk_size << SECTOR_SHIFT;
@@ -143,15 +146,11 @@
if (!ps->area)
return r;
- nr_pages = sectors_to_pages(ps->chunk_size);
return 0;
}
static void free_area(struct pstore *ps)
{
- size_t nr_pages;
-
- nr_pages = sectors_to_pages(ps->chunk_size);
vfree(ps->area);
}
@@ -207,15 +206,13 @@
dh = (struct disk_header *) ps->area;
- if (le32_to_cpu(dh->magic) == 0) {
+ if (le32_to_cpu(dh->magic) == 0)
*new_snapshot = 1;
-
- } else if (le32_to_cpu(dh->magic) == SNAP_MAGIC) {
+ else if (le32_to_cpu(dh->magic) == SNAP_MAGIC) {
*new_snapshot = 0;
ps->valid = le32_to_cpu(dh->valid);
ps->version = le32_to_cpu(dh->version);
ps->chunk_size = le32_to_cpu(dh->chunk_size);
-
} else {
DMWARN("Invalid/corrupt snapshot");
r = -ENXIO;
@@ -241,6 +238,8 @@
/*
* Access functions for the disk exceptions, these do the endian conversions.
+ * The disk exceptions reside in the current memory-resident exception
+ * buffer
*/
static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
{
@@ -437,8 +436,11 @@
sector_t size = get_dev_size(store->snap->cow->bdev);
/* Is there enough room ? */
- if (size < ((ps->next_free + 1) * store->snap->chunk_size))
+ spin_lock_irq(&ps->pstore_lock);
+ if (size < ((ps->next_free + 1) * store->snap->chunk_size)) {
+ spin_unlock_irq(&ps->pstore_lock);
return -ENOSPC;
+ }
e->new_chunk = ps->next_free;
@@ -450,7 +452,8 @@
if ((++ps->next_free % stride) == 1)
ps->next_free++;
- atomic_inc(&ps->pending_count);
+ ps->pending_count++;
+ spin_unlock_irq(&ps->pstore_lock);
return 0;
}
@@ -465,15 +468,33 @@
struct disk_exception de;
struct commit_callback *cb;
+ spin_lock_irq(&ps->pstore_lock);
+
+ /*
+ * This can be called concurrently by per-cpu threads of the kcopyd
+ * work queue.
+ */
+ while (ps->pstore_area_write) {
+ DECLARE_WAITQUEUE(wait, current);
+ /*
+ * wait until the area write is complete
+ * and the next meta data area is zero'd.
+ */
+ add_wait_queue(&ps->pstore_wait_queue, &wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&ps->pstore_lock);
+ schedule();
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&ps->pstore_wait_queue, &wait);
+ spin_lock_irq(&ps->pstore_lock);
+ }
+
de.old_chunk = e->old_chunk;
de.new_chunk = e->new_chunk;
write_exception(ps, ps->current_committed++, &de);
/*
- * Add the callback to the back of the array. This code
- * is the only place where the callback array is
- * manipulated, and we know that it will never be called
- * multiple times concurrently.
+ * Add the callback to the back of the array.
*/
cb = ps->callbacks + ps->callback_count++;
cb->callback = callback;
@@ -484,8 +505,14 @@
* filled this metadata area we commit the exceptions to
* disk.
*/
- if (atomic_dec_and_test(&ps->pending_count) ||
+ if ((--ps->pending_count) ||
(ps->current_committed == ps->exceptions_per_area)) {
+ ps->pstore_area_write = 1;
+ spin_unlock_irq(&ps->pstore_lock);
+ /*
+ * we are guaranteed that only ONE thread at a time
+ * goes through this code.
+ */
r = area_io(ps, ps->current_area, WRITE);
if (r)
ps->valid = 0;
@@ -496,17 +523,20 @@
}
ps->callback_count = 0;
+ /*
+ * Have we completely filled the current area ?
+ */
+ if (ps->current_committed == ps->exceptions_per_area) {
+ ps->current_committed = 0;
+ r = zero_area(ps, ps->current_area + 1);
+ if (r)
+ ps->valid = 0;
+ }
+ spin_lock_irq(&ps->pstore_lock);
+ ps->pstore_area_write = 0;
+ wake_up_all(&ps->pstore_wait_queue);
}
-
- /*
- * Have we completely filled the current area ?
- */
- if (ps->current_committed == ps->exceptions_per_area) {
- ps->current_committed = 0;
- r = zero_area(ps, ps->current_area + 1);
- if (r)
- ps->valid = 0;
- }
+ spin_unlock_irq(&ps->pstore_lock);
}
static void persistent_drop(struct exception_store *store)
@@ -542,6 +572,9 @@
sizeof(struct disk_exception);
ps->next_free = 2; /* skipping the header and first area */
ps->current_committed = 0;
+ init_waitqueue_head(&ps->pstore_wait_queue);
+ spin_lock_init(&ps->pstore_lock);
+ ps->pstore_area_write = 0;
r = alloc_area(ps);
if (r)
@@ -551,7 +584,7 @@
* Allocate space for all the callbacks.
*/
ps->callback_count = 0;
- atomic_set(&ps->pending_count, 0);
+ ps->pending_count = 0;
ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
sizeof(*ps->callbacks));
More information about the dm-devel
mailing list