From de7eaac51267e61855f7596a77317eb70b13ccd3 Mon Sep 17 00:00:00 2001 From: Ankit Sharma Date: Tue, 14 Feb 2017 16:27:52 +0530 Subject: [PATCH] power: qpnp-fg: Fix possible race condition in FG debugfs There is a possible race condition when FG debugfs files are concurrently accessed by multiple threads. Fix this. CRs-Fixed: 1105481 Change-Id: I154e7f3cdd8d51cf67ef1dfd9d78f423f183cb64 Signed-off-by: Ankit Sharma --- drivers/power/supply/qcom/qpnp-fg.c | 32 ++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-fg.c b/drivers/power/supply/qcom/qpnp-fg.c index e4a8ade80d4f..cfd2f64a9bb8 100644 --- a/drivers/power/supply/qcom/qpnp-fg.c +++ b/drivers/power/supply/qcom/qpnp-fg.c @@ -549,6 +549,7 @@ struct fg_trans { struct fg_chip *chip; struct fg_log_buffer *log; /* log buffer */ u8 *data; /* fg data that is read */ + struct mutex memif_dfs_lock; /* Prevent thread concurrency */ }; struct fg_dbgfs { @@ -5730,6 +5731,7 @@ static int fg_memif_data_open(struct inode *inode, struct file *file) trans->addr = dbgfs_data.addr; trans->chip = dbgfs_data.chip; trans->offset = trans->addr; + mutex_init(&trans->memif_dfs_lock); file->private_data = trans; return 0; @@ -5741,6 +5743,7 @@ static int fg_memif_dfs_close(struct inode *inode, struct file *file) if (trans && trans->log && trans->data) { file->private_data = NULL; + mutex_destroy(&trans->memif_dfs_lock); kfree(trans->log); kfree(trans->data); kfree(trans); @@ -5898,10 +5901,13 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf, size_t ret; size_t len; + mutex_lock(&trans->memif_dfs_lock); /* Is the the log buffer empty */ if (log->rpos >= log->wpos) { - if (get_log_data(trans) <= 0) - return 0; + if (get_log_data(trans) <= 0) { + len = 0; + goto unlock_mutex; + } } len = min(count, log->wpos - log->rpos); @@ -5909,7 +5915,8 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf, ret = copy_to_user(buf, &log->data[log->rpos], len); if (ret == len) { pr_err("error copy sram register values to user\n"); - return -EFAULT; + len = -EFAULT; + goto unlock_mutex; } /* 'ret' is the number of bytes not copied */ @@ -5917,6 +5924,9 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf, *ppos += len; log->rpos += len; + +unlock_mutex: + mutex_unlock(&trans->memif_dfs_lock); return len; } @@ -5937,14 +5947,20 @@ static ssize_t fg_memif_dfs_reg_write(struct file *file, const char __user *buf, int cnt = 0; u8 *values; size_t ret = 0; + char *kbuf; + u32 offset; struct fg_trans *trans = file->private_data; - u32 offset = trans->offset; + + mutex_lock(&trans->memif_dfs_lock); + offset = trans->offset; /* Make a copy of the user data */ - char *kbuf = kmalloc(count + 1, GFP_KERNEL); - if (!kbuf) - return -ENOMEM; + kbuf = kmalloc(count + 1, GFP_KERNEL); + if (!kbuf) { + ret = -ENOMEM; + goto unlock_mutex; + } ret = copy_from_user(kbuf, buf, count); if (ret == count) { @@ -5995,6 +6011,8 @@ static ssize_t fg_memif_dfs_reg_write(struct file *file, const char __user *buf, free_buf: kfree(kbuf); +unlock_mutex: + mutex_unlock(&trans->memif_dfs_lock); return ret; }