aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Steiner <steiner@sgi.com>2009-12-15 19:48:08 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-16 10:20:15 -0500
commit7f2251b1bcdd3d2971b2fde3008b270ea11b8780 (patch)
tree5fc3a2fc089188a6a61e16374a5b715db280aca7
parent6c9620c64be3920487c0533e0ab6724dad565d59 (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.c6
-rw-r--r--drivers/misc/sgi-gru/grumain.c18
-rw-r--r--drivers/misc/sgi-gru/grutlbpurge.c8
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(&gts->ts_ctxlock); 100 mutex_lock(&gts->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,
286void gts_drop(struct gru_thread_state *gts) 287void gts_drop(struct gru_thread_state *gts)
287{ 288{
288 if (gts && atomic_dec_return(&gts->ts_refcnt) == 0) { 289 if (gts && atomic_dec_return(&gts->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
349err: 353err:
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;
323error:
324 kfree(gms);
325 return ERR_PTR(err);
320} 326}
321 327
322void gru_drop_mmu_notifier(struct gru_mm_struct *gms) 328void gru_drop_mmu_notifier(struct gru_mm_struct *gms)