rpms/kernel/F-10 linux-2.6-lib-idr.c-fix-rcu-related-race-with-idr_find.patch, NONE, 1.1 kernel.spec, 1.1179, 1.1180

Chuck Ebbert cebbert at fedoraproject.org
Tue Dec 9 12:55:51 UTC 2008


Author: cebbert

Update of /cvs/pkgs/rpms/kernel/F-10
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv19786

Modified Files:
	kernel.spec 
Added Files:
	linux-2.6-lib-idr.c-fix-rcu-related-race-with-idr_find.patch 
Log Message:
Revert idr patch from 2.6.27.8 that caused DRM breakage.

linux-2.6-lib-idr.c-fix-rcu-related-race-with-idr_find.patch:

--- NEW FILE linux-2.6-lib-idr.c-fix-rcu-related-race-with-idr_find.patch ---
>From 6ff2d39b91aec3dcae951afa982059e3dd9b49dc Mon Sep 17 00:00:00 2001
From: Manfred Spraul <manfred at colorfullife.com>
Date: Mon, 1 Dec 2008 13:14:02 -0800
Subject: lib/idr.c: fix rcu related race with idr_find

From: Manfred Spraul <manfred at colorfullife.com>

commit 6ff2d39b91aec3dcae951afa982059e3dd9b49dc upstream.

2nd part of the fixes needed for
http://bugzilla.kernel.org/show_bug.cgi?id=11796.

When the idr tree is either grown or shrunk, then the update to the number
of layers and the top pointer were not atomic.  This race caused crashes.

The attached patch fixes that by replicating the layers counter in each
layer, thus idr_find doesn't need idp->layers anymore.

Signed-off-by: Manfred Spraul <manfred at colorfullife.com>
Cc: Clement Calmels <cboulte at gmail.com>
Cc: Nadia Derbey <Nadia.Derbey at bull.net>
Cc: Pierre Peiffer <peifferp at gmail.com>
Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds at linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>

---
 include/linux/idr.h |    3 ++-
 lib/idr.c           |   14 ++++++++++++--
 2 files changed, 14 insertions(+), 3 deletions(-)

--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -52,13 +52,14 @@ struct idr_layer {
 	unsigned long		 bitmap; /* A zero bit means "space here" */
 	struct idr_layer	*ary[1<<IDR_BITS];
 	int			 count;	 /* When zero, we can release it */
+	int			 layer;	 /* distance from leaf */
 	struct rcu_head		 rcu_head;
 };
 
 struct idr {
 	struct idr_layer *top;
 	struct idr_layer *id_free;
-	int		  layers;
+	int		  layers; /* only valid without concurrent changes */
 	int		  id_free_cnt;
 	spinlock_t	  lock;
 };
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -185,6 +185,7 @@ static int sub_alloc(struct idr *idp, in
 			new = get_from_free_list(idp);
 			if (!new)
 				return -1;
+			new->layer = l-1;
 			rcu_assign_pointer(p->ary[m], new);
 			p->count++;
 		}
@@ -210,6 +211,7 @@ build_up:
 	if (unlikely(!p)) {
 		if (!(p = get_from_free_list(idp)))
 			return -1;
+		p->layer = 0;
 		layers = 1;
 	}
 	/*
@@ -237,6 +239,7 @@ build_up:
 		}
 		new->ary[0] = p;
 		new->count = 1;
+		new->layer = layers-1;
 		if (p->bitmap == IDR_FULL)
 			__set_bit(0, &new->bitmap);
 		p = new;
@@ -493,17 +496,21 @@ void *idr_find(struct idr *idp, int id)
 	int n;
 	struct idr_layer *p;
 
-	n = idp->layers * IDR_BITS;
 	p = rcu_dereference(idp->top);
+	if (!p)
+		return NULL;
+	n = (p->layer+1) * IDR_BITS;
 
 	/* Mask off upper bits we don't use for the search. */
 	id &= MAX_ID_MASK;
 
 	if (id >= (1 << n))
 		return NULL;
+	BUG_ON(n == 0);
 
 	while (n > 0 && p) {
 		n -= IDR_BITS;
+		BUG_ON(n != p->layer*IDR_BITS);
 		p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]);
 	}
 	return((void *)p);
@@ -582,8 +589,11 @@ void *idr_replace(struct idr *idp, void 
 	int n;
 	struct idr_layer *p, *old_p;
 
-	n = idp->layers * IDR_BITS;
 	p = idp->top;
+	if (!p)
+		return ERR_PTR(-EINVAL);
+
+	n = (p->layer+1) * IDR_BITS;
 
 	id &= MAX_ID_MASK;
 


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-10/kernel.spec,v
retrieving revision 1.1179
retrieving revision 1.1180
diff -u -r1.1179 -r1.1180
--- kernel.spec	9 Dec 2008 03:52:37 -0000	1.1179
+++ kernel.spec	9 Dec 2008 12:55:20 -0000	1.1180
@@ -575,6 +575,8 @@
 %if !%{nopatches}
 
 # revert upstream patches we get via other methods
+# revert 2.6.27.8 idr patch that breaks DRM
+Patch08: linux-2.6-lib-idr.c-fix-rcu-related-race-with-idr_find.patch
 Patch09: linux-2.6-upstream-reverts.patch
 # Git trees.
 Patch10: git-cpufreq.patch
@@ -1085,6 +1087,9 @@
 
 %if !%{nopatches}
 
+# revert IDR patch from 2.6.27.8
+ApplyPatch linux-2.6-lib-idr.c-fix-rcu-related-race-with-idr_find.patch -R
+
 # revert patches from upstream that conflict or that we get via other means
 C=$(wc -l $RPM_SOURCE_DIR/linux-2.6-upstream-reverts.patch | awk '{print $1}')
 if [ "$C" -gt 10 ]; then
@@ -1911,6 +1916,9 @@
 %kernel_variant_files -k vmlinux %{with_kdump} kdump
 
 %changelog
+* Tue Dec 09 2008 Chuck Ebbert <cebbert at redhat.com> 2.6.27.8-144
+- Revert idr patch from 2.6.27.8 that caused DRM breakage.
+
 * Mon Dec 08 2008 Chuck Ebbert <cebbert at redhat.com> 2.6.27.8-143
 - ATM security fix (CVE-2008-5079)
 




More information about the fedora-extras-commits mailing list