drivers: soc: Synchronize apr callback and voice svc release
Issue is seen when apr callback is received while voice_svc_release is in process of freeing the driver private data. Avoid invalid access of private data pointer by putting the callback and release functions in the same locked context. Change-Id: I93af13cab0a3c7e653a9bc9fa7f4f86bfa0502df Signed-off-by: smanag <smanag@codeaurora.org>
This commit is contained in:
parent
309e66d753
commit
01d8ecac97
|
@ -14,6 +14,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -67,7 +68,11 @@ static void *dummy_q6_mvm;
|
|||
static void *dummy_q6_cvs;
|
||||
dev_t device_num;
|
||||
|
||||
spinlock_t voicesvc_lock;
|
||||
static bool is_released;
|
||||
static int voice_svc_dummy_reg(void);
|
||||
static int voice_svc_dummy_dereg(void);
|
||||
|
||||
static int32_t qdsp_dummy_apr_callback(struct apr_client_data *data,
|
||||
void *priv);
|
||||
|
||||
|
@ -82,10 +87,16 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
|
|||
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_lock(&voicesvc_lock);
|
||||
if (is_released) {
|
||||
spin_unlock(&voicesvc_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
prtd = (struct voice_svc_prvt *)priv;
|
||||
if (prtd == NULL) {
|
||||
pr_err("%s: private data is NULL\n", __func__);
|
||||
spin_unlock(&voicesvc_lock);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -128,6 +139,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
|
|||
|
||||
spin_unlock_irqrestore(&prtd->response_lock,
|
||||
spin_flags);
|
||||
spin_unlock(&voicesvc_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -156,6 +168,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
|
|||
__func__);
|
||||
}
|
||||
|
||||
spin_unlock(&voicesvc_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -614,6 +627,21 @@ err:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int voice_svc_dummy_dereg(void)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
if (dummy_q6_mvm != NULL) {
|
||||
apr_deregister(dummy_q6_mvm);
|
||||
dummy_q6_mvm = NULL;
|
||||
}
|
||||
|
||||
if (dummy_q6_cvs != NULL) {
|
||||
apr_deregister(dummy_q6_cvs);
|
||||
dummy_q6_cvs = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int voice_svc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct voice_svc_prvt *prtd = NULL;
|
||||
|
@ -637,6 +665,7 @@ static int voice_svc_open(struct inode *inode, struct file *file)
|
|||
mutex_init(&prtd->response_mutex_lock);
|
||||
file->private_data = (void *)prtd;
|
||||
|
||||
is_released = 0;
|
||||
/* Current APR implementation doesn't support session based
|
||||
* multiple service registrations. The apr_deregister()
|
||||
* function sets the destination and client IDs to zero, if
|
||||
|
@ -669,6 +698,11 @@ static int voice_svc_release(struct inode *inode, struct file *file)
|
|||
goto done;
|
||||
}
|
||||
|
||||
mutex_lock(&prtd->response_mutex_lock);
|
||||
if (reg_dummy_sess) {
|
||||
voice_svc_dummy_dereg();
|
||||
reg_dummy_sess = 0;
|
||||
}
|
||||
if (prtd->apr_q6_cvs != NULL) {
|
||||
svc_name = VOICE_SVC_MVM_STR;
|
||||
handle = &prtd->apr_q6_cvs;
|
||||
|
@ -685,7 +719,6 @@ static int voice_svc_release(struct inode *inode, struct file *file)
|
|||
pr_err("%s: Failed to dereg MVM %d\n", __func__, ret);
|
||||
}
|
||||
|
||||
mutex_lock(&prtd->response_mutex_lock);
|
||||
spin_lock_irqsave(&prtd->response_lock, spin_flags);
|
||||
|
||||
while (!list_empty(&prtd->response_queue)) {
|
||||
|
@ -703,9 +736,11 @@ static int voice_svc_release(struct inode *inode, struct file *file)
|
|||
|
||||
mutex_destroy(&prtd->response_mutex_lock);
|
||||
|
||||
spin_lock(&voicesvc_lock);
|
||||
kfree(file->private_data);
|
||||
file->private_data = NULL;
|
||||
|
||||
is_released = 1;
|
||||
spin_unlock(&voicesvc_lock);
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
@ -774,6 +809,7 @@ static int voice_svc_probe(struct platform_device *pdev)
|
|||
goto add_err;
|
||||
}
|
||||
pr_debug("%s: Device created\n", __func__);
|
||||
spin_lock_init(&voicesvc_lock);
|
||||
goto done;
|
||||
|
||||
add_err:
|
||||
|
|
Loading…
Reference in New Issue