Commit 669f044170d8933c3d66d231b69ea97cb8447338
Committed by
Martin K. Petersen
1 parent
27c3d76821
scsi: srp_transport: Move queuecommand() wait code to SCSI core
Additionally, rename srp_wait_for_queuecommand() into scsi_wait_for_queuecommand() and add a comment about the queuecommand() call from scsi_send_eh_cmnd(). Note: this patch changes scsi_internal_device_block from a function that did not sleep into a function that may sleep. This is fine for all callers of this function: * scsi_internal_device_block() is called from the mpt3sas device while that driver holds the ioc->dm_cmds.mutex. This means that the mpt3sas driver calls this function from thread context. * scsi_target_block() is called by __iscsi_block_session() from kernel thread context and with IRQs enabled. * The SRP transport code also calls scsi_target_block() from kernel thread context while sleeping is allowed. * The snic driver also calls scsi_target_block() from a context from which sleeping is allowed. The scsi_target_block() call namely occurs immediately after a scsi_flush_work() call. [mkp: s/shost/sdev/] Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Cc: James Bottomley <jejb@linux.vnet.ibm.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Doug Ledford <dledford@redhat.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Showing 2 changed files with 45 additions and 37 deletions Side-by-side Diff
drivers/scsi/scsi_lib.c
... | ... | @@ -2734,6 +2734,39 @@ |
2734 | 2734 | EXPORT_SYMBOL_GPL(sdev_evt_send_simple); |
2735 | 2735 | |
2736 | 2736 | /** |
2737 | + * scsi_request_fn_active() - number of kernel threads inside scsi_request_fn() | |
2738 | + * @sdev: SCSI device to count the number of scsi_request_fn() callers for. | |
2739 | + */ | |
2740 | +static int scsi_request_fn_active(struct scsi_device *sdev) | |
2741 | +{ | |
2742 | + struct request_queue *q = sdev->request_queue; | |
2743 | + int request_fn_active; | |
2744 | + | |
2745 | + WARN_ON_ONCE(sdev->host->use_blk_mq); | |
2746 | + | |
2747 | + spin_lock_irq(q->queue_lock); | |
2748 | + request_fn_active = q->request_fn_active; | |
2749 | + spin_unlock_irq(q->queue_lock); | |
2750 | + | |
2751 | + return request_fn_active; | |
2752 | +} | |
2753 | + | |
2754 | +/** | |
2755 | + * scsi_wait_for_queuecommand() - wait for ongoing queuecommand() calls | |
2756 | + * @sdev: SCSI device pointer. | |
2757 | + * | |
2758 | + * Wait until the ongoing shost->hostt->queuecommand() calls that are | |
2759 | + * invoked from scsi_request_fn() have finished. | |
2760 | + */ | |
2761 | +static void scsi_wait_for_queuecommand(struct scsi_device *sdev) | |
2762 | +{ | |
2763 | + WARN_ON_ONCE(sdev->host->use_blk_mq); | |
2764 | + | |
2765 | + while (scsi_request_fn_active(sdev)) | |
2766 | + msleep(20); | |
2767 | +} | |
2768 | + | |
2769 | +/** | |
2737 | 2770 | * scsi_device_quiesce - Block user issued commands. |
2738 | 2771 | * @sdev: scsi device to quiesce. |
2739 | 2772 | * |
... | ... | @@ -2817,8 +2850,7 @@ |
2817 | 2850 | * @sdev: device to block |
2818 | 2851 | * |
2819 | 2852 | * Block request made by scsi lld's to temporarily stop all |
2820 | - * scsi commands on the specified device. Called from interrupt | |
2821 | - * or normal process context. | |
2853 | + * scsi commands on the specified device. May sleep. | |
2822 | 2854 | * |
2823 | 2855 | * Returns zero if successful or error if not |
2824 | 2856 | * |
... | ... | @@ -2827,6 +2859,10 @@ |
2827 | 2859 | * (which must be a legal transition). When the device is in this |
2828 | 2860 | * state, all commands are deferred until the scsi lld reenables |
2829 | 2861 | * the device with scsi_device_unblock or device_block_tmo fires. |
2862 | + * | |
2863 | + * To do: avoid that scsi_send_eh_cmnd() calls queuecommand() after | |
2864 | + * scsi_internal_device_block() has blocked a SCSI device and also | |
2865 | + * remove the rport mutex lock and unlock calls from srp_queuecommand(). | |
2830 | 2866 | */ |
2831 | 2867 | int |
2832 | 2868 | scsi_internal_device_block(struct scsi_device *sdev) |
... | ... | @@ -2854,6 +2890,7 @@ |
2854 | 2890 | spin_lock_irqsave(q->queue_lock, flags); |
2855 | 2891 | blk_stop_queue(q); |
2856 | 2892 | spin_unlock_irqrestore(q->queue_lock, flags); |
2893 | + scsi_wait_for_queuecommand(sdev); | |
2857 | 2894 | } |
2858 | 2895 | |
2859 | 2896 | return 0; |
drivers/scsi/scsi_transport_srp.c
... | ... | @@ -24,7 +24,6 @@ |
24 | 24 | #include <linux/err.h> |
25 | 25 | #include <linux/slab.h> |
26 | 26 | #include <linux/string.h> |
27 | -#include <linux/delay.h> | |
28 | 27 | |
29 | 28 | #include <scsi/scsi.h> |
30 | 29 | #include <scsi/scsi_cmnd.h> |
... | ... | @@ -393,36 +392,6 @@ |
393 | 392 | } |
394 | 393 | } |
395 | 394 | |
396 | -/** | |
397 | - * scsi_request_fn_active() - number of kernel threads inside scsi_request_fn() | |
398 | - * @shost: SCSI host for which to count the number of scsi_request_fn() callers. | |
399 | - * | |
400 | - * To do: add support for scsi-mq in this function. | |
401 | - */ | |
402 | -static int scsi_request_fn_active(struct Scsi_Host *shost) | |
403 | -{ | |
404 | - struct scsi_device *sdev; | |
405 | - struct request_queue *q; | |
406 | - int request_fn_active = 0; | |
407 | - | |
408 | - shost_for_each_device(sdev, shost) { | |
409 | - q = sdev->request_queue; | |
410 | - | |
411 | - spin_lock_irq(q->queue_lock); | |
412 | - request_fn_active += q->request_fn_active; | |
413 | - spin_unlock_irq(q->queue_lock); | |
414 | - } | |
415 | - | |
416 | - return request_fn_active; | |
417 | -} | |
418 | - | |
419 | -/* Wait until ongoing shost->hostt->queuecommand() calls have finished. */ | |
420 | -static void srp_wait_for_queuecommand(struct Scsi_Host *shost) | |
421 | -{ | |
422 | - while (scsi_request_fn_active(shost)) | |
423 | - msleep(20); | |
424 | -} | |
425 | - | |
426 | 395 | static void __rport_fail_io_fast(struct srp_rport *rport) |
427 | 396 | { |
428 | 397 | struct Scsi_Host *shost = rport_to_shost(rport); |
429 | 398 | |
430 | 399 | |
... | ... | @@ -432,14 +401,17 @@ |
432 | 401 | |
433 | 402 | if (srp_rport_set_state(rport, SRP_RPORT_FAIL_FAST)) |
434 | 403 | return; |
404 | + /* | |
405 | + * Call scsi_target_block() to wait for ongoing shost->queuecommand() | |
406 | + * calls before invoking i->f->terminate_rport_io(). | |
407 | + */ | |
408 | + scsi_target_block(rport->dev.parent); | |
435 | 409 | scsi_target_unblock(rport->dev.parent, SDEV_TRANSPORT_OFFLINE); |
436 | 410 | |
437 | 411 | /* Involve the LLD if possible to terminate all I/O on the rport. */ |
438 | 412 | i = to_srp_internal(shost->transportt); |
439 | - if (i->f->terminate_rport_io) { | |
440 | - srp_wait_for_queuecommand(shost); | |
413 | + if (i->f->terminate_rport_io) | |
441 | 414 | i->f->terminate_rport_io(rport); |
442 | - } | |
443 | 415 | } |
444 | 416 | |
445 | 417 | /** |
... | ... | @@ -567,7 +539,6 @@ |
567 | 539 | if (res) |
568 | 540 | goto out; |
569 | 541 | scsi_target_block(&shost->shost_gendev); |
570 | - srp_wait_for_queuecommand(shost); | |
571 | 542 | res = rport->state != SRP_RPORT_LOST ? i->f->reconnect(rport) : -ENODEV; |
572 | 543 | pr_debug("%s (state %d): transport.reconnect() returned %d\n", |
573 | 544 | dev_name(&shost->shost_gendev), rport->state, res); |