When you suspend a snapshot or snapshot-origin, dm_suspend() will sleep until all I/O initiated on that device has completed. In persistent_commit() we invoke callbacks into dm-snap.c when we write the exceptions metadata to disk. These callbacks, in turn, flush any pending I/O. However, only after these callbacks have been does persistent_commit() zero the next metadata area if the current area has been filled. So, you can have a sequence as follows: 1) Write to a snapshot or snapshot-origin, triggering an exception copy 2) Suspend the device, causing the caller to sleep 3) When the exception copy completes, write the metadata to disk 4) Invoke the callbacks, causing waiting I/O to be flushed 5) Notice this metadata area has been filled, zero the next area 6) Sleeping process resumes, and then proceeds to reload the device 7) The exception metadata is re-read from disk by newly target Now, if the write in (5) is delayed until after the reads in (7) are performed, and then we can read an uninitialised metadata area in (7), possibly causing device loading to fail. Index: linux-2.6.16.i686/drivers/md/dm-exception-store.c =================================================================== --- linux-2.6.16.i686.orig/drivers/md/dm-exception-store.c 2006-04-28 10:18:54.000000000 +0100 +++ linux-2.6.16.i686/drivers/md/dm-exception-store.c 2006-04-28 10:38:37.000000000 +0100 @@ -540,6 +540,15 @@ static void persistent_commit(struct exc if (r) ps->valid = 0; + /* + * Have we completely filled the current area ? + */ + if (ps->current_committed == ps->exceptions_per_area) { + ps->current_committed = 0; + if (zero_area(ps, ps->current_area + 1)) + ps->valid = 0; + } + for (i = 0; i < ps->callback_count; i++) { cb = ps->callbacks + i; cb->callback(cb->context, r == 0 ? 1 : 0); @@ -547,16 +556,6 @@ static void persistent_commit(struct exc 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; - } } static void persistent_drop(struct exception_store *store)