diff options
author | Andrey Markovytch <andreym@codeaurora.org> | 2017-01-29 09:36:34 +0200 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-01-28 23:39:12 -0800 |
commit | d6bbd448c783a92e425f928e32ec470a9ebe2cb2 (patch) | |
tree | bd17fec95fa6bd1335850dfac378ef80fba7fda7 /drivers | |
parent | 958e36a73f7fe46ee28a749cd9b56ddf5dbf56cd (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.c | 46 |
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]; |