diff options
author | Sonny Rao <sonny@burdell.org> | 2006-06-25 08:49:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:01:26 -0400 |
commit | 1eec00565d849ceda67f425e089c3233e3ef2ca2 (patch) | |
tree | 83f5bb133755ddde28772e64b99ff0cfd701f0d7 | |
parent | a45219483e2894af3c07f959cbd4edb4575b4f8c (diff) |
[PATCH] fix race in idr code
I ran into a bug where the kernel died in the idr code:
cpu 0x1d: Vector: 300 (Data Access) at [c000000b7096f710]
pc: c0000000001f8984: .idr_get_new_above_int+0x140/0x330
lr: c0000000001f89b4: .idr_get_new_above_int+0x170/0x330
sp: c000000b7096f990
msr: 800000000000b032
dar: 0
dsisr: 40010000
current = 0xc000000b70d43830
paca = 0xc000000000556900
pid = 2022, comm = hwup
1d:mon> t
[c000000b7096f990] c0000000000d2ad8 .expand_files+0x2e8/0x364 (unreliable)
[c000000b7096faa0] c0000000001f8bf8 .idr_get_new_above+0x18/0x68
[c000000b7096fb20] c00000000002a054 .init_new_context+0x5c/0xf0
[c000000b7096fbc0] c000000000049dc8 .copy_process+0x91c/0x1404
[c000000b7096fcd0] c00000000004a988 .do_fork+0xd8/0x224
[c000000b7096fdc0] c00000000000ebdc .sys_clone+0x5c/0x74
[c000000b7096fe30] c000000000008950 .ppc_clone+0x8/0xc
-rw-r--r-- | lib/idr.c | 16 |
1 files changed, 12 insertions, 4 deletions
@@ -48,15 +48,21 @@ static struct idr_layer *alloc_layer(struct idr *idp) | |||
48 | return(p); | 48 | return(p); |
49 | } | 49 | } |
50 | 50 | ||
51 | /* only called when idp->lock is held */ | ||
52 | static void __free_layer(struct idr *idp, struct idr_layer *p) | ||
53 | { | ||
54 | p->ary[0] = idp->id_free; | ||
55 | idp->id_free = p; | ||
56 | idp->id_free_cnt++; | ||
57 | } | ||
58 | |||
51 | static void free_layer(struct idr *idp, struct idr_layer *p) | 59 | static void free_layer(struct idr *idp, struct idr_layer *p) |
52 | { | 60 | { |
53 | /* | 61 | /* |
54 | * Depends on the return element being zeroed. | 62 | * Depends on the return element being zeroed. |
55 | */ | 63 | */ |
56 | spin_lock(&idp->lock); | 64 | spin_lock(&idp->lock); |
57 | p->ary[0] = idp->id_free; | 65 | __free_layer(idp, p); |
58 | idp->id_free = p; | ||
59 | idp->id_free_cnt++; | ||
60 | spin_unlock(&idp->lock); | 66 | spin_unlock(&idp->lock); |
61 | } | 67 | } |
62 | 68 | ||
@@ -184,12 +190,14 @@ build_up: | |||
184 | * The allocation failed. If we built part of | 190 | * The allocation failed. If we built part of |
185 | * the structure tear it down. | 191 | * the structure tear it down. |
186 | */ | 192 | */ |
193 | spin_lock(&idp->lock); | ||
187 | for (new = p; p && p != idp->top; new = p) { | 194 | for (new = p; p && p != idp->top; new = p) { |
188 | p = p->ary[0]; | 195 | p = p->ary[0]; |
189 | new->ary[0] = NULL; | 196 | new->ary[0] = NULL; |
190 | new->bitmap = new->count = 0; | 197 | new->bitmap = new->count = 0; |
191 | free_layer(idp, new); | 198 | __free_layer(idp, new); |
192 | } | 199 | } |
200 | spin_unlock(&idp->lock); | ||
193 | return -1; | 201 | return -1; |
194 | } | 202 | } |
195 | new->ary[0] = p; | 203 | new->ary[0] = p; |