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 <skananth@codeaurora.org>
Signed-off-by: Gauri Joshi <gaurjosh@codeaurora.org>
This commit is contained in:
Subramanian Ananthanarayanan 2020-11-16 14:16:40 +05:30 • committed by Gauri Joshi
commit db6c7f0843

View file

@ -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);