diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2005-08-31 21:29:08 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-31 22:39:43 -0400 |
commit | ec60beebed497691c97d674c1facac5ca3d7a4b3 (patch) | |
tree | 0591903d946969283238116291b2755b1cfa86d2 | |
parent | cbf9074cc30ca0eee19c9bd7304faf9f1beb1e76 (diff) |
[PATCH] iseries_veth: Make init_connection() & destroy_connection() symmetrical
This patch makes veth_init_connection() and veth_destroy_connection()
symmetrical in that they allocate/deallocate the same data.
Currently if there's an error while initialising connections (ie. ENOMEM)
we call veth_module_cleanup(), however this will oops because we call
driver_unregister() before we've called driver_register(). I've never seen
this actually happen though.
So instead we explicitly call veth_destroy_connection() for each connection,
any that have been set up will be deallocated.
We also fix a potential leak if vio_register_driver() fails.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | drivers/net/iseries_veth.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 91d79db96e82..ab9fb218d111 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c | |||
@@ -683,6 +683,14 @@ static void veth_stop_connection(u8 rlp) | |||
683 | 683 | ||
684 | /* Wait for the state machine to run. */ | 684 | /* Wait for the state machine to run. */ |
685 | flush_scheduled_work(); | 685 | flush_scheduled_work(); |
686 | } | ||
687 | |||
688 | static void veth_destroy_connection(u8 rlp) | ||
689 | { | ||
690 | struct veth_lpar_connection *cnx = veth_cnx[rlp]; | ||
691 | |||
692 | if (! cnx) | ||
693 | return; | ||
686 | 694 | ||
687 | if (cnx->num_events > 0) | 695 | if (cnx->num_events > 0) |
688 | mf_deallocate_lp_events(cnx->remote_lp, | 696 | mf_deallocate_lp_events(cnx->remote_lp, |
@@ -694,14 +702,6 @@ static void veth_stop_connection(u8 rlp) | |||
694 | HvLpEvent_Type_VirtualLan, | 702 | HvLpEvent_Type_VirtualLan, |
695 | cnx->num_ack_events, | 703 | cnx->num_ack_events, |
696 | NULL, NULL); | 704 | NULL, NULL); |
697 | } | ||
698 | |||
699 | static void veth_destroy_connection(u8 rlp) | ||
700 | { | ||
701 | struct veth_lpar_connection *cnx = veth_cnx[rlp]; | ||
702 | |||
703 | if (! cnx) | ||
704 | return; | ||
705 | 705 | ||
706 | kfree(cnx->msgs); | 706 | kfree(cnx->msgs); |
707 | kfree(cnx); | 707 | kfree(cnx); |
@@ -1441,15 +1441,24 @@ int __init veth_module_init(void) | |||
1441 | 1441 | ||
1442 | for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) { | 1442 | for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) { |
1443 | rc = veth_init_connection(i); | 1443 | rc = veth_init_connection(i); |
1444 | if (rc != 0) { | 1444 | if (rc != 0) |
1445 | veth_module_cleanup(); | 1445 | goto error; |
1446 | return rc; | ||
1447 | } | ||
1448 | } | 1446 | } |
1449 | 1447 | ||
1450 | HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan, | 1448 | HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan, |
1451 | &veth_handle_event); | 1449 | &veth_handle_event); |
1452 | 1450 | ||
1453 | return vio_register_driver(&veth_driver); | 1451 | rc = vio_register_driver(&veth_driver); |
1452 | if (rc != 0) | ||
1453 | goto error; | ||
1454 | |||
1455 | return 0; | ||
1456 | |||
1457 | error: | ||
1458 | for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) { | ||
1459 | veth_destroy_connection(i); | ||
1460 | } | ||
1461 | |||
1462 | return rc; | ||
1454 | } | 1463 | } |
1455 | module_init(veth_module_init); | 1464 | module_init(veth_module_init); |