From db6c7f0843acd715fcbbff9a2cf334cbc448af8c Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Mon, 16 Nov 2020 14:16:40 +0530 Subject: [PATCH] msm: mhi_dev: Serialize UCI open and close file node operations Multiple clients might perform open and close file operations simultaneously on the same file node created by UCI. To avoid race conditions which might result in invalid accesses or crashes, the open and close operations are serialized. Change-Id: Ic6a290a2c6af25bcd60983a7b531bf1287201821 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 2d04c2cbf5b0..c5cb081e8bcc 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -372,6 +372,7 @@ struct uci_client { struct mhi_uci_ctxt_t *uci_ctxt; struct mutex in_chan_lock; struct mutex out_chan_lock; + struct mutex client_lock; spinlock_t req_lock; unsigned int f_flags; /* Pointer to dynamically allocated mhi_req structs */ @@ -779,6 +780,8 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) if (!uci_handle) return -ENODEV; + mutex_lock(&uci_handle->client_lock); + poll_wait(file, &uci_handle->read_wq, wait); poll_wait(file, &uci_handle->write_wq, wait); /* @@ -786,8 +789,10 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) * to poll are in connected state and return with the * appropriate mask if channels are disconnected. */ - if (!mhi_uci_are_channels_connected(uci_handle)) { + if (!atomic_read(&uci_handle->mhi_chans_open) || + !mhi_uci_are_channels_connected(uci_handle)) { mask = POLLHUP; + mutex_unlock(&uci_handle->client_lock); return mask; } mask = uci_handle->at_ctrl_mask; @@ -807,6 +812,8 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait) uci_log(UCI_DBG_VERBOSE, "Client attempted to poll chan %d, returning mask 0x%x\n", uci_handle->in_chan, mask); + mutex_unlock(&uci_handle->client_lock); + return mask; } @@ -1066,6 +1073,7 @@ static int mhi_uci_client_open(struct inode *mhi_inode, return -EINVAL; } + mutex_lock(&uci_handle->client_lock); uci_log(UCI_DBG_DBG, "Client opened struct device node 0x%x, ref count 0x%x\n", iminor(mhi_inode), atomic_read(&uci_handle->ref_count)); @@ -1073,6 +1081,7 @@ static int mhi_uci_client_open(struct inode *mhi_inode, if (!uci_handle) { atomic_dec(&uci_handle->ref_count); uci_log(UCI_DBG_DBG, "No memory, returning failure\n"); + mutex_unlock(&uci_handle->client_lock); return -ENOMEM; } uci_handle->uci_ctxt = &uci_ctxt; @@ -1090,11 +1099,13 @@ static int mhi_uci_client_open(struct inode *mhi_inode, uci_log(UCI_DBG_INFO, "Closing failed channel\n"); } + mutex_unlock(&uci_handle->client_lock); return rc; } } } file_handle->private_data = uci_handle; + mutex_unlock(&uci_handle->client_lock); return 0; @@ -1111,10 +1122,12 @@ static int mhi_uci_client_release(struct inode *mhi_inode, if (!uci_handle) return -EINVAL; + mutex_lock(&uci_handle->client_lock); in_chan_attr = uci_handle->in_chan_attr; if (!in_chan_attr) { uci_log(UCI_DBG_ERROR, "Null channel attributes for chan %d\n", uci_handle->in_chan); + mutex_unlock(&uci_handle->client_lock); return -EINVAL; } @@ -1122,6 +1135,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode, uci_log(UCI_DBG_DBG, "Client close chan %d, ref count 0x%x\n", iminor(mhi_inode), atomic_read(&uci_handle->ref_count)); + mutex_unlock(&uci_handle->client_lock); return 0; } @@ -1185,6 +1199,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode, atomic_set(&uci_handle->read_data_ready, 0); atomic_set(&uci_handle->write_data_ready, 0); file_handle->private_data = NULL; + mutex_unlock(&uci_handle->client_lock); return 0; } @@ -1667,6 +1682,7 @@ static int mhi_register_client(struct uci_client *mhi_client, int index) mutex_init(&mhi_client->in_chan_lock); mutex_init(&mhi_client->out_chan_lock); + mutex_init(&mhi_client->client_lock); spin_lock_init(&mhi_client->req_lock); /* Init the completion event for AT ctrl read */ init_completion(&mhi_client->at_ctrl_read_done);