diff options
| author | Veera Sundaram Sankaran <veeras@codeaurora.org> | 2015-04-16 18:43:19 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:29:53 -0700 |
| commit | bd14538fc85ba5f144a294f6a7497fc7421ea866 (patch) | |
| tree | 7a34785d47a47575c07a3f4d50435366276f9dc3 /drivers/video/fbdev | |
| parent | 33a726f79978190e0a0d362957be17b0b438702b (diff) | |
mdss: mdp: use file descriptor node info to track clients
FB clients are tracked using process id. The process id does
not match if open and close API callers are different. Track
the fb clients using file descriptor node id in such cases
and release all resources associated with that process id
gracefully.
CRs-fixed: 652449
Change-Id: I09c965a421197c6464a64684e9706f30df327882
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/core/fbmem.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 127 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.h | 6 |
3 files changed, 119 insertions, 16 deletions
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 0705d8883ede..0b7aab88f84a 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1460,6 +1460,7 @@ __releases(&info->lock) goto out; } file->private_data = info; + info->file = file; if (info->fbops->fb_open) { res = info->fbops->fb_open(info,1); if (res) @@ -1484,6 +1485,7 @@ __releases(&info->lock) struct fb_info * const info = file->private_data; mutex_lock(&info->lock); + info->file = file; if (info->fbops->fb_release) info->fbops->fb_release(info,1); module_put(info->fbops->owner); diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index a991e1810823..fa0527df5813 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1437,10 +1437,73 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd) return 0; } +/** + * mdss_fb_release_file_entry() - Releases file node entry from list + * @info: Frame buffer info + * @pinfo: Process list node in which file node entry is going to + * be removed + * @release_all: Releases all file node entries from list if this parameter + * is true + * + * This function is called to remove the file node entry/entries from main + * list. It also helps to find the process id if fb_open and fb_close + * callers are different. + */ +static struct mdss_fb_proc_info *mdss_fb_release_file_entry( + struct fb_info *info, + struct mdss_fb_proc_info *pinfo, bool release_all) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct mdss_fb_file_info *file_info = NULL, *temp_file_info = NULL; + struct mdss_fb_proc_info *proc_info = NULL, *temp_proc_info = NULL; + struct file *file = info->file; + bool node_found = false; + + if (!pinfo && release_all) { + pr_err("process node not provided for release all case\n"); + goto end; + } + + if (pinfo) { + proc_info = pinfo; + list_for_each_entry_safe(file_info, temp_file_info, + &pinfo->file_list, list) { + if (!release_all && file_info->file != file) + continue; + + list_del(&file_info->list); + kfree(file_info); + + node_found = true; + + if (!release_all) + break; + } + } + + if (!node_found) { + list_for_each_entry_safe(proc_info, temp_proc_info, + &mfd->proc_list, list) { + list_for_each_entry_safe(file_info, temp_file_info, + &proc_info->file_list, list) { + if (file_info->file == file) { + list_del(&file_info->list); + kfree(file_info); + goto end; + } + } + } + } + +end: + return proc_info; +} + static int mdss_fb_open(struct fb_info *info, int user) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; struct mdss_fb_proc_info *pinfo = NULL; + struct mdss_fb_file_info *file_info = NULL; int result; int pid = current->tgid; struct task_struct *task = current->group_leader; @@ -1451,6 +1514,12 @@ static int mdss_fb_open(struct fb_info *info, int user) return -EPERM; } + file_info = kmalloc(sizeof(*file_info), GFP_KERNEL); + if (!file_info) { + pr_err("unable to alloc file info\n"); + return -ENOMEM; + } + list_for_each_entry(pinfo, &mfd->proc_list, list) { if (pinfo->pid == pid) break; @@ -1460,14 +1529,19 @@ static int mdss_fb_open(struct fb_info *info, int user) pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL); if (!pinfo) { pr_err("unable to alloc process info\n"); + kfree(file_info); return -ENOMEM; } pinfo->pid = pid; pinfo->ref_cnt = 0; list_add(&pinfo->list, &mfd->proc_list); + INIT_LIST_HEAD(&pinfo->file_list); pr_debug("new process entry pid=%d\n", pinfo->pid); } + file_info->file = info->file; + list_add(&file_info->list, &pinfo->file_list); + result = pm_runtime_get_sync(info->dev); if (result < 0) { @@ -1506,13 +1580,15 @@ blank_error: mfd->disp_thread = NULL; thread_error: + pm_runtime_put(info->dev); + +pm_error: if (pinfo && !pinfo->ref_cnt) { list_del(&pinfo->list); kfree(pinfo); } - pm_runtime_put(info->dev); - -pm_error: + list_del(&file_info->list); + kfree(file_info); return result; } @@ -1520,6 +1596,7 @@ 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, *temp_pinfo = NULL; + struct mdss_fb_proc_info *proc_info = NULL; int ret = 0; int pid = current->tgid; bool unknown_pid = true, release_needed = false; @@ -1550,6 +1627,18 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all) pr_debug("found process %s pid=%d mfd->ref=%d pinfo->ref=%d\n", task->comm, mfd->ref_cnt, pinfo->pid, pinfo->ref_cnt); + proc_info = mdss_fb_release_file_entry(info, pinfo, + release_all); + /* + * if fb_release is called from different known process then + * release the ref_count of original proc_info instead of + * current process. + */ + if (!release_all && proc_info && proc_info != pinfo) { + pr_info("fb_release called from different process for current file node\n"); + pinfo = proc_info; + } + do { if (mfd->ref_cnt < pinfo->ref_cnt) pr_warn("WARN:mfd->ref=%d < pinfo->ref=%d\n", @@ -1576,6 +1665,23 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all) break; } + if (unknown_pid) { + pinfo = mdss_fb_release_file_entry(info, NULL, false); + if (pinfo) { + mfd->ref_cnt--; + pinfo->ref_cnt--; + pm_runtime_put(info->dev); + if (!pinfo->ref_cnt) { + list_del(&pinfo->list); + kfree(pinfo); + release_needed = true; + } + } else { + WARN("unknown caller:: process %s mfd->ref=%d\n", + task->comm, mfd->ref_cnt); + } + } + if (release_needed) { pr_debug("known process %s pid=%d mfd->ref=%d\n", task->comm, pid, mfd->ref_cnt); @@ -1586,19 +1692,8 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all) pr_err("error releasing fb%d pid=%d\n", 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); - } + } else if (release_all && mfd->ref_cnt) { + pr_err("reference count mismatch with proc list entries\n"); } if (!mfd->ref_cnt) { diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 5f844f073334..0db60893ba54 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -141,9 +141,15 @@ struct msm_mdp_interface { / (2 * max_bright);\ } while (0) +struct mdss_fb_file_info { + struct file *file; + struct list_head list; +}; + struct mdss_fb_proc_info { int pid; u32 ref_cnt; + struct list_head file_list; struct list_head list; }; |
