tty: synclinkmp: do not ignore errors in probe()
synclinkmp_init_one() ignores all errors and does not release
all resources if something fails.
The patch adds returned code to device_init() and add_device()
and proper error handling.
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>
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index 4b314b6..90da0c7 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -549,8 +549,8 @@
unsigned int set, unsigned int clear);
static int set_break(struct tty_struct *tty, int break_state);
-static void add_device(SLMP_INFO *info);
-static void device_init(int adapter_num, struct pci_dev *pdev);
+static int add_device(SLMP_INFO *info);
+static int device_init(int adapter_num, struct pci_dev *pdev);
static int claim_resources(SLMP_INFO *info);
static void release_resources(SLMP_INFO *info);
@@ -3688,7 +3688,7 @@
/* Add the specified device instance data structure to the
* global linked list of devices and increment the device count.
*/
-static void add_device(SLMP_INFO *info)
+static int add_device(SLMP_INFO *info)
{
info->next_device = NULL;
info->line = synclinkmp_device_count;
@@ -3726,7 +3726,9 @@
info->max_frame_size );
#if SYNCLINK_GENERIC_HDLC
- hdlcdev_init(info);
+ return hdlcdev_init(info);
+#else
+ return 0;
#endif
}
@@ -3815,10 +3817,10 @@
return info;
}
-static void device_init(int adapter_num, struct pci_dev *pdev)
+static int device_init(int adapter_num, struct pci_dev *pdev)
{
SLMP_INFO *port_array[SCA_MAX_PORTS];
- int port;
+ int port, rc;
/* allocate device instances for up to SCA_MAX_PORTS devices */
for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
@@ -3828,14 +3830,16 @@
tty_port_destroy(&port_array[port]->port);
kfree(port_array[port]);
}
- return;
+ return -ENOMEM;
}
}
/* give copy of port_array to all ports and add to device list */
for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
memcpy(port_array[port]->port_array,port_array,sizeof(port_array));
- add_device( port_array[port] );
+ rc = add_device( port_array[port] );
+ if (rc)
+ goto err_add;
spin_lock_init(&port_array[port]->lock);
}
@@ -3855,21 +3859,30 @@
alloc_dma_bufs(port_array[port]);
}
- if ( request_irq(port_array[0]->irq_level,
+ rc = request_irq(port_array[0]->irq_level,
synclinkmp_interrupt,
port_array[0]->irq_flags,
port_array[0]->device_name,
- port_array[0]) < 0 ) {
+ port_array[0]);
+ if ( rc ) {
printk( "%s(%d):%s Can't request interrupt, IRQ=%d\n",
__FILE__,__LINE__,
port_array[0]->device_name,
port_array[0]->irq_level );
+ goto err_irq;
}
- else {
- port_array[0]->irq_requested = true;
- adapter_test(port_array[0]);
- }
+ port_array[0]->irq_requested = true;
+ adapter_test(port_array[0]);
}
+ return 0;
+err_irq:
+ release_resources( port_array[0] );
+err_add:
+ for ( port = 0; port < SCA_MAX_PORTS; ++port ) {
+ tty_port_destroy(&port_array[port]->port);
+ kfree(port_array[port]);
+ }
+ return rc;
}
static const struct tty_operations ops = {
@@ -5584,8 +5597,7 @@
printk("error enabling pci device %p\n", dev);
return -EIO;
}
- device_init( ++synclinkmp_adapter_count, dev );
- return 0;
+ return device_init( ++synclinkmp_adapter_count, dev );
}
static void synclinkmp_remove_one (struct pci_dev *dev)