diff options
author | Jack Steiner <steiner@sgi.com> | 2009-12-15 16:48:08 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 07:20:15 -0800 |
commit | 7f2251b1bcdd3d2971b2fde3008b270ea11b8780 (patch) | |
tree | 5fc3a2fc089188a6a61e16374a5b715db280aca7 /drivers/misc/sgi-gru | |
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>
Diffstat (limited to 'drivers/misc/sgi-gru')
-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) vma = gru_find_vma(vaddr); if (vma) gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); - if (gts) { + if (!IS_ERR(gts)) { mutex_lock(>s->ts_ctxlock); downgrade_write(&mm->mmap_sem); } else { @@ -747,8 +747,8 @@ int gru_set_context_option(unsigned long arg) gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1); gts = gru_alloc_locked_gts(req.gseg); - if (!gts) - return -EINVAL; + if (IS_ERR(gts)) + return PTR_ERR(gts); switch (req.op) { 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 @@ #include <linux/sched.h> #include <linux/device.h> #include <linux/list.h> +#include <linux/err.h> #include <asm/uv/uv_hub.h> #include "gru.h" #include "grutables.h" @@ -286,7 +287,8 @@ static void gru_unload_mm_tracker(struct gru_state *gru, void gts_drop(struct gru_thread_state *gts) { if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { - gru_drop_mmu_notifier(gts->ts_gms); + if (gts->ts_gms) + gru_drop_mmu_notifier(gts->ts_gms); kfree(gts); STAT(gts_free); } @@ -313,13 +315,14 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, int cbr_au_count, int dsr_au_count, int options, int tsid) { struct gru_thread_state *gts; + struct gru_mm_struct *gms; int bytes; bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count); bytes += sizeof(struct gru_thread_state); gts = kmalloc(bytes, GFP_KERNEL); if (!gts) - return NULL; + return ERR_PTR(-ENOMEM); STAT(gts_alloc); 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, if (vma) { gts->ts_mm = current->mm; gts->ts_vma = vma; - gts->ts_gms = gru_register_mmu_notifier(); - if (!gts->ts_gms) + gms = gru_register_mmu_notifier(); + if (IS_ERR(gms)) goto err; + gts->ts_gms = gms; } gru_dbg(grudev, "alloc gts %p\n", gts); @@ -348,7 +352,7 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, err: gts_drop(gts); - return NULL; + return ERR_CAST(gms); } /* @@ -396,8 +400,8 @@ struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count, vdata->vd_user_options, tsid); - if (!gts) - return NULL; + if (IS_ERR(gts)) + return gts; spin_lock(&vdata->vd_lock); 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) { struct gru_mm_struct *gms; struct mmu_notifier *mn; + int err; mn = mmu_find_ops(current->mm, &gru_mmuops); if (mn) { @@ -311,12 +312,17 @@ struct gru_mm_struct *gru_register_mmu_notifier(void) gms->ms_notifier.ops = &gru_mmuops; atomic_set(&gms->ms_refcnt, 1); init_waitqueue_head(&gms->ms_wait_queue); - __mmu_notifier_register(&gms->ms_notifier, current->mm); + err = __mmu_notifier_register(&gms->ms_notifier, current->mm); + if (err) + goto error; } } gru_dbg(grudev, "gms %p, refcnt %d\n", gms, atomic_read(&gms->ms_refcnt)); return gms; +error: + kfree(gms); + return ERR_PTR(err); } void gru_drop_mmu_notifier(struct gru_mm_struct *gms) |