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.

Merge tag 'ata-7.0-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux

Pull ata fixes from Niklas Cassel:

- The newly introduced feature that issues a deferred (non-NCQ) command
from a workqueue, forgot to consider the case where the deferred QC
times out. Fix the code to take timeouts into consideration, which
avoids a use after free (Damien)

- The newly introduced feature that issues a deferred (non-NCQ) command
from a workqueue, when unloading the module, calls cancel_work_sync(),
a function that can sleep, while holding a spin lock. Move the function
call outside the lock (Damien)

* tag 'ata-7.0-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux:
ata: libata-core: fix cancellation of a port deferred qc work
ata: libata-eh: correctly handle deferred qc timeouts

+22 -8
+3 -5
drivers/ata/libata-core.c
··· 6269 6269 } 6270 6270 } 6271 6271 6272 - /* Make sure the deferred qc work finished. */ 6273 - cancel_work_sync(&ap->deferred_qc_work); 6274 - WARN_ON(ap->deferred_qc); 6275 - 6276 6272 /* Tell EH to disable all devices */ 6277 6273 ap->pflags |= ATA_PFLAG_UNLOADING; 6278 6274 ata_port_schedule_eh(ap); ··· 6279 6283 /* wait till EH commits suicide */ 6280 6284 ata_port_wait_eh(ap); 6281 6285 6282 - /* it better be dead now */ 6286 + /* It better be dead now and not have any remaining deferred qc. */ 6283 6287 WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED)); 6288 + WARN_ON(ap->deferred_qc); 6284 6289 6290 + cancel_work_sync(&ap->deferred_qc_work); 6285 6291 cancel_delayed_work_sync(&ap->hotplug_task); 6286 6292 cancel_delayed_work_sync(&ap->scsi_rescan_task); 6287 6293
+19 -3
drivers/ata/libata-eh.c
··· 640 640 set_host_byte(scmd, DID_OK); 641 641 642 642 ata_qc_for_each_raw(ap, qc, i) { 643 - if (qc->flags & ATA_QCFLAG_ACTIVE && 644 - qc->scsicmd == scmd) 643 + if (qc->scsicmd != scmd) 644 + continue; 645 + if ((qc->flags & ATA_QCFLAG_ACTIVE) || 646 + qc == ap->deferred_qc) 645 647 break; 646 648 } 647 649 648 - if (i < ATA_MAX_QUEUE) { 650 + if (qc == ap->deferred_qc) { 651 + /* 652 + * This is a deferred command that timed out while 653 + * waiting for the command queue to drain. Since the qc 654 + * is not active yet (deferred_qc is still set, so the 655 + * deferred qc work has not issued the command yet), 656 + * simply signal the timeout by finishing the SCSI 657 + * command and clear the deferred qc to prevent the 658 + * deferred qc work from issuing this qc. 659 + */ 660 + WARN_ON_ONCE(qc->flags & ATA_QCFLAG_ACTIVE); 661 + ap->deferred_qc = NULL; 662 + set_host_byte(scmd, DID_TIME_OUT); 663 + scsi_eh_finish_cmd(scmd, &ap->eh_done_q); 664 + } else if (i < ATA_MAX_QUEUE) { 649 665 /* the scmd has an associated qc */ 650 666 if (!(qc->flags & ATA_QCFLAG_EH)) { 651 667 /* which hasn't failed yet, timeout */