diff options
author | Alexey Khoroshilov <khoroshilov@ispras.ru> | 2013-02-16 17:24:37 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-02-18 14:05:14 -0500 |
commit | 9e17df37d710f8998e9cb10a548304fe33d4a5c2 (patch) | |
tree | 67e3c53b0015d37f23b76c8f661342b8ea504b26 /drivers/tty | |
parent | f30e826069918da0876493e2de9ba13287b68e0a (diff) |
tty: mxser: improve error handling in mxser_probe() and mxser_module_init()
1. Currently mxser_probe() and mxser_module_init() ignore errors
that can happen in tty_port_register_device().
2. mxser_module_init() does not deallocate resources allocated in mxser_get_ISA_conf()
if mxser_initbrd() failed.
The patch adds proper error handling in all the cases.
Also it moves free_irq() from mxser_release_ISA_res() to mxser_board_remove(),
since it makes mxser_release_ISA_res() a counterpart for mxser_get_ISA_conf(),
while free_irq() is relevant to both ISA and PCI boards.
Found by Linux Driver Verification project (linuxtesting.org).
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/mxser.c | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index ad34a202a34d..484b6a3c9b03 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c | |||
@@ -2364,7 +2364,6 @@ static void mxser_release_vector(struct mxser_board *brd) | |||
2364 | 2364 | ||
2365 | static void mxser_release_ISA_res(struct mxser_board *brd) | 2365 | static void mxser_release_ISA_res(struct mxser_board *brd) |
2366 | { | 2366 | { |
2367 | free_irq(brd->irq, brd); | ||
2368 | release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); | 2367 | release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); |
2369 | mxser_release_vector(brd); | 2368 | mxser_release_vector(brd); |
2370 | } | 2369 | } |
@@ -2430,6 +2429,7 @@ static void mxser_board_remove(struct mxser_board *brd) | |||
2430 | tty_unregister_device(mxvar_sdriver, brd->idx + i); | 2429 | tty_unregister_device(mxvar_sdriver, brd->idx + i); |
2431 | tty_port_destroy(&brd->ports[i].port); | 2430 | tty_port_destroy(&brd->ports[i].port); |
2432 | } | 2431 | } |
2432 | free_irq(brd->irq, brd); | ||
2433 | } | 2433 | } |
2434 | 2434 | ||
2435 | static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) | 2435 | static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) |
@@ -2554,6 +2554,7 @@ static int mxser_probe(struct pci_dev *pdev, | |||
2554 | struct mxser_board *brd; | 2554 | struct mxser_board *brd; |
2555 | unsigned int i, j; | 2555 | unsigned int i, j; |
2556 | unsigned long ioaddress; | 2556 | unsigned long ioaddress; |
2557 | struct device *tty_dev; | ||
2557 | int retval = -EINVAL; | 2558 | int retval = -EINVAL; |
2558 | 2559 | ||
2559 | for (i = 0; i < MXSER_BOARDS; i++) | 2560 | for (i = 0; i < MXSER_BOARDS; i++) |
@@ -2637,13 +2638,25 @@ static int mxser_probe(struct pci_dev *pdev, | |||
2637 | if (retval) | 2638 | if (retval) |
2638 | goto err_rel3; | 2639 | goto err_rel3; |
2639 | 2640 | ||
2640 | for (i = 0; i < brd->info->nports; i++) | 2641 | for (i = 0; i < brd->info->nports; i++) { |
2641 | tty_port_register_device(&brd->ports[i].port, mxvar_sdriver, | 2642 | tty_dev = tty_port_register_device(&brd->ports[i].port, |
2642 | brd->idx + i, &pdev->dev); | 2643 | mxvar_sdriver, brd->idx + i, &pdev->dev); |
2644 | if (IS_ERR(tty_dev)) { | ||
2645 | retval = PTR_ERR(tty_dev); | ||
2646 | for (i--; i >= 0; i--) | ||
2647 | tty_unregister_device(mxvar_sdriver, | ||
2648 | brd->idx + i); | ||
2649 | goto err_relbrd; | ||
2650 | } | ||
2651 | } | ||
2643 | 2652 | ||
2644 | pci_set_drvdata(pdev, brd); | 2653 | pci_set_drvdata(pdev, brd); |
2645 | 2654 | ||
2646 | return 0; | 2655 | return 0; |
2656 | err_relbrd: | ||
2657 | for (i = 0; i < brd->info->nports; i++) | ||
2658 | tty_port_destroy(&brd->ports[i].port); | ||
2659 | free_irq(brd->irq, brd); | ||
2647 | err_rel3: | 2660 | err_rel3: |
2648 | pci_release_region(pdev, 3); | 2661 | pci_release_region(pdev, 3); |
2649 | err_zero: | 2662 | err_zero: |
@@ -2665,7 +2678,6 @@ static void mxser_remove(struct pci_dev *pdev) | |||
2665 | 2678 | ||
2666 | mxser_board_remove(brd); | 2679 | mxser_board_remove(brd); |
2667 | 2680 | ||
2668 | free_irq(pdev->irq, brd); | ||
2669 | pci_release_region(pdev, 2); | 2681 | pci_release_region(pdev, 2); |
2670 | pci_release_region(pdev, 3); | 2682 | pci_release_region(pdev, 3); |
2671 | pci_disable_device(pdev); | 2683 | pci_disable_device(pdev); |
@@ -2683,6 +2695,7 @@ static struct pci_driver mxser_driver = { | |||
2683 | static int __init mxser_module_init(void) | 2695 | static int __init mxser_module_init(void) |
2684 | { | 2696 | { |
2685 | struct mxser_board *brd; | 2697 | struct mxser_board *brd; |
2698 | struct device *tty_dev; | ||
2686 | unsigned int b, i, m; | 2699 | unsigned int b, i, m; |
2687 | int retval; | 2700 | int retval; |
2688 | 2701 | ||
@@ -2728,14 +2741,29 @@ static int __init mxser_module_init(void) | |||
2728 | 2741 | ||
2729 | /* mxser_initbrd will hook ISR. */ | 2742 | /* mxser_initbrd will hook ISR. */ |
2730 | if (mxser_initbrd(brd, NULL) < 0) { | 2743 | if (mxser_initbrd(brd, NULL) < 0) { |
2744 | mxser_release_ISA_res(brd); | ||
2731 | brd->info = NULL; | 2745 | brd->info = NULL; |
2732 | continue; | 2746 | continue; |
2733 | } | 2747 | } |
2734 | 2748 | ||
2735 | brd->idx = m * MXSER_PORTS_PER_BOARD; | 2749 | brd->idx = m * MXSER_PORTS_PER_BOARD; |
2736 | for (i = 0; i < brd->info->nports; i++) | 2750 | for (i = 0; i < brd->info->nports; i++) { |
2737 | tty_port_register_device(&brd->ports[i].port, | 2751 | tty_dev = tty_port_register_device(&brd->ports[i].port, |
2738 | mxvar_sdriver, brd->idx + i, NULL); | 2752 | mxvar_sdriver, brd->idx + i, NULL); |
2753 | if (IS_ERR(tty_dev)) { | ||
2754 | for (i--; i >= 0; i--) | ||
2755 | tty_unregister_device(mxvar_sdriver, | ||
2756 | brd->idx + i); | ||
2757 | for (i = 0; i < brd->info->nports; i++) | ||
2758 | tty_port_destroy(&brd->ports[i].port); | ||
2759 | free_irq(brd->irq, brd); | ||
2760 | mxser_release_ISA_res(brd); | ||
2761 | brd->info = NULL; | ||
2762 | break; | ||
2763 | } | ||
2764 | } | ||
2765 | if (brd->info == NULL) | ||
2766 | continue; | ||
2739 | 2767 | ||
2740 | m++; | 2768 | m++; |
2741 | } | 2769 | } |