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>hifive-unleashed-5.1
parent
6c9620c64b
commit
7f2251b1bc
|
@ -96,7 +96,7 @@ static struct gru_thread_state *gru_alloc_locked_gts(unsigned long vaddr)
|
||||||
vma = gru_find_vma(vaddr);
|
vma = gru_find_vma(vaddr);
|
||||||
if (vma)
|
if (vma)
|
||||||
gts = gru_alloc_thread_state(vma, TSID(vaddr, vma));
|
gts = gru_alloc_thread_state(vma, TSID(vaddr, vma));
|
||||||
if (gts) {
|
if (!IS_ERR(gts)) {
|
||||||
mutex_lock(>s->ts_ctxlock);
|
mutex_lock(>s->ts_ctxlock);
|
||||||
downgrade_write(&mm->mmap_sem);
|
downgrade_write(&mm->mmap_sem);
|
||||||
} else {
|
} 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);
|
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);
|
gts = gru_alloc_locked_gts(req.gseg);
|
||||||
if (!gts)
|
if (IS_ERR(gts))
|
||||||
return -EINVAL;
|
return PTR_ERR(gts);
|
||||||
|
|
||||||
switch (req.op) {
|
switch (req.op) {
|
||||||
case sco_blade_chiplet:
|
case sco_blade_chiplet:
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/err.h>
|
||||||
#include <asm/uv/uv_hub.h>
|
#include <asm/uv/uv_hub.h>
|
||||||
#include "gru.h"
|
#include "gru.h"
|
||||||
#include "grutables.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)
|
void gts_drop(struct gru_thread_state *gts)
|
||||||
{
|
{
|
||||||
if (gts && atomic_dec_return(>s->ts_refcnt) == 0) {
|
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);
|
kfree(gts);
|
||||||
STAT(gts_free);
|
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)
|
int cbr_au_count, int dsr_au_count, int options, int tsid)
|
||||||
{
|
{
|
||||||
struct gru_thread_state *gts;
|
struct gru_thread_state *gts;
|
||||||
|
struct gru_mm_struct *gms;
|
||||||
int bytes;
|
int bytes;
|
||||||
|
|
||||||
bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count);
|
bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count);
|
||||||
bytes += sizeof(struct gru_thread_state);
|
bytes += sizeof(struct gru_thread_state);
|
||||||
gts = kmalloc(bytes, GFP_KERNEL);
|
gts = kmalloc(bytes, GFP_KERNEL);
|
||||||
if (!gts)
|
if (!gts)
|
||||||
return NULL;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
STAT(gts_alloc);
|
STAT(gts_alloc);
|
||||||
memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */
|
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) {
|
if (vma) {
|
||||||
gts->ts_mm = current->mm;
|
gts->ts_mm = current->mm;
|
||||||
gts->ts_vma = vma;
|
gts->ts_vma = vma;
|
||||||
gts->ts_gms = gru_register_mmu_notifier();
|
gms = gru_register_mmu_notifier();
|
||||||
if (!gts->ts_gms)
|
if (IS_ERR(gms))
|
||||||
goto err;
|
goto err;
|
||||||
|
gts->ts_gms = gms;
|
||||||
}
|
}
|
||||||
|
|
||||||
gru_dbg(grudev, "alloc gts %p\n", gts);
|
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:
|
err:
|
||||||
gts_drop(gts);
|
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,
|
gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count,
|
||||||
vdata->vd_user_options, tsid);
|
vdata->vd_user_options, tsid);
|
||||||
if (!gts)
|
if (IS_ERR(gts))
|
||||||
return NULL;
|
return gts;
|
||||||
|
|
||||||
spin_lock(&vdata->vd_lock);
|
spin_lock(&vdata->vd_lock);
|
||||||
ngts = gru_find_current_gts_nolock(vdata, tsid);
|
ngts = gru_find_current_gts_nolock(vdata, tsid);
|
||||||
|
|
|
@ -299,6 +299,7 @@ struct gru_mm_struct *gru_register_mmu_notifier(void)
|
||||||
{
|
{
|
||||||
struct gru_mm_struct *gms;
|
struct gru_mm_struct *gms;
|
||||||
struct mmu_notifier *mn;
|
struct mmu_notifier *mn;
|
||||||
|
int err;
|
||||||
|
|
||||||
mn = mmu_find_ops(current->mm, &gru_mmuops);
|
mn = mmu_find_ops(current->mm, &gru_mmuops);
|
||||||
if (mn) {
|
if (mn) {
|
||||||
|
@ -311,12 +312,17 @@ struct gru_mm_struct *gru_register_mmu_notifier(void)
|
||||||
gms->ms_notifier.ops = &gru_mmuops;
|
gms->ms_notifier.ops = &gru_mmuops;
|
||||||
atomic_set(&gms->ms_refcnt, 1);
|
atomic_set(&gms->ms_refcnt, 1);
|
||||||
init_waitqueue_head(&gms->ms_wait_queue);
|
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,
|
gru_dbg(grudev, "gms %p, refcnt %d\n", gms,
|
||||||
atomic_read(&gms->ms_refcnt));
|
atomic_read(&gms->ms_refcnt));
|
||||||
return gms;
|
return gms;
|
||||||
|
error:
|
||||||
|
kfree(gms);
|
||||||
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gru_drop_mmu_notifier(struct gru_mm_struct *gms)
|
void gru_drop_mmu_notifier(struct gru_mm_struct *gms)
|
||||||
|
|
Loading…
Reference in New Issue