scsi: ufs: fix wrong sequence of lrb_in_use and pm

[1] tried to fix wrong lrbp=NULL after clear_bit_unlock, which caused a race
condition. But, it caused a power regression since __ufshcd_release was called
before lrb_in_use is released.

Actually, we should have followed the sequence:
1. lrbp->cmd = NULL
2. clear_bit_unlock()
3. __ufshcd_release()
4. __ufshcd_hibern8_release()

Let's add right fix.

[1] f0e7e5baba0a (scsi: ufs: Avoid potential lrb race caused by early release of lrb_in_use")

Bug: 157450639
Fixes: 639e1063a57e ("Revert "scsi: ufs: Avoid potential lrb race caused by early release of lrb_in_use"")
Fixes: f0e7e5baba0a (scsi: ufs: Avoid potential lrb race caused by early release of lrb_in_use")
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
Change-Id: If738dc3e8e9caa7eee28c729dea3a47a3ed56b97
[dereference23: Apply to msm-4.14]
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
fourteen
Jaegeuk Kim 5 years ago committed by Jenna
parent 219229e831
commit 082fd231c4
  1. 12
      drivers/scsi/ufs/ufshcd.c

@ -7494,15 +7494,12 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
#endif
cmd->result = result;
clear_bit_unlock(index, &hba->lrb_in_use);
lrbp->complete_time_stamp = ktime_get();
update_req_stats(hba, lrbp);
ufshcd_complete_lrbp_crypto(hba, cmd, lrbp);
/* Mark completed command as NULL in LRB */
lrbp->cmd = NULL;
hba->ufs_stats.clk_rel.ctx = XFR_REQ_COMPL;
__ufshcd_release(hba, false);
__ufshcd_hibern8_release(hba, false);
if (cmd->request) {
/*
* As we are accessing the "request" structure,
@ -7530,6 +7527,10 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
}
}
clear_bit_unlock(index, &hba->lrb_in_use);
__ufshcd_release(hba, false);
__ufshcd_hibern8_release(hba, false);
/* Do not touch lrbp after scsi done */
cmd->scsi_done(cmd);
} else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE ||
@ -7579,12 +7580,10 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result)
/* Clear pending transfer requests */
ufshcd_clear_cmd(hba, index);
ufshcd_outstanding_req_clear(hba, index);
clear_bit_unlock(index, &hba->lrb_in_use);
lrbp->complete_time_stamp = ktime_get();
update_req_stats(hba, lrbp);
/* Mark completed command as NULL in LRB */
lrbp->cmd = NULL;
ufshcd_release_all(hba);
if (cmd->request) {
/*
* As we are accessing the "request" structure,
@ -7594,6 +7593,9 @@ void ufshcd_abort_outstanding_transfer_requests(struct ufs_hba *hba, int result)
ufshcd_vops_pm_qos_req_end(hba, cmd->request,
true);
}
clear_bit_unlock(index, &hba->lrb_in_use);
ufshcd_release_all(hba);
/* Do not touch lrbp after scsi done */
cmd->scsi_done(cmd);
} else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) {

Loading…
Cancel
Save