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:
parent
1051937d46
commit
b1209983d2
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue