[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