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

Commit 579f6eef authored by Ujwal Patel's avatar Ujwal Patel
Browse files

msm: mdss: release all overlay resources if calling process is unknown



There are cases where fb release is called from a process which is
unknown to internal process tracking list. This usually happens when
a crash handlers closes open fds in a kernel worker thread rather than
in process context. In such cases if fb open happens from a completely
new process then it may lead to pipe leakage due to race condition
between unknown process and this new, fb open, process. Prevent this by
releasing all overlay resources when fb release is called from an
unknown process context.

Change-Id: I07157116413dfb26e0b87c61f9def916a653340a
Signed-off-by: default avatarUjwal Patel <ujwalp@codeaurora.org>
parent 7a6bc7a2
Loading
Loading
Loading
Loading
+32 −20
Original line number Diff line number Diff line
@@ -1205,11 +1205,12 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
	struct mdss_fb_proc_info *pinfo = NULL, *temp_pinfo = NULL;
	int ret = 0;
	int pid = current->tgid;
	bool unknown_pid = true;
	struct task_struct *task;
	bool unknown_pid = true, release_needed = false;
	struct task_struct *task = current->group_leader;

	if (!mfd->ref_cnt) {
		pr_info("try to close unopened fb %d!\n", mfd->index);
		pr_info("try to close unopened fb %d! from %s\n", mfd->index,
			task->comm);
		return -EINVAL;
	}

@@ -1222,12 +1223,14 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
			continue;

		unknown_pid = false;
		pr_debug("found process entry pid=%d ref=%d\n", pinfo->pid,
			pinfo->ref_cnt);

		pr_debug("found process %s pid=%d mfd->ref=%d pinfo->ref=%d\n",
			task->comm, mfd->ref_cnt, pinfo->pid, pinfo->ref_cnt);

		do {
			if (mfd->ref_cnt < pinfo->ref_cnt)
				pr_warn("WARN:mfd->ref_cnt < pinfo->ref_cnt\n");
				pr_warn("WARN:mfd->ref=%d < pinfo->ref=%d\n",
					mfd->ref_cnt, pinfo->ref_cnt);
			else
				mfd->ref_cnt--;

@@ -1236,28 +1239,37 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
		} while (release_all && pinfo->ref_cnt);

		if (pinfo->ref_cnt == 0) {
			if (mfd->mdp.release_fnc) {
				ret = mfd->mdp.release_fnc(mfd);
				if (ret)
					pr_err("error releasing fb%d pid=%d\n",
						mfd->index, pinfo->pid);
			}
			list_del(&pinfo->list);
			kfree(pinfo);
			release_needed = !release_all;
		}

		if (!release_all)
			break;
	}

	if (unknown_pid) {
		task = current->group_leader;
		pr_debug("unknown process %s pid=%d mfd->ref_cnt=%d\n",
	if (release_needed) {
		pr_debug("known process %s pid=%d mfd->ref=%d\n",
			task->comm, pid, mfd->ref_cnt);

		mfd->ref_cnt--;
		if (mfd->mdp.release_fnc) {
			ret = mfd->mdp.release_fnc(mfd);
			ret = mfd->mdp.release_fnc(mfd, false);
			if (ret)
				pr_err("error releasing fb%d pid=%d\n",
					mfd->index, pinfo->pid);
					mfd->index, pid);
		}
	} else if (unknown_pid || release_all) {
		pr_warn("unknown process %s pid=%d mfd->ref=%d\n",
			task->comm, pid, mfd->ref_cnt);

		if (mfd->ref_cnt)
			mfd->ref_cnt--;

		if (mfd->mdp.release_fnc) {
			ret = mfd->mdp.release_fnc(mfd, true);
			if (ret)
				pr_err("error fb%d release process %s pid=%d\n",
					mfd->index, task->comm, pid);
		}
	}

@@ -1265,8 +1277,8 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
			mfd->op_enable);
		if (ret) {
			pr_err("can't turn off fb%d! rc=%d\n",
				mfd->index, ret);
			pr_err("can't turn off fb%d! rc=%d process %s pid=%d\n",
				mfd->index, ret, task->comm, pid);
			return ret;
		}
	}
+1 −1
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ struct msm_mdp_interface {
	int (*on_fnc)(struct msm_fb_data_type *mfd);
	int (*off_fnc)(struct msm_fb_data_type *mfd);
	/* called to release resources associated to the process */
	int (*release_fnc)(struct msm_fb_data_type *mfd);
	int (*release_fnc)(struct msm_fb_data_type *mfd, bool release_all);
	int (*kickoff_fnc)(struct msm_fb_data_type *mfd,
					struct mdp_display_commit *data);
	int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg);
+7 −2
Original line number Diff line number Diff line
@@ -1157,11 +1157,13 @@ done:
/**
 * mdss_mdp_overlay_release_all() - release any overlays associated with fb dev
 * @mfd:	Msm frame buffer structure associated with fb device
 * @release_all: ignore pid and release all the pipes
 *
 * Release any resources allocated by calling process, this can be called
 * on fb_release to release any overlays/rotator sessions left open.
 */
static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd,
	bool release_all)
{
	struct mdss_mdp_pipe *pipe;
	struct mdss_mdp_rotator_session *rot, *tmp;
@@ -1175,7 +1177,7 @@ static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
	mutex_lock(&mdp5_data->ov_lock);
	mutex_lock(&mfd->lock);
	list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
		if (!mfd->ref_cnt || (pipe->pid == pid)) {
		if (release_all || (pipe->pid == pid)) {
			unset_ndx |= pipe->ndx;
			cnt++;
		}
@@ -1187,6 +1189,9 @@ static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
		cnt++;
	}

	pr_debug("release_all=%d mfd->ref_cnt=%d unset_ndx=0x%x cnt=%d\n",
		release_all, mfd->ref_cnt, unset_ndx, cnt);

	mutex_unlock(&mfd->lock);

	if (unset_ndx) {