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>
This commit is contained in:
Alexey Khoroshilov 2015-10-24 02:27:43 +03:00 committed by Greg Kroah-Hartman
parent 1051937d46
commit b1209983d2
1 changed files with 28 additions and 16 deletions

View File

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