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.
Unified · Split
| @@ -3469,13 +3469,39 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, · 3468 unmodified lines | ||
| 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 | 3473 | { |
| 3474 | 3474 | ctlr_info_t *tmp_ptr; |
| 3475 | − int i, j; | |
| 3475 | + int i; | |
| 3476 | 3476 | char flush_buf[4]; |
| 3477 | 3477 | int return_code; |
| 3478 | 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) | |
| 3501 | +{ | |
| 3502 | + ctlr_info_t *tmp_ptr; | |
| 3503 | + int i, j; | |
| 3504 | + | |
| 3479 | 3505 | if (pci_get_drvdata(pdev) == NULL) { |
| 3480 | 3506 | printk(KERN_ERR "cciss: Unable to remove device \n"); |
| 3481 | 3507 | return; |
| @@ -3506,18 +3532,7 @@ static void cciss_remove_one(struct pci_dev *pdev) · 24 unmodified lines | ||
| 3506 | 3532 | |
| 3507 | 3533 | cciss_unregister_scsi(i); /* unhook from SCSI subsystem */ |
| 3508 | 3534 | |
| 3509 | − /* Turn board interrupts off and send the flush cache command */ | |
| 3510 | − /* sendcmd will turn off interrupt, and send the flush... | |
| 3511 | − * To write all data in the battery backed cache to disks */ | |
| 3512 | − memset(flush_buf, 0, 4); | |
| 3513 | − return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, | |
| 3514 | − TYPE_CMD); | |
| 3515 | − if (return_code == IO_OK) { | |
| 3516 | − printk(KERN_INFO "Completed flushing cache on controller %d\n", i); | |
| 3517 | − } else { | |
| 3518 | − printk(KERN_WARNING "Error flushing cache on controller %d\n", i); | |
| 3519 | − } | |
| 3520 | − free_irq(hba[i]->intr[2], hba[i]); | |
| 3535 | + cciss_shutdown(pdev); | |
| 3521 | 3536 | |
| 3522 | 3537 | #ifdef CONFIG_PCI_MSI |
| 3523 | 3538 | if (hba[i]->msix_vector) |
| @@ -3550,7 +3565,7 @@ static struct pci_driver cciss_pci_driver = { · 26 unmodified lines | ||
| 3550 | 3565 | .probe = cciss_init_one, |
| 3551 | 3566 | .remove = __devexit_p(cciss_remove_one), |
| 3552 | 3567 | .id_table = cciss_pci_device_id, /* id_table */ |
| 3553 | − .shutdown = cciss_remove_one, | |
| 3568 | + .shutdown = cciss_shutdown, | |
| 3554 | 3569 | }; |
| 3555 | 3570 | |
| 3556 | 3571 | /* |