Message ID | 20230612165049.29440-5-mwilck@suse.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | scsi: fixes for targets with many LUNs, and scsi_target_block rework | expand |
On 6/12/23 09:50, mwilck@suse.com wrote: > @@ -2800,9 +2792,17 @@ static void scsi_device_block(struct scsi_device *sdev, void *data) > > mutex_lock(&sdev->state_mutex); > err = __scsi_internal_device_block_nowait(sdev); > - if (err == 0) > - scsi_stop_queue(sdev, false); > - mutex_unlock(&sdev->state_mutex); > + if (err == 0) { > + /* > + * scsi_stop_queue() must be called with the state_mutex > + * held. Otherwise a simultaneous scsi_start_queue() call > + * might unquiesce the queue before we quiesce it. > + */ > + scsi_stop_queue(sdev); > + mutex_unlock(&sdev->state_mutex); > + blk_mq_wait_quiesce_done(sdev->request_queue->tag_set); > + } else > + mutex_unlock(&sdev->state_mutex); > > WARN_ONCE(err, "__scsi_internal_device_block_nowait(%s) failed: err = %d\n", > dev_name(&sdev->sdev_gendev), err); Has it been considered to modify the above code such that there is a single mutex_unlock() call instead of two? I wouldn't mind if blk_mq_wait_quiesce_done() would be called if err != 0 since performance is not that important if this function fails. Thanks, Bart.
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
On Mon, 2023-06-12 at 11:02 -0700, Bart Van Assche wrote: > On 6/12/23 09:50, mwilck@suse.com wrote: > > @@ -2800,9 +2792,17 @@ static void scsi_device_block(struct > > scsi_device *sdev, void *data) > > > > mutex_lock(&sdev->state_mutex); > > err = __scsi_internal_device_block_nowait(sdev); > > - if (err == 0) > > - scsi_stop_queue(sdev, false); > > - mutex_unlock(&sdev->state_mutex); > > + if (err == 0) { > > + /* > > + * scsi_stop_queue() must be called with the > > state_mutex > > + * held. Otherwise a simultaneous > > scsi_start_queue() call > > + * might unquiesce the queue before we quiesce it. > > + */ > > + scsi_stop_queue(sdev); > > + mutex_unlock(&sdev->state_mutex); > > + blk_mq_wait_quiesce_done(sdev->request_queue- > > >tag_set); > > + } else > > + mutex_unlock(&sdev->state_mutex); > > > > WARN_ONCE(err, "__scsi_internal_device_block_nowait(%s) > > failed: err = %d\n", > > dev_name(&sdev->sdev_gendev), err); > > Has it been considered to modify the above code such that there is a > single mutex_unlock() call instead of two? I wouldn't mind if > blk_mq_wait_quiesce_done() would be called if err != 0 since > performance > is not that important if this function fails. This code is just an intermediate stage. The double mutex_unlock() is converted back to a single one in the subsequent patch. As Christoph has already ack'd it, unless it's really important to you, I'd like to keep this patch as-is. Thanks, Martin
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 69fb7a9d8883..3e12cc61569d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2731,24 +2731,16 @@ void scsi_start_queue(struct scsi_device *sdev) blk_mq_unquiesce_queue(sdev->request_queue); } -static void scsi_stop_queue(struct scsi_device *sdev, bool nowait) +static void scsi_stop_queue(struct scsi_device *sdev) { /* * The atomic variable of ->queue_stopped covers that * blk_mq_quiesce_queue* is balanced with blk_mq_unquiesce_queue. * - * However, we still need to wait until quiesce is done - * in case that queue has been stopped. + * The caller needs to wait until quiesce is done. */ - if (!cmpxchg(&sdev->queue_stopped, 0, 1)) { - if (nowait) - blk_mq_quiesce_queue_nowait(sdev->request_queue); - else - blk_mq_quiesce_queue(sdev->request_queue); - } else { - if (!nowait) - blk_mq_wait_quiesce_done(sdev->request_queue->tag_set); - } + if (!cmpxchg(&sdev->queue_stopped, 0, 1)) + blk_mq_quiesce_queue_nowait(sdev->request_queue); } /** @@ -2775,7 +2767,7 @@ int scsi_internal_device_block_nowait(struct scsi_device *sdev) * request queue. */ if (!ret) - scsi_stop_queue(sdev, true); + scsi_stop_queue(sdev); return ret; } EXPORT_SYMBOL_GPL(scsi_internal_device_block_nowait); @@ -2800,9 +2792,17 @@ static void scsi_device_block(struct scsi_device *sdev, void *data) mutex_lock(&sdev->state_mutex); err = __scsi_internal_device_block_nowait(sdev); - if (err == 0) - scsi_stop_queue(sdev, false); - mutex_unlock(&sdev->state_mutex); + if (err == 0) { + /* + * scsi_stop_queue() must be called with the state_mutex + * held. Otherwise a simultaneous scsi_start_queue() call + * might unquiesce the queue before we quiesce it. + */ + scsi_stop_queue(sdev); + mutex_unlock(&sdev->state_mutex); + blk_mq_wait_quiesce_done(sdev->request_queue->tag_set); + } else + mutex_unlock(&sdev->state_mutex); WARN_ONCE(err, "__scsi_internal_device_block_nowait(%s) failed: err = %d\n", dev_name(&sdev->sdev_gendev), err);