Commit 379e2554 authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen

scsi: alua: Move a scsi_device_put() call out of alua_rtpg_select_sdev()

Move a scsi_device_put() call from alua_rtpg_select_sdev() to its
callers. Fixes the following smatch complaint:

drivers/scsi/device_handler/scsi_dh_alua.c:853 alua_rtpg_select_sdev() warn: sleeping in atomic context

alua_rtpg_work() <- disables preempt
-> alua_rtpg_select_sdev()
   -> scsi_device_put()

Cc: Hannes Reinecke <hare@suse.de>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Reported-by: default avatarDan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20221031224728.2607760-3-bvanassche@acm.orgSigned-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 0b25e17e
...@@ -815,14 +815,19 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg) ...@@ -815,14 +815,19 @@ static unsigned alua_stpg(struct scsi_device *sdev, struct alua_port_group *pg)
return SCSI_DH_RETRY; return SCSI_DH_RETRY;
} }
static bool alua_rtpg_select_sdev(struct alua_port_group *pg) /*
* The caller must call scsi_device_put() on the returned pointer if it is not
* NULL.
*/
static struct scsi_device * __must_check
alua_rtpg_select_sdev(struct alua_port_group *pg)
{ {
struct alua_dh_data *h; struct alua_dh_data *h;
struct scsi_device *sdev = NULL; struct scsi_device *sdev = NULL, *prev_sdev;
lockdep_assert_held(&pg->lock); lockdep_assert_held(&pg->lock);
if (WARN_ON(!pg->rtpg_sdev)) if (WARN_ON(!pg->rtpg_sdev))
return false; return NULL;
/* /*
* RCU protection isn't necessary for dh_list here * RCU protection isn't necessary for dh_list here
...@@ -849,22 +854,22 @@ static bool alua_rtpg_select_sdev(struct alua_port_group *pg) ...@@ -849,22 +854,22 @@ static bool alua_rtpg_select_sdev(struct alua_port_group *pg)
pr_warn("%s: no device found for rtpg\n", pr_warn("%s: no device found for rtpg\n",
(pg->device_id_len ? (pg->device_id_len ?
(char *)pg->device_id_str : "(nameless PG)")); (char *)pg->device_id_str : "(nameless PG)"));
return false; return NULL;
} }
sdev_printk(KERN_INFO, sdev, "rtpg retry on different device\n"); sdev_printk(KERN_INFO, sdev, "rtpg retry on different device\n");
scsi_device_put(pg->rtpg_sdev); prev_sdev = pg->rtpg_sdev;
pg->rtpg_sdev = sdev; pg->rtpg_sdev = sdev;
return true; return prev_sdev;
} }
static void alua_rtpg_work(struct work_struct *work) static void alua_rtpg_work(struct work_struct *work)
{ {
struct alua_port_group *pg = struct alua_port_group *pg =
container_of(work, struct alua_port_group, rtpg_work.work); container_of(work, struct alua_port_group, rtpg_work.work);
struct scsi_device *sdev; struct scsi_device *sdev, *prev_sdev = NULL;
LIST_HEAD(qdata_list); LIST_HEAD(qdata_list);
int err = SCSI_DH_OK; int err = SCSI_DH_OK;
struct alua_queue_data *qdata, *tmp; struct alua_queue_data *qdata, *tmp;
...@@ -905,7 +910,7 @@ static void alua_rtpg_work(struct work_struct *work) ...@@ -905,7 +910,7 @@ static void alua_rtpg_work(struct work_struct *work)
/* If RTPG failed on the current device, try using another */ /* If RTPG failed on the current device, try using another */
if (err == SCSI_DH_RES_TEMP_UNAVAIL && if (err == SCSI_DH_RES_TEMP_UNAVAIL &&
alua_rtpg_select_sdev(pg)) (prev_sdev = alua_rtpg_select_sdev(pg)))
err = SCSI_DH_IMM_RETRY; err = SCSI_DH_IMM_RETRY;
if (err == SCSI_DH_RETRY || err == SCSI_DH_IMM_RETRY || if (err == SCSI_DH_RETRY || err == SCSI_DH_IMM_RETRY ||
...@@ -917,9 +922,7 @@ static void alua_rtpg_work(struct work_struct *work) ...@@ -917,9 +922,7 @@ static void alua_rtpg_work(struct work_struct *work)
pg->interval = ALUA_RTPG_RETRY_DELAY; pg->interval = ALUA_RTPG_RETRY_DELAY;
pg->flags |= ALUA_PG_RUN_RTPG; pg->flags |= ALUA_PG_RUN_RTPG;
spin_unlock_irqrestore(&pg->lock, flags); spin_unlock_irqrestore(&pg->lock, flags);
queue_delayed_work(kaluad_wq, &pg->rtpg_work, goto queue_rtpg;
pg->interval * HZ);
return;
} }
if (err != SCSI_DH_OK) if (err != SCSI_DH_OK)
pg->flags &= ~ALUA_PG_RUN_STPG; pg->flags &= ~ALUA_PG_RUN_STPG;
...@@ -934,9 +937,7 @@ static void alua_rtpg_work(struct work_struct *work) ...@@ -934,9 +937,7 @@ static void alua_rtpg_work(struct work_struct *work)
pg->interval = 0; pg->interval = 0;
pg->flags &= ~ALUA_PG_RUNNING; pg->flags &= ~ALUA_PG_RUNNING;
spin_unlock_irqrestore(&pg->lock, flags); spin_unlock_irqrestore(&pg->lock, flags);
queue_delayed_work(kaluad_wq, &pg->rtpg_work, goto queue_rtpg;
pg->interval * HZ);
return;
} }
} }
...@@ -950,6 +951,9 @@ static void alua_rtpg_work(struct work_struct *work) ...@@ -950,6 +951,9 @@ static void alua_rtpg_work(struct work_struct *work)
pg->rtpg_sdev = NULL; pg->rtpg_sdev = NULL;
spin_unlock_irqrestore(&pg->lock, flags); spin_unlock_irqrestore(&pg->lock, flags);
if (prev_sdev)
scsi_device_put(prev_sdev);
list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) { list_for_each_entry_safe(qdata, tmp, &qdata_list, entry) {
list_del(&qdata->entry); list_del(&qdata->entry);
if (qdata->callback_fn) if (qdata->callback_fn)
...@@ -961,6 +965,12 @@ static void alua_rtpg_work(struct work_struct *work) ...@@ -961,6 +965,12 @@ static void alua_rtpg_work(struct work_struct *work)
spin_unlock_irqrestore(&pg->lock, flags); spin_unlock_irqrestore(&pg->lock, flags);
scsi_device_put(sdev); scsi_device_put(sdev);
kref_put(&pg->kref, release_port_group); kref_put(&pg->kref, release_port_group);
return;
queue_rtpg:
if (prev_sdev)
scsi_device_put(prev_sdev);
queue_delayed_work(kaluad_wq, &pg->rtpg_work, pg->interval * HZ);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment