Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1738

kernel-2.6.18-238.el5.src.rpm

From: Mikulas Patocka <mpatocka@redhat.com>
Date: Mon, 1 Sep 2008 18:00:18 -0400
Subject: [md] dm kcopyd: private mempool
Message-id: Pine.LNX.4.64.0809011757100.12369@hs20-bc2-1.build.redhat.com
O-Subject: [RHEL 5.3 PATCH 2/2] bz460845 Deadlock with nested LVMs
Bugzilla: 460845
RH-Acked-by: Alasdair G Kergon <agk@redhat.com>

This is another patch for the same bug --- kcopyd uses shared mempool of
reserved memory for all clients and it could cause deadlocks with nested
LVM (if the upper layer drains the mempool and the lower layer has no
memory to make progress). This patch changes it to per-client mempool.

This is backported upstream patch.

Upstream commit: 08d8757a4d52d21d825b9170af36f2696d1da1a8 (2.6.26-rc1)

Testing: compiled on a workstation and tested dm-raid1 and dm-snapshot.

diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index 6ebc27c..b079d04 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -42,6 +42,8 @@ struct kcopyd_client {
 #ifndef __GENKSYMS__
 	struct dm_io_client *io_client;
 
+	mempool_t *job_pool;
+
 	struct workqueue_struct *kcopyd_wq;
 	struct work_struct kcopyd_work;
 
@@ -221,7 +223,6 @@ struct kcopyd_job {
 #define MIN_JOBS 512
 
 static kmem_cache_t *_job_cache;
-static mempool_t *_job_pool;
 
 static int jobs_init(void)
 {
@@ -232,20 +233,12 @@ static int jobs_init(void)
 	if (!_job_cache)
 		return -ENOMEM;
 
-	_job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
-	if (!_job_pool) {
-		kmem_cache_destroy(_job_cache);
-		return -ENOMEM;
-	}
-
 	return 0;
 }
 
 static void jobs_exit(void)
 {
-	mempool_destroy(_job_pool);
 	kmem_cache_destroy(_job_cache);
-	_job_pool = NULL;
 	_job_cache = NULL;
 }
 
@@ -298,7 +291,7 @@ static int run_complete_job(struct kcopyd_job *job)
 	struct kcopyd_client *kc = job->kc;
 
 	kcopyd_put_pages(kc, job->pages);
-	mempool_free(job, _job_pool);
+	mempool_free(job, kc->job_pool);
 	fn(read_err, write_err, context);
 
 	if (atomic_dec_and_test(&kc->nr_jobs))
@@ -489,7 +482,8 @@ static void segment_complete(int read_err,
 
 	if (count) {
 		int i;
-		struct kcopyd_job *sub_job = mempool_alloc(_job_pool, GFP_NOIO);
+		struct kcopyd_job *sub_job = mempool_alloc(job->kc->job_pool,
+							   GFP_NOIO);
 
 		*sub_job = *job;
 		sub_job->source.sector += progress;
@@ -513,7 +507,7 @@ static void segment_complete(int read_err,
 		 * after we've completed.
 		 */
 		job->fn(read_err, write_err, job->context);
-		mempool_free(job, _job_pool);
+		mempool_free(job, job->kc->job_pool);
 	}
 }
 
@@ -540,7 +534,7 @@ int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
 	/*
 	 * Allocate a new job.
 	 */
-	job = mempool_alloc(_job_pool, GFP_NOIO);
+	job = mempool_alloc(kc->job_pool, GFP_NOIO);
 
 	/*
 	 * set up for the read.
@@ -666,10 +660,19 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
 	INIT_LIST_HEAD(&kc->io_jobs);
 	INIT_LIST_HEAD(&kc->pages_jobs);
 
+	kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
+	if (!kc->job_pool) {
+		r = -ENOMEM;
+		kfree(kc);
+		kcopyd_exit();
+		return r;
+	}
+
 	INIT_WORK(&kc->kcopyd_work, do_work, kc);
 	kc->kcopyd_wq = create_singlethread_workqueue("kcopyd");
 	if (!kc->kcopyd_wq) {
 		r = -ENOMEM;
+		mempool_destroy(kc->job_pool);
 		kfree(kc);
 		kcopyd_exit();
 		return r;
@@ -680,6 +683,7 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
 	r = client_alloc_pages(kc, nr_pages);
 	if (r) {
 		destroy_workqueue(kc->kcopyd_wq);
+		mempool_destroy(kc->job_pool);
 		kfree(kc);
 		kcopyd_exit();
 		return r;
@@ -690,6 +694,7 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
 		r = PTR_ERR(kc->io_client);
 		client_free_pages(kc);
 		destroy_workqueue(kc->kcopyd_wq);
+		mempool_destroy(kc->job_pool);
 		kfree(kc);
 		kcopyd_exit();
 		return r;
@@ -715,6 +720,7 @@ void kcopyd_client_destroy(struct kcopyd_client *kc)
 	dm_io_client_destroy(kc->io_client);
 	client_free_pages(kc);
 	client_del(kc);
+	mempool_destroy(kc->job_pool);
 	kfree(kc);
 	kcopyd_exit();
 }