diff options
author | Jack Steiner <steiner@sgi.com> | 2009-12-15 19:48:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 10:20:15 -0500 |
commit | 7f2251b1bcdd3d2971b2fde3008b270ea11b8780 (patch) | |
tree | 5fc3a2fc089188a6a61e16374a5b715db280aca7 | |
parent | 6c9620c64be3920487c0533e0ab6724dad565d59 (diff) |
gru: handle failures to mmu_notifier_register
Under some conditions, mmu_notifier_register() will fail to register a
mmu_notifier. Fix the GRU driver to correctly handle these failures.
Signed-off-by: Jack Steiner <steiner@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/misc/sgi-gru/grufault.c | 6 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grumain.c | 18 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grutlbpurge.c | 8 |
3 files changed, 21 insertions, 11 deletions
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 9470303a9cb9..ada7df7e0968 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c | |||
@@ -96,7 +96,7 @@ static struct gru_thread_state *gru_alloc_locked_gts(unsigned long vaddr) | |||
96 | vma = gru_find_vma(vaddr); | 96 | vma = gru_find_vma(vaddr); |
97 | if (vma) | 97 | if (vma) |
98 | gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); | 98 | gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); |
99 | if (gts) { | 99 | if (!IS_ERR(gts)) { |
100 | mutex_lock(>s->ts_ctxlock); | 100 | mutex_lock(>s->ts_ctxlock); |
101 | downgrade_write(&mm->mmap_sem); | 101 | downgrade_write(&mm->mmap_sem); |
102 | } else { | 102 | } else { |
@@ -747,8 +747,8 @@ int gru_set_context_option(unsigned long arg) | |||
747 | gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1); | 747 | gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1); |
748 | 748 | ||
749 | gts = gru_alloc_locked_gts(req.gseg); | 749 | gts = gru_alloc_locked_gts(req.gseg); |
750 | if (!gts) | 750 | if (IS_ERR(gts)) |
751 | return -EINVAL; | 751 | return PTR_ERR(gts); |
752 | 752 | ||
753 | switch (req.op) { | 753 | switch (req.op) { |
754 | case sco_blade_chiplet: | 754 | case sco_blade_chiplet: |
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index 9ec54bde4472..944028871884 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/device.h> | 28 | #include <linux/device.h> |
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/err.h> | ||
30 | #include <asm/uv/uv_hub.h> | 31 | #include <asm/uv/uv_hub.h> |
31 | #include "gru.h" | 32 | #include "gru.h" |
32 | #include "grutables.h" | 33 | #include "grutables.h" |
@@ -286,7 +287,8 @@ static void gru_unload_mm_tracker(struct gru_state *gru, | |||
286 | void gts_drop(struct gru_thread_state *gts) | 287 | void gts_drop(struct gru_thread_state *gts) |
287 | { | 288 | { |
288 | if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { | 289 | if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { |
289 | gru_drop_mmu_notifier(gts->ts_gms); | 290 | if (gts->ts_gms) |
291 | gru_drop_mmu_notifier(gts->ts_gms); | ||
290 | kfree(gts); | 292 | kfree(gts); |
291 | STAT(gts_free); | 293 | STAT(gts_free); |
292 | } | 294 | } |
@@ -313,13 +315,14 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | |||
313 | int cbr_au_count, int dsr_au_count, int options, int tsid) | 315 | int cbr_au_count, int dsr_au_count, int options, int tsid) |
314 | { | 316 | { |
315 | struct gru_thread_state *gts; | 317 | struct gru_thread_state *gts; |
318 | struct gru_mm_struct *gms; | ||
316 | int bytes; | 319 | int bytes; |
317 | 320 | ||
318 | bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count); | 321 | bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count); |
319 | bytes += sizeof(struct gru_thread_state); | 322 | bytes += sizeof(struct gru_thread_state); |
320 | gts = kmalloc(bytes, GFP_KERNEL); | 323 | gts = kmalloc(bytes, GFP_KERNEL); |
321 | if (!gts) | 324 | if (!gts) |
322 | return NULL; | 325 | return ERR_PTR(-ENOMEM); |
323 | 326 | ||
324 | STAT(gts_alloc); | 327 | STAT(gts_alloc); |
325 | memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */ | 328 | memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */ |
@@ -338,9 +341,10 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | |||
338 | if (vma) { | 341 | if (vma) { |
339 | gts->ts_mm = current->mm; | 342 | gts->ts_mm = current->mm; |
340 | gts->ts_vma = vma; | 343 | gts->ts_vma = vma; |
341 | gts->ts_gms = gru_register_mmu_notifier(); | 344 | gms = gru_register_mmu_notifier(); |
342 | if (!gts->ts_gms) | 345 | if (IS_ERR(gms)) |
343 | goto err; | 346 | goto err; |
347 | gts->ts_gms = gms; | ||
344 | } | 348 | } |
345 | 349 | ||
346 | gru_dbg(grudev, "alloc gts %p\n", gts); | 350 | gru_dbg(grudev, "alloc gts %p\n", gts); |
@@ -348,7 +352,7 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, | |||
348 | 352 | ||
349 | err: | 353 | err: |
350 | gts_drop(gts); | 354 | gts_drop(gts); |
351 | return NULL; | 355 | return ERR_CAST(gms); |
352 | } | 356 | } |
353 | 357 | ||
354 | /* | 358 | /* |
@@ -396,8 +400,8 @@ struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, | |||
396 | 400 | ||
397 | gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count, | 401 | gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count, |
398 | vdata->vd_user_options, tsid); | 402 | vdata->vd_user_options, tsid); |
399 | if (!gts) | 403 | if (IS_ERR(gts)) |
400 | return NULL; | 404 | return gts; |
401 | 405 | ||
402 | spin_lock(&vdata->vd_lock); | 406 | spin_lock(&vdata->vd_lock); |
403 | ngts = gru_find_current_gts_nolock(vdata, tsid); | 407 | ngts = gru_find_current_gts_nolock(vdata, tsid); |
diff --git a/drivers/misc/sgi-gru/grutlbpurge.c b/drivers/misc/sgi-gru/grutlbpurge.c index 1d125091f5e7..421c548e51f1 100644 --- a/drivers/misc/sgi-gru/grutlbpurge.c +++ b/drivers/misc/sgi-gru/grutlbpurge.c | |||
@@ -299,6 +299,7 @@ struct gru_mm_struct *gru_register_mmu_notifier(void) | |||
299 | { | 299 | { |
300 | struct gru_mm_struct *gms; | 300 | struct gru_mm_struct *gms; |
301 | struct mmu_notifier *mn; | 301 | struct mmu_notifier *mn; |
302 | int err; | ||
302 | 303 | ||
303 | mn = mmu_find_ops(current->mm, &gru_mmuops); | 304 | mn = mmu_find_ops(current->mm, &gru_mmuops); |
304 | if (mn) { | 305 | if (mn) { |
@@ -311,12 +312,17 @@ struct gru_mm_struct *gru_register_mmu_notifier(void) | |||
311 | gms->ms_notifier.ops = &gru_mmuops; | 312 | gms->ms_notifier.ops = &gru_mmuops; |
312 | atomic_set(&gms->ms_refcnt, 1); | 313 | atomic_set(&gms->ms_refcnt, 1); |
313 | init_waitqueue_head(&gms->ms_wait_queue); | 314 | init_waitqueue_head(&gms->ms_wait_queue); |
314 | __mmu_notifier_register(&gms->ms_notifier, current->mm); | 315 | err = __mmu_notifier_register(&gms->ms_notifier, current->mm); |
316 | if (err) | ||
317 | goto error; | ||
315 | } | 318 | } |
316 | } | 319 | } |
317 | gru_dbg(grudev, "gms %p, refcnt %d\n", gms, | 320 | gru_dbg(grudev, "gms %p, refcnt %d\n", gms, |
318 | atomic_read(&gms->ms_refcnt)); | 321 | atomic_read(&gms->ms_refcnt)); |
319 | return gms; | 322 | return gms; |
323 | error: | ||
324 | kfree(gms); | ||
325 | return ERR_PTR(err); | ||
320 | } | 326 | } |
321 | 327 | ||
322 | void gru_drop_mmu_notifier(struct gru_mm_struct *gms) | 328 | void gru_drop_mmu_notifier(struct gru_mm_struct *gms) |