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; |
