From: Mikulas Patocka Change snapshot per-module mempool to per-device mempool. Per-module mempools could cause a deadlock if multiple snapshot devices are stacked above each other. Signed-off-by: Mikulas Patocka Signed-off-by: Alasdair G Kergon --- drivers/md/dm-snap.c | 40 ++++++++++++++++++++++------------------ drivers/md/dm-snap.h | 2 ++ 2 files changed, 24 insertions(+), 18 deletions(-) Index: linux-2.6.26/drivers/md/dm-snap.c =================================================================== --- linux-2.6.26.orig/drivers/md/dm-snap.c 2008-07-20 18:46:12.000000000 +0100 +++ linux-2.6.26/drivers/md/dm-snap.c 2008-07-20 18:46:13.000000000 +0100 @@ -96,7 +96,6 @@ struct dm_snap_pending_exception { */ static struct kmem_cache *exception_cache; static struct kmem_cache *pending_cache; -static mempool_t *pending_pool; struct dm_snap_tracked_chunk { struct hlist_node node; @@ -364,14 +363,19 @@ static void free_exception(struct dm_sna kmem_cache_free(exception_cache, e); } -static struct dm_snap_pending_exception *alloc_pending_exception(void) +static struct dm_snap_pending_exception *alloc_pending_exception(struct dm_snapshot *s) { - return mempool_alloc(pending_pool, GFP_NOIO); + struct dm_snap_pending_exception *pe = mempool_alloc(s->pending_pool, + GFP_NOIO); + + pe->snap = s; + + return pe; } static void free_pending_exception(struct dm_snap_pending_exception *pe) { - mempool_free(pe, pending_pool); + mempool_free(pe, pe->snap->pending_pool); } static void insert_completed_exception(struct dm_snapshot *s, @@ -627,12 +631,18 @@ static int snapshot_ctr(struct dm_target goto bad5; } + s->pending_pool = mempool_create_slab_pool(MIN_IOS, pending_cache); + if (!s->pending_pool) { + ti->error = "Could not allocate mempool for pending exceptions"; + goto bad6; + } + s->tracked_chunk_pool = mempool_create_slab_pool(MIN_IOS, tracked_chunk_cache); if (!s->tracked_chunk_pool) { ti->error = "Could not allocate tracked_chunk mempool for " "tracking reads"; - goto bad6; + goto bad_tracked_chunk_pool; } for (i = 0; i < DM_TRACKED_CHUNK_HASH_SIZE; i++) @@ -669,6 +679,9 @@ static int snapshot_ctr(struct dm_target bad_load_and_register: mempool_destroy(s->tracked_chunk_pool); + bad_tracked_chunk_pool: + mempool_destroy(s->pending_pool); + bad6: dm_kcopyd_client_destroy(s->kcopyd_client); @@ -723,6 +736,8 @@ static void snapshot_dtr(struct dm_targe __free_exceptions(s); + mempool_destroy(s->pending_pool); + dm_put_device(ti, s->origin); dm_put_device(ti, s->cow); @@ -969,7 +984,7 @@ __find_pending_exception(struct dm_snaps * to hold the lock while we do this. */ up_write(&s->lock); - pe = alloc_pending_exception(); + pe = alloc_pending_exception(s); down_write(&s->lock); if (!s->valid) { @@ -989,7 +1004,6 @@ __find_pending_exception(struct dm_snaps bio_list_init(&pe->snapshot_bios); pe->primary_pe = NULL; atomic_set(&pe->ref_count, 0); - pe->snap = s; pe->started = 0; if (s->store.prepare_exception(&s->store, &pe->e)) { @@ -1418,24 +1432,15 @@ static int __init dm_snapshot_init(void) goto bad5; } - pending_pool = mempool_create_slab_pool(128, pending_cache); - if (!pending_pool) { - DMERR("Couldn't create pending pool."); - r = -ENOMEM; - goto bad_pending_pool; - } - ksnapd = create_singlethread_workqueue("ksnapd"); if (!ksnapd) { DMERR("Failed to create ksnapd workqueue."); r = -ENOMEM; - goto bad6; + goto bad_pending_pool; } return 0; - bad6: - mempool_destroy(pending_pool); bad_pending_pool: kmem_cache_destroy(tracked_chunk_cache); bad5: @@ -1466,7 +1471,6 @@ static void __exit dm_snapshot_exit(void DMERR("origin unregister failed %d", r); exit_origin_hash(); - mempool_destroy(pending_pool); kmem_cache_destroy(pending_cache); kmem_cache_destroy(exception_cache); kmem_cache_destroy(tracked_chunk_cache); Index: linux-2.6.26/drivers/md/dm-snap.h =================================================================== --- linux-2.6.26.orig/drivers/md/dm-snap.h 2008-07-20 18:46:09.000000000 +0100 +++ linux-2.6.26/drivers/md/dm-snap.h 2008-07-20 18:46:13.000000000 +0100 @@ -161,6 +161,8 @@ struct dm_snapshot { /* The last percentage we notified */ int last_percent; + mempool_t *pending_pool; + struct exception_table pending; struct exception_table complete;