diff mbox series

[RFC,3/6] scsi: ufs: Let ufshcd_[down/up]_read be nested within ufshcd_[down/up]_write

Message ID 20211004120650.153218-4-adrian.hunter@intel.com (mailing list archive)
State Changes Requested
Headers show
Series scsi: ufs: Start to make driver synchronization easier to understand | expand

Commit Message

Adrian Hunter Oct. 4, 2021, 12:06 p.m. UTC
In preparation to hold ufshcd_down_write() lock for the entire error
handler duration.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/scsi/ufs/ufshcd.h | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 495e1c0afae3..74891947bb34 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -898,6 +898,7 @@  struct ufs_hba {
 	bool is_urgent_bkops_lvl_checked;
 
 	struct rw_semaphore host_rw_sem;
+	struct task_struct *excl_task;
 	unsigned char desc_size[QUERY_DESC_IDN_MAX];
 	atomic_t scsi_block_reqs_cnt;
 
@@ -1420,31 +1421,45 @@  static inline int ufshcd_rpmb_rpm_put(struct ufs_hba *hba)
 
 static inline void ufshcd_down_read(struct ufs_hba *hba)
 {
-	down_read(&hba->host_rw_sem);
+	if (hba->excl_task != current)
+		down_read(&hba->host_rw_sem);
 }
 
 static inline void ufshcd_up_read(struct ufs_hba *hba)
 {
-	up_read(&hba->host_rw_sem);
+	if (hba->excl_task != current)
+		up_read(&hba->host_rw_sem);
 }
 
 static inline int ufshcd_down_read_trylock(struct ufs_hba *hba)
 {
+	if (hba->excl_task == current)
+		return 1;
+
 	return down_read_trylock(&hba->host_rw_sem);
 }
 
 static inline void ufshcd_down_write(struct ufs_hba *hba)
 {
 	down_write(&hba->host_rw_sem);
+	/*
+	 * Assign exclusive access to this task, which enables bypassing
+	 * down_read/up_read, refer ufshcd_down_read() and ufshcd_up_read().
+	 * Note, if the same task will not be doing up_write(), it must set
+	 * hba->excl_task to NULL itself.
+	 */
+	hba->excl_task = current;
 }
 
 static inline void ufshcd_up_write(struct ufs_hba *hba)
 {
+	hba->excl_task = NULL;
 	up_write(&hba->host_rw_sem);
 }
 
 static inline void ufshcd_downgrade_write(struct ufs_hba *hba)
 {
+	hba->excl_task = NULL;
 	downgrade_write(&hba->host_rw_sem);
 }