Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ata: libata-eh: avoid unnecessary calls to ata_scsi_port_error_handler()

When handling SCSI command timeouts, if we had no actual command
timeouts (either because the command was a deferred qc or the completion
path won the race with ata_scsi_cmd_error_handler()), we do not need to
go through a port error handling, as there was in fact no errors at all.

Modify ata_scsi_cmd_error_handler() to return the number of commands
that timed out and use this return value in ata_scsi_error() to call
ata_scsi_port_error_handler() only if we had command timeouts, or if
the port EH has already been scheduled due to failed commands.
Otherwise, simply call scsi_eh_flush_done_q() to finish the completed
commands without running the full port error handling.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Niklas Cassel <cassel@kernel.org>

authored by

Damien Le Moal and committed by
Niklas Cassel
46a9d970 db1d3cfa

+21 -10
+19 -9
drivers/ata/libata-eh.c
··· 560 560 { 561 561 struct ata_port *ap = ata_shost_to_port(host); 562 562 unsigned long flags; 563 + int nr_timedout; 563 564 LIST_HEAD(eh_work_q); 564 565 565 566 spin_lock_irqsave(host->host_lock, flags); 566 567 list_splice_init(&host->eh_cmd_q, &eh_work_q); 567 568 spin_unlock_irqrestore(host->host_lock, flags); 568 569 569 - ata_scsi_cmd_error_handler(host, ap, &eh_work_q); 570 + /* 571 + * First check what errors we got with ata_scsi_cmd_error_handler(). 572 + * If we had no command timeouts and EH is not scheduled for this port, 573 + * meaning that we do not have any failed command, then there is no 574 + * need to go through the full port error handling. We only need to 575 + * flush the completed commands we have. 576 + */ 577 + nr_timedout = ata_scsi_cmd_error_handler(host, ap, &eh_work_q); 578 + if (nr_timedout || ata_port_eh_scheduled(ap)) 579 + ata_scsi_port_error_handler(host, ap); 580 + else 581 + scsi_eh_flush_done_q(&ap->eh_done_q); 570 582 571 - /* If we timed raced normal completion and there is nothing to 572 - recover nr_timedout == 0 why exactly are we doing error recovery ? */ 573 - ata_scsi_port_error_handler(host, ap); 574 - 575 - /* finish or retry handled scmd's and clean up */ 576 583 WARN_ON(!list_empty(&eh_work_q)); 577 - 578 584 } 579 585 580 586 /** ··· 592 586 * process the given list of commands and return those finished to the 593 587 * ap->eh_done_q. This function is the first part of the libata error 594 588 * handler which processes a given list of failed commands. 589 + * 590 + * Return the number of commands that timed out. 595 591 */ 596 - void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, 597 - struct list_head *eh_work_q) 592 + int ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, 593 + struct list_head *eh_work_q) 598 594 { 599 595 int i; 600 596 unsigned long flags; ··· 686 678 ap->eh_tries = ATA_EH_MAX_TRIES; 687 679 688 680 spin_unlock_irqrestore(ap->lock, flags); 681 + 682 + return nr_timedout; 689 683 } 690 684 EXPORT_SYMBOL(ata_scsi_cmd_error_handler); 691 685
+2 -1
include/linux/libata.h
··· 1225 1225 extern struct ata_device *ata_dev_pair(struct ata_device *adev); 1226 1226 int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); 1227 1227 extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap); 1228 - extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q); 1228 + int ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, 1229 + struct list_head *eh_q); 1229 1230 1230 1231 /* 1231 1232 * SATA specific code - drivers/ata/libata-sata.c