summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAndrey Markovytch <andreym@codeaurora.org>2017-01-29 09:36:34 +0200
committerGerrit - the friendly Code Review server <code-review@localhost>2017-01-28 23:39:12 -0800
commitd6bbd448c783a92e425f928e32ec470a9ebe2cb2 (patch)
treebd17fec95fa6bd1335850dfac378ef80fba7fda7 /drivers
parent958e36a73f7fe46ee28a749cd9b56ddf5dbf56cd (diff)
ufs: add additional sync between ice work queue and pending request
Fixes the issue where the job could have been scheduled with request that was about to be released thus causing crash with stale pointer. Change-Id: I4ed1f08ed810303738c05d08f27a8ea21ba1e4f7 Signed-off-by: Andrey Markovytch <andreym@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/ufs/ufs-qcom-ice.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index 85f82b2251c1..814d1dcfe90e 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -173,10 +173,19 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work)
struct ice_data_setting ice_set;
struct ufs_qcom_host *qcom_host =
container_of(work, struct ufs_qcom_host, ice_cfg_work);
+ struct request *req_pending = NULL;
- if (!qcom_host->ice.vops->config_start || !qcom_host->req_pending)
+ if (!qcom_host->ice.vops->config_start)
return;
+ spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
+ req_pending = qcom_host->req_pending;
+ if (!req_pending) {
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+
/*
* config_start is called again as previous attempt returned -EAGAIN,
* this call shall now take care of the necessary key setup.
@@ -263,6 +272,10 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
if (qcom_host->ice.vops->config_start) {
memset(&ice_set, 0, sizeof(ice_set));
+
+ spin_lock_irqsave(
+ &qcom_host->ice_work_lock, flags);
+
err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
cmd->request, &ice_set, true);
if (err) {
@@ -281,13 +294,11 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
"%s: scheduling task for ice setup\n",
__func__);
- spin_lock_irqsave(
- &qcom_host->ice_work_lock, flags);
-
if (!qcom_host->req_pending) {
ufshcd_scsi_block_requests(
qcom_host->hba);
qcom_host->req_pending = cmd->request;
+
if (!schedule_work(
&qcom_host->ice_cfg_work)) {
qcom_host->req_pending = NULL;
@@ -302,9 +313,6 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
}
}
- spin_unlock_irqrestore(
- &qcom_host->ice_work_lock, flags);
-
} else {
if (err != -EBUSY)
dev_err(qcom_host->hba->dev,
@@ -312,9 +320,14 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
__func__, err);
}
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock,
+ flags);
+
return err;
}
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+
if (ufs_qcom_is_data_cmd(cmd_op, true))
*enable = !ice_set.encr_bypass;
else if (ufs_qcom_is_data_cmd(cmd_op, false))
@@ -380,8 +393,13 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
return -EINVAL;
}
- memset(&ice_set, 0, sizeof(ice_set));
+
if (qcom_host->ice.vops->config_start) {
+ memset(&ice_set, 0, sizeof(ice_set));
+
+ spin_lock_irqsave(
+ &qcom_host->ice_work_lock, flags);
+
err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
req, &ice_set, true);
if (err) {
@@ -401,9 +419,6 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
"%s: scheduling task for ice setup\n",
__func__);
- spin_lock_irqsave(
- &qcom_host->ice_work_lock, flags);
-
if (!qcom_host->req_pending) {
ufshcd_scsi_block_requests(
qcom_host->hba);
@@ -422,9 +437,6 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
}
}
- spin_unlock_irqrestore(
- &qcom_host->ice_work_lock, flags);
-
} else {
if (err != -EBUSY)
dev_err(qcom_host->hba->dev,
@@ -432,8 +444,14 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
__func__, err);
}
+ spin_unlock_irqrestore(
+ &qcom_host->ice_work_lock, flags);
+
return err;
}
+
+ spin_unlock_irqrestore(
+ &qcom_host->ice_work_lock, flags);
}
cmd_op = cmd->cmnd[0];