diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2005-09-01 11:29:08 +1000 |
---|---|---|
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) /* 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); |