mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
273 lines
8.5 KiB
Diff
273 lines
8.5 KiB
Diff
|
From d109d8d7e2998a635406215a559e298fa7ef4bb8 Mon Sep 17 00:00:00 2001
|
||
|
From: "lianwei.wang" <lian-wei.wang@motorola.com>
|
||
|
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 <lian-wei.wang@motorola.com>
|
||
|
Reviewed-on: http://gerrit.pcs.mot.com/384275
|
||
|
Reviewed-by: Guo-Jian Chen <A21757@motorola.com>
|
||
|
Reviewed-by: Ke Lv <a2435c@motorola.com>
|
||
|
Tested-by: Jira Key <JIRAKEY@motorola.com>
|
||
|
Reviewed-by: Jeffrey Carlyle <jeff.carlyle@motorola.com>
|
||
|
Reviewed-by: Check Patch <CHEKPACH@motorola.com>
|
||
|
Reviewed-by: Klocwork kwcheck <klocwork-kwcheck@sourceforge.mot.com>
|
||
|
Reviewed-by: Tao Hu <taohu@motorola.com>
|
||
|
---
|
||
|
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);
|