Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7f2251b1 authored by Jack Steiner's avatar Jack Steiner Committed by Linus Torvalds
Browse files

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: default avatarJack Steiner <steiner@sgi.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6c9620c6
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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(&gts->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:
+11 −7
Original line number Diff line number Diff line
@@ -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,6 +287,7 @@ static void gru_unload_mm_tracker(struct gru_state *gru,
void gts_drop(struct gru_thread_state *gts)
{
	if (gts && atomic_dec_return(&gts->ts_refcnt) == 0) {
		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);
+7 −1
Original line number Diff line number Diff line
@@ -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)