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

cciss: Fix pci_driver.shutdown while device is still active

Fix an Oops in the cciss driver caused by system shutdown while a filesystem
on a cciss device is still active. The cciss_remove_one function only
properly removes the device if the device has been cleanly released by its
users, which is not the case when the pci_driver.shutdown method is called.

This patch adds a new cciss_shutdown function to better match the pattern
used by various SCSI drivers: deactivate device interrupts and flush caches.
It also alters the cciss_remove_one function to match and readds the
__devexit annotation that was removed when cciss_remove_one was serving as
the pci_driver.shutdown method.

Signed-off-by: Gerald Britton <gbritton@alum.mit.edu>
Acked-by: Mike Miller <mike.miller@hp.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Gerald Britton and committed by
Linus Torvalds
e9ca75b5 dec04cff

+31 -16
+31 -16
drivers/block/cciss.c
··· 3469 3469 return -1; 3470 3470 } 3471 3471 3472 - static void cciss_remove_one(struct pci_dev *pdev) 3472 + static void cciss_shutdown(struct pci_dev *pdev) 3473 + { 3474 + ctlr_info_t *tmp_ptr; 3475 + int i; 3476 + char flush_buf[4]; 3477 + int return_code; 3478 + 3479 + tmp_ptr = pci_get_drvdata(pdev); 3480 + if (tmp_ptr == NULL) 3481 + return; 3482 + i = tmp_ptr->ctlr; 3483 + if (hba[i] == NULL) 3484 + return; 3485 + 3486 + /* Turn board interrupts off and send the flush cache command */ 3487 + /* sendcmd will turn off interrupt, and send the flush... 3488 + * To write all data in the battery backed cache to disks */ 3489 + memset(flush_buf, 0, 4); 3490 + return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, 3491 + TYPE_CMD); 3492 + if (return_code == IO_OK) { 3493 + printk(KERN_INFO "Completed flushing cache on controller %d\n", i); 3494 + } else { 3495 + printk(KERN_WARNING "Error flushing cache on controller %d\n", i); 3496 + } 3497 + free_irq(hba[i]->intr[2], hba[i]); 3498 + } 3499 + 3500 + static void __devexit cciss_remove_one(struct pci_dev *pdev) 3473 3501 { 3474 3502 ctlr_info_t *tmp_ptr; 3475 3503 int i, j; 3476 - char flush_buf[4]; 3477 - int return_code; 3478 3504 3479 3505 if (pci_get_drvdata(pdev) == NULL) { 3480 3506 printk(KERN_ERR "cciss: Unable to remove device \n"); ··· 3532 3506 3533 3507 cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ 3534 3508 3535 - /* Turn board interrupts off and send the flush cache command */ 3536 - /* sendcmd will turn off interrupt, and send the flush... 3537 - * To write all data in the battery backed cache to disks */ 3538 - memset(flush_buf, 0, 4); 3539 - return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, 3540 - TYPE_CMD); 3541 - if (return_code == IO_OK) { 3542 - printk(KERN_INFO "Completed flushing cache on controller %d\n", i); 3543 - } else { 3544 - printk(KERN_WARNING "Error flushing cache on controller %d\n", i); 3545 - } 3546 - free_irq(hba[i]->intr[2], hba[i]); 3509 + cciss_shutdown(pdev); 3547 3510 3548 3511 #ifdef CONFIG_PCI_MSI 3549 3512 if (hba[i]->msix_vector) ··· 3565 3550 .probe = cciss_init_one, 3566 3551 .remove = __devexit_p(cciss_remove_one), 3567 3552 .id_table = cciss_pci_device_id, /* id_table */ 3568 - .shutdown = cciss_remove_one, 3553 + .shutdown = cciss_shutdown, 3569 3554 }; 3570 3555 3571 3556 /*