aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2005-09-01 11:29:08 +1000
committerJeff Garzik <jgarzik@pobox.com>2005-08-31 22:39:43 -0400
commitec60beebed497691c97d674c1facac5ca3d7a4b3 (patch)
tree0591903d946969283238116291b2755b1cfa86d2
parentcbf9074cc30ca0eee19c9bd7304faf9f1beb1e76 (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.c35
1 files changed, 22 insertions, 13 deletions
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 91d79db96e8..ab9fb218d11 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -683,6 +683,14 @@ static void veth_stop_connection(u8 rlp)
/* Wait for the state machine to run. */
flush_scheduled_work();
+}
+
+static void veth_destroy_connection(u8 rlp)
+{
+ struct veth_lpar_connection *cnx = veth_cnx[rlp];
+
+ if (! cnx)
+ return;
if (cnx->num_events > 0)
mf_deallocate_lp_events(cnx->remote_lp,
@@ -694,14 +702,6 @@ static void veth_stop_connection(u8 rlp)
HvLpEvent_Type_VirtualLan,
cnx->num_ack_events,
NULL, NULL);
-}
-
-static void veth_destroy_connection(u8 rlp)
-{
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
- if (! cnx)
- return;
kfree(cnx->msgs);
kfree(cnx);
@@ -1441,15 +1441,24 @@ int __init veth_module_init(void)
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
rc = veth_init_connection(i);
- if (rc != 0) {
- veth_module_cleanup();
- return rc;
- }
+ if (rc != 0)
+ goto error;
}
HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan,
&veth_handle_event);
- return vio_register_driver(&veth_driver);
+ rc = vio_register_driver(&veth_driver);
+ if (rc != 0)
+ goto error;
+
+ return 0;
+
+error:
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+ veth_destroy_connection(i);
+ }
+
+ return rc;
}
module_init(veth_module_init);