Sort the snapshot list. Snapshot with the largest chunk size goes first, smallest last. This fixes corruption with multiple snapshots with different chunksizes (https://bugzilla.redhat.com/show_bug.cgi?id=182659) For example, let's have two snapshots with different chunksizes, the first snapshot has small chunksize and the second snapshot has large chunksize. Let's have chunks A, B, C in these snapshots: snapshot1: ====A==== ====B==== snapshot2: ==========C========== Now, write to the origin at the position "A/C" comes. It triggers reallocation of A, then reallocation of C and links C's primary_pe to A. Then, another write to the origin comes at the position "B/C". It creates pending exception for "B", then it finds "C", it has already pending exceptions and it is already linked to "A", so nothing is done with it. If the reallocation of "B" finishes before reallocation of "C", the second write is dispatched to the origin and causes data corruption in the chunk "C" in snapshot2. To avoid this situation, we maintain snapshots sorted, in a descending order according to a chunk size. Signed-off-by: Mikulas Patocka --- drivers/md/dm-snap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) Index: linux-2.6.31-fast-new-2/drivers/md/dm-snap.c =================================================================== --- linux-2.6.31-fast-new-2.orig/drivers/md/dm-snap.c 2009-10-16 21:47:52.000000000 +0200 +++ linux-2.6.31-fast-new-2/drivers/md/dm-snap.c 2009-10-16 21:47:57.000000000 +0200 @@ -305,6 +305,7 @@ static void __insert_origin(struct origi */ static int register_snapshot(struct dm_snapshot *snap) { + struct dm_snapshot *l; struct origin *o, *new_o; struct block_device *bdev = snap->origin->bdev; @@ -328,7 +329,11 @@ static int register_snapshot(struct dm_s __insert_origin(o); } - list_add_tail(&snap->list, &o->snapshots); + /* Sort the list according to chunk size, largest-first smallest-last */ + list_for_each_entry(l, &o->snapshots, list) + if (l->store->chunk_size < snap->store->chunk_size) + break; + list_add_tail(&snap->list, &l->list); up_write(&_origins_lock); return 0;