Sophie

Sophie

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

kernel-2.6.18-238.el5.src.rpm

From: Josef Bacik <josef@redhat.com>
Date: Tue, 1 Dec 2009 20:06:54 -0500
Subject: [fs] jbd: fix race in slab creation/deletion
Message-id: <20091201200654.GC20032@localhost.localdomain>
Patchwork-id: 21597
O-Subject: Re: [PATCH] [RHEL5.5 PATCH] jbd: fix race in slab creation/deletion
Bugzilla: 496847
RH-Acked-by: Eric Sandeen <sandeen@redhat.com>

This patch is in reference to bz 496847.  If we mount multiple jbd based fs's at
the same time we can race on creating the jbd slab caches.  This isn't a problem
on most systems because root is usuall ext3, but in this customers case they are
using diskless systems, which then at some point mount a bunch of ext3 fs's at
once, which causes problems.  This was fixed upstream in a much more invasive
way by simply eliminating the jbd slab caches, but Lustre was kind enough to
pass along this much less intrusive patch to resolve the problem.

diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index b118f0c..394e568 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -1646,6 +1646,7 @@ void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry)
 #define JBD_MAX_SLABS 5
 #define JBD_SLAB_INDEX(size)  (size >> 11)
 
+static DECLARE_RWSEM(jbd_slab_lock); /* protect jbd_slab[] */
 static kmem_cache_t *jbd_slab[JBD_MAX_SLABS];
 static const char *jbd_slab_names[JBD_MAX_SLABS] = {
 	"jbd_1k", "jbd_2k", "jbd_4k", NULL, "jbd_8k"
@@ -1655,24 +1656,27 @@ static void journal_destroy_jbd_slabs(void)
 {
 	int i;
 
+	down_write(&jbd_slab_lock);
 	for (i = 0; i < JBD_MAX_SLABS; i++) {
 		if (jbd_slab[i])
 			kmem_cache_destroy(jbd_slab[i]);
 		jbd_slab[i] = NULL;
 	}
+	up_write(&jbd_slab_lock);
 }
 
 static int journal_create_jbd_slab(size_t slab_size)
 {
-	int i = JBD_SLAB_INDEX(slab_size);
+	int rc = 0, i = JBD_SLAB_INDEX(slab_size);
 
 	BUG_ON(i >= JBD_MAX_SLABS);
 
 	/*
 	 * Check if we already have a slab created for this size
 	 */
+	down_write(&jbd_slab_lock);
 	if (jbd_slab[i])
-		return 0;
+		goto out_lock;
 
 	/*
 	 * Create a slab and force alignment to be same as slabsize -
@@ -1683,9 +1687,11 @@ static int journal_create_jbd_slab(size_t slab_size)
 				slab_size, slab_size, 0, NULL, NULL);
 	if (!jbd_slab[i]) {
 		printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
 	}
-	return 0;
+out_lock:
+	up_write(&jbd_slab_lock);
+	return rc;
 }
 
 void * jbd_slab_alloc(size_t size, gfp_t flags)