aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-snap.c
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2008-10-30 09:33:16 -0400
committerAlasdair G Kergon <agk@redhat.com>2008-10-30 09:33:16 -0400
commit879129d208f725267366296b631aef31409cf304 (patch)
tree7dd927ae094580f6a3fe420c0cc5f8e251ce9e9e /drivers/md/dm-snap.c
parent60c856c8e2f57a3f69c505735ef66e3719ea0bd6 (diff)
dm snapshot: wait for chunks in destructor
If there are several snapshots sharing an origin and one is removed while the origin is being written to, the snapshot's mempool may get deleted while elements are still referenced. Prior to dm-snapshot-use-per-device-mempools.patch the pending exceptions may still have been referenced after the snapshot was destroyed, but this was not a problem because the shared mempool was still there. This patch fixes the problem by tracking the number of mempool elements in use. The scenario: - You have an origin and two snapshots 1 and 2. - Someone writes to the origin. - It creates two exceptions in the snapshots, snapshot 1 will be primary exception, snapshot 2's pending_exception->primary_pe will point to the exception in snapshot 1. - The exceptions are being relocated, relocation of exception 1 finishes (but it's pending_exception is still allocated, because it is referenced by an exception from snapshot 2) - The user lvremoves snapshot 1 --- it calls just suspend (does nothing) and destructor. md->pending is zero (there is no I/O submitted to the snapshot by md layer), so it won't help us. - The destructor waits for kcopyd jobs to finish on snapshot 1 --- but there are none. - The destructor on snapshot 1 cleans up everything. - The relocation of exception on snapshot 2 finishes, it drops reference on primary_pe. This frees its primary_pe pointer. Primary_pe points to pending exception created for snapshot 1. So it frees memory into non-existing mempool. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r--drivers/md/dm-snap.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 746603b42f86..6c96db26b87c 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -370,6 +370,7 @@ static struct dm_snap_pending_exception *alloc_pending_exception(struct dm_snaps
370 struct dm_snap_pending_exception *pe = mempool_alloc(s->pending_pool, 370 struct dm_snap_pending_exception *pe = mempool_alloc(s->pending_pool,
371 GFP_NOIO); 371 GFP_NOIO);
372 372
373 atomic_inc(&s->pending_exceptions_count);
373 pe->snap = s; 374 pe->snap = s;
374 375
375 return pe; 376 return pe;
@@ -377,7 +378,11 @@ static struct dm_snap_pending_exception *alloc_pending_exception(struct dm_snaps
377 378
378static void free_pending_exception(struct dm_snap_pending_exception *pe) 379static void free_pending_exception(struct dm_snap_pending_exception *pe)
379{ 380{
380 mempool_free(pe, pe->snap->pending_pool); 381 struct dm_snapshot *s = pe->snap;
382
383 mempool_free(pe, s->pending_pool);
384 smp_mb__before_atomic_dec();
385 atomic_dec(&s->pending_exceptions_count);
381} 386}
382 387
383static void insert_completed_exception(struct dm_snapshot *s, 388static void insert_completed_exception(struct dm_snapshot *s,
@@ -602,6 +607,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
602 607
603 s->valid = 1; 608 s->valid = 1;
604 s->active = 0; 609 s->active = 0;
610 atomic_set(&s->pending_exceptions_count, 0);
605 init_rwsem(&s->lock); 611 init_rwsem(&s->lock);
606 spin_lock_init(&s->pe_lock); 612 spin_lock_init(&s->pe_lock);
607 s->ti = ti; 613 s->ti = ti;
@@ -728,6 +734,14 @@ static void snapshot_dtr(struct dm_target *ti)
728 /* After this returns there can be no new kcopyd jobs. */ 734 /* After this returns there can be no new kcopyd jobs. */
729 unregister_snapshot(s); 735 unregister_snapshot(s);
730 736
737 while (atomic_read(&s->pending_exceptions_count))
738 yield();
739 /*
740 * Ensure instructions in mempool_destroy aren't reordered
741 * before atomic_read.
742 */
743 smp_mb();
744
731#ifdef CONFIG_DM_DEBUG 745#ifdef CONFIG_DM_DEBUG
732 for (i = 0; i < DM_TRACKED_CHUNK_HASH_SIZE; i++) 746 for (i = 0; i < DM_TRACKED_CHUNK_HASH_SIZE; i++)
733 BUG_ON(!hlist_empty(&s->tracked_chunk_hash[i])); 747 BUG_ON(!hlist_empty(&s->tracked_chunk_hash[i]));