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

Commit 2c3343ea authored by Tharun Kumar Merugu's avatar Tharun Kumar Merugu
Browse files

msm: adsprpc: Avoid race condition during map creation and free



Avoid race condition among concurrent fastrpc threads while
creating and removing memory mappings.

Change-Id: Ibf9ab0d4d19137804dbff4237a973895c410330c
Acked-by: default avatarThyagarajan Venkatanarayanan <venkatan@qti.qualcomm.com>
Signed-off-by: default avatarTharun Kumar Merugu <mtharu@codeaurora.org>
parent 4624f8d7
Loading
Loading
Loading
Loading
+54 −25
Original line number Diff line number Diff line
@@ -338,6 +338,7 @@ struct fastrpc_file {
	struct pm_qos_request pm_qos_req;
	int qos_request;
	struct mutex map_mutex;
	struct mutex internal_map_mutex;
};

static struct fastrpc_apps gfa;
@@ -473,15 +474,11 @@ static void fastrpc_mmap_add(struct fastrpc_mmap *map)
				map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
		struct fastrpc_apps *me = &gfa;

		spin_lock(&me->hlock);
		hlist_add_head(&map->hn, &me->maps);
		spin_unlock(&me->hlock);
	} else {
		struct fastrpc_file *fl = map->fl;

		spin_lock(&fl->hlock);
		hlist_add_head(&map->hn, &fl->maps);
		spin_unlock(&fl->hlock);
	}
}

@@ -497,7 +494,6 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd,
		return -EOVERFLOW;
	if (mflags == ADSP_MMAP_HEAP_ADDR ||
				 mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
		spin_lock(&me->hlock);
		hlist_for_each_entry_safe(map, n, &me->maps, hn) {
			if (va >= map->va &&
				va + len <= map->va + map->len &&
@@ -508,9 +504,7 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd,
				break;
			}
		}
		spin_unlock(&me->hlock);
	} else {
		spin_lock(&fl->hlock);
		hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
			if (va >= map->va &&
				va + len <= map->va + map->len &&
@@ -521,7 +515,6 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd,
				break;
			}
		}
		spin_unlock(&fl->hlock);
	}
	if (match) {
		*ppmap = match;
@@ -554,7 +547,6 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
	struct hlist_node *n;
	struct fastrpc_apps *me = &gfa;

	spin_lock(&me->hlock);
	hlist_for_each_entry_safe(map, n, &me->maps, hn) {
		if (map->raddr == va &&
			map->raddr + map->len == va + len &&
@@ -564,12 +556,10 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
			break;
		}
	}
	spin_unlock(&me->hlock);
	if (match) {
		*ppmap = match;
		return 0;
	}
	spin_lock(&fl->hlock);
	hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
		if (map->raddr == va &&
			map->raddr + map->len == va + len &&
@@ -579,7 +569,6 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
			break;
		}
	}
	spin_unlock(&fl->hlock);
	if (match) {
		*ppmap = match;
		return 0;
@@ -599,19 +588,15 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags)
	fl = map->fl;
	if (map->flags == ADSP_MMAP_HEAP_ADDR ||
				map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
		spin_lock(&me->hlock);
		map->refs--;
		if (!map->refs)
			hlist_del_init(&map->hn);
		spin_unlock(&me->hlock);
		if (map->refs > 0)
			return;
	} else {
		spin_lock(&fl->hlock);
		map->refs--;
		if (!map->refs)
			hlist_del_init(&map->hn);
		spin_unlock(&fl->hlock);
		if (map->refs > 0 && !flags)
			return;
	}
@@ -1108,8 +1093,10 @@ static void context_free(struct smq_invoke_ctx *ctx)
	spin_lock(&ctx->fl->hlock);
	hlist_del_init(&ctx->hn);
	spin_unlock(&ctx->fl->hlock);
	mutex_lock(&ctx->fl->map_mutex);
	for (i = 0; i < nbufs; ++i)
		fastrpc_mmap_free(ctx->maps[i], 0);
	mutex_unlock(&ctx->fl->map_mutex);
	fastrpc_buf_free(ctx->buf, 1);
	ctx->magic = 0;
	ctx->ctxid = 0;
@@ -1250,14 +1237,17 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
		uintptr_t buf = (uintptr_t)lpra[i].buf.pv;
		size_t len = lpra[i].buf.len;

		mutex_lock(&ctx->fl->map_mutex);
		if (ctx->fds[i] && (ctx->fds[i] != -1))
			fastrpc_mmap_create(ctx->fl, ctx->fds[i],
					ctx->attrs[i], buf, len,
					mflags, &ctx->maps[i]);
		mutex_unlock(&ctx->fl->map_mutex);
		ipage += 1;
	}
	PERF_END);
	handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc);
	mutex_lock(&ctx->fl->map_mutex);
	for (i = bufs; i < bufs + handles; i++) {
		int dmaflags = 0;

@@ -1266,10 +1256,13 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
		VERIFY(err, !fastrpc_mmap_create(ctx->fl, ctx->fds[i],
				FASTRPC_ATTR_NOVA, 0, 0, dmaflags,
				&ctx->maps[i]));
		if (err)
		if (err) {
			mutex_unlock(&ctx->fl->map_mutex);
			goto bail;
		}
		ipage += 1;
	}
	mutex_unlock(&ctx->fl->map_mutex);
	metalen = copylen = (size_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST) +
				 (sizeof(uint32_t) * M_CRCLIST);

@@ -1478,10 +1471,13 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
			if (err)
				goto bail;
		} else {
			mutex_lock(&ctx->fl->map_mutex);
			fastrpc_mmap_free(ctx->maps[i], 0);
			mutex_unlock(&ctx->fl->map_mutex);
			ctx->maps[i] = NULL;
		}
	}
	mutex_lock(&ctx->fl->map_mutex);
	if (inbufs + outbufs + handles) {
		for (i = 0; i < M_FDLIST; i++) {
			if (!fdlist[i])
@@ -1491,6 +1487,7 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx,
				fastrpc_mmap_free(mmap, 0);
		}
	}
	mutex_unlock(&ctx->fl->map_mutex);
	if (ctx->crc && crclist && rpra)
		K_COPY_TO_USER(err, kernel, ctx->crc,
			crclist, M_CRCLIST*sizeof(uint32_t));
@@ -1795,8 +1792,10 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
		if (err)
			goto bail;
		if (init->filelen) {
			mutex_lock(&fl->map_mutex);
			VERIFY(err, !fastrpc_mmap_create(fl, init->filefd, 0,
				init->file, init->filelen, mflags, &file));
			mutex_unlock(&fl->map_mutex);
			if (err)
				goto bail;
		}
@@ -1805,8 +1804,10 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
			init->memlen));
		if (err)
			goto bail;
		mutex_lock(&fl->map_mutex);
		VERIFY(err, !fastrpc_mmap_create(fl, init->memfd, 0,
				init->mem, init->memlen, mflags, &mem));
		mutex_unlock(&fl->map_mutex);
		if (err)
			goto bail;
		inbuf.pageslen = 1;
@@ -1878,9 +1879,11 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
		inbuf.pageslen = 0;
		if (!me->staticpd_flags) {
			inbuf.pageslen = 1;
			mutex_lock(&fl->map_mutex);
			VERIFY(err, !fastrpc_mmap_create(fl, -1, 0, init->mem,
				 init->memlen, ADSP_MMAP_REMOTE_HEAP_ADDR,
				 &mem));
			mutex_unlock(&fl->map_mutex);
			if (err)
				goto bail;
			phys = mem->phys;
@@ -1941,10 +1944,15 @@ static int fastrpc_init_process(struct fastrpc_file *fl,
					me->channel[fl->cid].rhvm.vmid,
					me->channel[fl->cid].rhvm.vmcount,
					hlosvm, hlosvmperm, 1);
		mutex_lock(&fl->map_mutex);
		fastrpc_mmap_free(mem, 0);
		mutex_unlock(&fl->map_mutex);
	}
	if (file)
	if (file) {
		mutex_lock(&fl->map_mutex);
		fastrpc_mmap_free(file, 0);
		mutex_unlock(&fl->map_mutex);
	}
	return err;
}

@@ -2199,18 +2207,25 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl,
	int err = 0;
	struct fastrpc_mmap *map = NULL;

	mutex_lock(&fl->internal_map_mutex);
	mutex_lock(&fl->map_mutex);
	VERIFY(err, !fastrpc_mmap_remove(fl, ud->vaddrout, ud->size, &map));
	mutex_unlock(&fl->map_mutex);
	if (err)
		goto bail;
	VERIFY(err, !fastrpc_munmap_on_dsp(fl, map));
	if (err)
		goto bail;
	mutex_lock(&fl->map_mutex);
	fastrpc_mmap_free(map, 0);
	mutex_unlock(&fl->map_mutex);
bail:
	if (err && map)
	if (err && map) {
		mutex_lock(&fl->map_mutex);
		fastrpc_mmap_add(map);
		mutex_unlock(&fl->map_mutex);
	}
	mutex_unlock(&fl->internal_map_mutex);
	return err;
}

@@ -2223,16 +2238,18 @@ static int fastrpc_internal_munmap_fd(struct fastrpc_file *fl,
	VERIFY(err, (fl && ud));
	if (err)
		goto bail;

	mutex_lock(&fl->map_mutex);
	if (fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map)) {
		pr_err("adsprpc: mapping not found to unmap fd 0x%x, va 0x%llx, len 0x%x\n",
			ud->fd, (unsigned long long)ud->va,
			(unsigned int)ud->len);
		err = -1;
		mutex_unlock(&fl->map_mutex);
		goto bail;
	}
	if (map)
		fastrpc_mmap_free(map, 0);
	mutex_unlock(&fl->map_mutex);
bail:
	return err;
}
@@ -2245,15 +2262,18 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
	struct fastrpc_mmap *map = NULL;
	int err = 0;

	mutex_lock(&fl->internal_map_mutex);
	mutex_lock(&fl->map_mutex);
	if (!fastrpc_mmap_find(fl, ud->fd, (uintptr_t)ud->vaddrin,
			 ud->size, ud->flags, 1, &map)) {
		mutex_unlock(&fl->map_mutex);
		mutex_unlock(&fl->internal_map_mutex);
		return 0;
	}
	VERIFY(err, !fastrpc_mmap_create(fl, ud->fd, 0,
			(uintptr_t)ud->vaddrin, ud->size,
			 ud->flags, &map));
	mutex_unlock(&fl->map_mutex);
	if (err)
		goto bail;
	VERIFY(err, 0 == fastrpc_mmap_on_dsp(fl, ud->flags, map));
@@ -2261,9 +2281,12 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl,
		goto bail;
	ud->vaddrout = map->raddr;
 bail:
	if (err && map)
	if (err && map) {
		mutex_lock(&fl->map_mutex);
		fastrpc_mmap_free(map, 0);
		mutex_unlock(&fl->map_mutex);
	}
	mutex_unlock(&fl->internal_map_mutex);
	return err;
}

@@ -2451,6 +2474,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
	spin_unlock(&fl->hlock);
	fastrpc_context_list_dtor(fl);
	fastrpc_buf_list_free(fl);
	mutex_lock(&fl->map_mutex);
	do {
		lmap = NULL;
		hlist_for_each_entry_safe(map, n, &fl->maps, hn) {
@@ -2460,6 +2484,7 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
		}
		fastrpc_mmap_free(lmap, 1);
	} while (lmap);
	mutex_unlock(&fl->map_mutex);

	if (fl->sctx)
		fastrpc_session_free(&fl->apps->channel[cid], fl->sctx);
@@ -2480,6 +2505,8 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
	} while (fperf);
	mutex_unlock(&fl->perf_mutex);
	mutex_destroy(&fl->perf_mutex);
	mutex_destroy(&fl->map_mutex);
	mutex_destroy(&fl->internal_map_mutex);
	kfree(fl);
	return 0;
}
@@ -2493,7 +2520,6 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
			pm_qos_remove_request(&fl->pm_qos_req);
		if (fl->debugfs_file != NULL)
			debugfs_remove(fl->debugfs_file);
		mutex_destroy(&fl->map_mutex);
		fastrpc_file_free(fl);
		file->private_data = NULL;
	}
@@ -2649,8 +2675,10 @@ static int fastrpc_channel_open(struct fastrpc_file *fl)

		if (me->channel[cid].ssrcount !=
				 me->channel[cid].prevssrcount) {
			mutex_lock(&fl->map_mutex);
			if (fastrpc_mmap_remove_ssr(fl))
				pr_err("ADSPRPC: SSR: Failed to unmap remote heap\n");
			mutex_unlock(&fl->map_mutex);
			me->channel[cid].prevssrcount =
						me->channel[cid].ssrcount;
		}
@@ -2689,6 +2717,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
	memset(&fl->perf, 0, sizeof(fl->perf));
	fl->qos_request = 0;
	filp->private_data = fl;
	mutex_init(&fl->internal_map_mutex);
	mutex_init(&fl->map_mutex);
	spin_lock(&me->hlock);
	hlist_add_head(&fl->hn, &me->drivers);