From d109d8d7e2998a635406215a559e298fa7ef4bb8 Mon Sep 17 00:00:00 2001 From: "lianwei.wang" Date: Fri, 30 Mar 2012 12:05:50 +0800 Subject: [PATCH] IKHSS7-18791 msm:fix the list usage in msm_bus_dbg The list usage in msm_bus_dbg driver are not correct which will cause kernel panic. . The list operation should be protected by a lock, e.g. mutex_lock. . The list entry should only be operated on a valid entry. Change-Id: I19efeb346d1bacf129ccfd7a6511bc795c029afc Signed-off-by: Lianwei Wang Reviewed-on: http://gerrit.pcs.mot.com/384275 Reviewed-by: Guo-Jian Chen Reviewed-by: Ke Lv Tested-by: Jira Key Reviewed-by: Jeffrey Carlyle Reviewed-by: Check Patch Reviewed-by: Klocwork kwcheck Reviewed-by: Tao Hu --- arch/arm/mach-msm/msm_bus/msm_bus_dbg.c | 74 ++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c index abd986bca68..76173529d35 100644 --- a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c +++ b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c @@ -28,6 +28,7 @@ static struct dentry *clients; static struct dentry *dir; static DEFINE_MUTEX(msm_bus_dbg_fablist_lock); +static DEFINE_MUTEX(msm_bus_dbg_cllist_lock); struct msm_bus_dbg_state { uint32_t cl; uint8_t enable; @@ -271,16 +272,21 @@ static ssize_t client_data_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int bsize = 0; + ssize_t read_count = 0; uint32_t cl = (uint32_t)file->private_data; struct msm_bus_cldata *cldata = NULL; + mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { - if (cldata->clid == cl) + if (cldata->clid == cl) { + bsize = cldata->size; + read_count = simple_read_from_buffer(buf, count, ppos, + cldata->buffer, bsize); break; + } } - bsize = cldata->size; - return simple_read_from_buffer(buf, count, ppos, - cldata->buffer, bsize); + mutex_unlock(&msm_bus_dbg_cllist_lock); + return read_count; } static int client_data_open(struct inode *inode, struct file *file) @@ -310,9 +316,11 @@ static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata, { struct msm_bus_cldata *cldata; + mutex_lock(&msm_bus_dbg_cllist_lock); cldata = kmalloc(sizeof(struct msm_bus_cldata), GFP_KERNEL); if (!cldata) { MSM_BUS_DBG("Failed to allocate memory for client data\n"); + mutex_unlock(&msm_bus_dbg_cllist_lock); return -ENOMEM; } cldata->pdata = pdata; @@ -321,6 +329,7 @@ static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata, cldata->file = file; cldata->size = 0; list_add_tail(&cldata->list, &cl_list); + mutex_unlock(&msm_bus_dbg_cllist_lock); return 0; } @@ -328,6 +337,7 @@ static void msm_bus_dbg_free_client(uint32_t clid) { struct msm_bus_cldata *cldata = NULL; + mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (cldata->clid == clid) { debugfs_remove(cldata->file); @@ -336,23 +346,34 @@ static void msm_bus_dbg_free_client(uint32_t clid) break; } } + mutex_unlock(&msm_bus_dbg_cllist_lock); } static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata, int index, uint32_t clid) { - int i = 0, j; + int i = 0, j, found = 0; char *buf = NULL; struct msm_bus_cldata *cldata = NULL; struct timespec ts; + mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { - if (cldata->clid == clid) + if (cldata->clid == clid) { + found = 1; break; + } + } + + if (!found) { + MSM_BUS_DBG("Client(clid=%d) doesn't exist\n", clid); + mutex_unlock(&msm_bus_dbg_cllist_lock); + return -EINVAL; } if (cldata->file == NULL) { if (pdata->name == NULL) { MSM_BUS_DBG("Client doesn't have a name\n"); + mutex_unlock(&msm_bus_dbg_cllist_lock); return -EINVAL; } cldata->file = msm_bus_dbg_create(pdata->name, S_IRUGO, @@ -390,6 +411,9 @@ static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata, i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n"); cldata->size = i; + + mutex_unlock(&msm_bus_dbg_cllist_lock); + return i; } @@ -426,6 +450,7 @@ static ssize_t msm_bus_dbg_update_request_write(struct file *file, chid = buf; MSM_BUS_DBG("buffer: %s\n size: %d\n", buf, sizeof(ubuf)); + mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (strstr(chid, cldata->pdata->name)) { cldata = cldata; @@ -435,16 +460,19 @@ static ssize_t msm_bus_dbg_update_request_write(struct file *file, if (ret) { MSM_BUS_DBG("Index conversion" " failed\n"); + mutex_unlock(&msm_bus_dbg_cllist_lock); return -EFAULT; } } else MSM_BUS_DBG("Error parsing input. Index not" " found\n"); + msm_bus_dbg_update_request(cldata, index); break; } } - msm_bus_dbg_update_request(cldata, index); + mutex_unlock(&msm_bus_dbg_cllist_lock); + kfree(buf); return cnt; } @@ -458,17 +486,18 @@ static ssize_t fabric_data_read(struct file *file, char __user *buf, { struct msm_bus_fab_list *fablist = NULL; int bsize = 0; - ssize_t ret; + ssize_t ret = 0; const char *name = file->private_data; mutex_lock(&msm_bus_dbg_fablist_lock); list_for_each_entry(fablist, &fabdata_list, list) { - if (strcmp(fablist->name, name) == 0) + if (strcmp(fablist->name, name) == 0) { + bsize = fablist->size; + ret = simple_read_from_buffer(buf, count, ppos, + fablist->buffer, bsize); break; + } } - bsize = fablist->size; - ret = simple_read_from_buffer(buf, count, ppos, - fablist->buffer, bsize); mutex_unlock(&msm_bus_dbg_fablist_lock); return ret; } @@ -519,16 +548,25 @@ static int msm_bus_dbg_fill_fab_buffer(const char *fabname, void *cdata, int nmasters, int nslaves, int ntslaves) { - int i; + int i, found = 0; char *buf = NULL; struct msm_bus_fab_list *fablist = NULL; struct timespec ts; mutex_lock(&msm_bus_dbg_fablist_lock); list_for_each_entry(fablist, &fabdata_list, list) { - if (strcmp(fablist->name, fabname) == 0) + if (strcmp(fablist->name, fabname) == 0) { + found = 1; break; + } + } + + if (!found) { + MSM_BUS_DBG("Fabric dbg entry %s does not exist, fabname\n"); + mutex_unlock(&msm_bus_dbg_fablist_lock); + return -EINVAL; } + if (fablist->file == NULL) { MSM_BUS_DBG("Fabric dbg entry does not exist\n"); mutex_unlock(&msm_bus_dbg_fablist_lock); @@ -542,7 +580,6 @@ static int msm_bus_dbg_fill_fab_buffer(const char *fabname, fablist->size = 0; } buf = fablist->buffer; - mutex_unlock(&msm_bus_dbg_fablist_lock); ts = ktime_to_timespec(ktime_get()); i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n", (int)ts.tv_sec, (int)ts.tv_nsec); @@ -550,7 +587,6 @@ static int msm_bus_dbg_fill_fab_buffer(const char *fabname, msm_bus_rpm_fill_cdata_buffer(&i, buf + i, MAX_BUFF_SIZE, cdata, nmasters, nslaves, ntslaves); i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n"); - mutex_lock(&msm_bus_dbg_fablist_lock); fablist->size = i; mutex_unlock(&msm_bus_dbg_fablist_lock); return 0; @@ -660,6 +696,7 @@ static int __init msm_bus_debugfs_init(void) clients, NULL, &msm_bus_dbg_update_request_fops) == NULL) goto err; + mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry(cldata, &cl_list, list) { if (cldata->pdata->name == NULL) { MSM_BUS_DBG("Client name not found\n"); @@ -668,6 +705,7 @@ static int __init msm_bus_debugfs_init(void) cldata->file = msm_bus_dbg_create(cldata-> pdata->name, S_IRUGO, clients, cldata->clid); } + mutex_unlock(&msm_bus_dbg_cllist_lock); mutex_lock(&msm_bus_dbg_fablist_lock); list_for_each_entry(fablist, &fabdata_list, list) { @@ -675,6 +713,7 @@ static int __init msm_bus_debugfs_init(void) commit, (void *)fablist->name, &fabric_data_fops); if (fablist->file == NULL) { MSM_BUS_DBG("Cannot create files for commit data\n"); + mutex_unlock(&msm_bus_dbg_fablist_lock); goto err; } } @@ -694,10 +733,13 @@ static void __exit msm_bus_dbg_teardown(void) struct msm_bus_cldata *cldata = NULL, *cldata_temp; debugfs_remove_recursive(dir); + mutex_lock(&msm_bus_dbg_cllist_lock); list_for_each_entry_safe(cldata, cldata_temp, &cl_list, list) { list_del(&cldata->list); kfree(cldata); } + mutex_unlock(&msm_bus_dbg_cllist_lock); + mutex_lock(&msm_bus_dbg_fablist_lock); list_for_each_entry_safe(fablist, fablist_temp, &fabdata_list, list) { list_del(&fablist->list);