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

Commit 831a828a authored by Ujwal Patel's avatar Ujwal Patel
Browse files

msm: mdss: Fix race condition during device shutdown



During device shutdown or restart, two separate contexts can call
mdss_fb_release. One system shutdown/restart thread which calls
shutdown routine registered through device driver. Other closing
of frame buffer devices from user processes. Fix race condition
between these two contexts by using proper locking mechanism and
releasing all the resources.

Change-Id: I583b0f1273d984215e276daf3b6307f3b6e9e8c6
Signed-off-by: default avatarUjwal Patel <ujwalp@codeaurora.org>
parent cc8945b6
Loading
Loading
Loading
Loading
+31 −27
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ static struct msm_mdp_interface *mdp_instance;
static int mdss_fb_register(struct msm_fb_data_type *mfd);
static int mdss_fb_open(struct fb_info *info, int user);
static int mdss_fb_release(struct fb_info *info, int user);
static int mdss_fb_release_all(struct fb_info *info, bool release_all);
static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
			       struct fb_info *info);
static int mdss_fb_check_var(struct fb_var_screeninfo *var,
@@ -296,10 +297,9 @@ static void mdss_fb_shutdown(struct platform_device *pdev)
{
	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);

	for (; mfd->ref_cnt > 1; mfd->ref_cnt--)
		pm_runtime_put(mfd->fbi->dev);

	mdss_fb_release(mfd->fbi, 0);
	lock_fb_info(mfd->fbi);
	mdss_fb_release_all(mfd->fbi, true);
	unlock_fb_info(mfd->fbi);
}

static int mdss_fb_probe(struct platform_device *pdev)
@@ -1195,10 +1195,10 @@ static int mdss_fb_open(struct fb_info *info, int user)
	return 0;
}

static int mdss_fb_release(struct fb_info *info, int user)
static int mdss_fb_release_all(struct fb_info *info, bool release_all)
{
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
	struct mdss_fb_proc_info *pinfo = NULL;
	struct mdss_fb_proc_info *pinfo = NULL, *temp_pinfo = NULL;
	int ret = 0;
	int pid = current->tgid;

@@ -1208,27 +1208,26 @@ static int mdss_fb_release(struct fb_info *info, int user)
	}

	mdss_fb_pan_idle(mfd);
	mfd->ref_cnt--;

	list_for_each_entry(pinfo, &mfd->proc_list, list) {
		if (pinfo->pid == pid)
			break;
	}
	pr_debug("release_all = %s\n", release_all ? "true" : "false");

	if (!pinfo || (pinfo->pid != pid)) {
		pr_warn("unable to find process info for fb%d pid=%d\n",
				mfd->index, pid);
		if (mfd->mdp.release_fnc) {
			ret = mfd->mdp.release_fnc(mfd);
			if (ret)
				pr_err("error releasing fb%d resources\n",
						mfd->index);
		}
	} else {
		pr_debug("found process entry pid=%d ref=%d\n",
				pinfo->pid, pinfo->ref_cnt);
	list_for_each_entry_safe(pinfo, temp_pinfo, &mfd->proc_list, list) {
		if (!release_all && (pinfo->pid != pid))
			continue;

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

		do {
			if (mfd->ref_cnt < pinfo->ref_cnt)
				pr_warn("WARN:mfd->ref_cnt < pinfo->ref_cnt\n");
			else
				mfd->ref_cnt--;

			pinfo->ref_cnt--;
			pm_runtime_put(info->dev);
		} while (release_all && pinfo->ref_cnt);

		if (pinfo->ref_cnt == 0) {
			if (mfd->mdp.release_fnc) {
				ret = mfd->mdp.release_fnc(mfd);
@@ -1245,15 +1244,20 @@ static int mdss_fb_release(struct fb_info *info, int user)
		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\n",
				mfd->index, ret);
			return ret;
		}
	}

	pm_runtime_put(info->dev);
	return ret;
}

static int mdss_fb_release(struct fb_info *info, int user)
{
	return mdss_fb_release_all(info, false);
}

static void mdss_fb_power_setting_idle(struct msm_fb_data_type *mfd)
{
	int ret;