From: Michael Ellerman <michael@ellerman.id.au>
To: linuxppc64-dev@ozlabs.org, netdev@oss.sgi.com,
linux-kernel@vger.kernel.org
Subject: [PATCH 9/12] iseries_veth: Use ref counts to track lifecycle of connection structs
Date: Thu, 30 Jun 2005 20:20:39 +1000 [thread overview]
Message-ID: <1120126839.794259.894526862881.qpatch@concordia> (raw)
In-Reply-To: <200506302016.55125.michael@ellerman.id.au>
The iseries_veth driver can attach to multiple vlans, which correspond to
multiple net devices. However there is only 1 connection between each LPAR,
so the connection structure may be shared by multiple net devices.
This makes module removal messy, because we can't deallocate the connections
until we know there are no net devices still using them. The solution is to
use ref counts on the connections, so we can delete them (actually stop) as
soon as the ref count hits zero.
This patch fixes (part of) a bug we were seeing with IPv6 sending probes to
a dead LPAR, which would then hang us forever due to leftover skbs.
This patch has the (minor?) side effect that we only start negotiating a
connection with LPARs which are on one of our vlans. The previous behaviour
was to start negotiation with all LPARs unconditionally, will have the think
about that one.
---
drivers/net/iseries_veth.c | 89 ++++++++++++++++++++++++++++++---------------
1 files changed, 61 insertions(+), 28 deletions(-)
Index: veth-dev/drivers/net/iseries_veth.c
===================================================================
--- veth-dev.orig/drivers/net/iseries_veth.c
+++ veth-dev/drivers/net/iseries_veth.c
@@ -129,6 +129,7 @@ struct veth_lpar_connection {
int num_events;
struct VethCapData local_caps;
+ struct kref refcount;
struct timer_list ack_timer;
spinlock_t lock;
@@ -620,6 +621,10 @@ static int veth_init_connection(u8 rlp)
return -ENOMEM;
memset(cnx, 0, sizeof(*cnx));
+ /* This gets us 1 reference, which is held on behalf of the driver
+ * infrastructure. It's released at module unload. */
+ kref_init(&cnx->refcount);
+
cnx->remote_lp = rlp;
spin_lock_init(&cnx->lock);
INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx);
@@ -658,12 +663,10 @@ static int veth_init_connection(u8 rlp)
return 0;
}
-static void veth_stop_connection(u8 rlp)
+static void veth_stop_connection(struct kref *ref)
{
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
- if (! cnx)
- return;
+ struct veth_lpar_connection *cnx;
+ cnx = container_of(ref, struct veth_lpar_connection, refcount);
spin_lock_irq(&cnx->lock);
cnx->state |= VETH_STATE_RESET | VETH_STATE_SHUTDOWN;
@@ -1352,15 +1355,31 @@ static void veth_timed_ack(unsigned long
static int veth_remove(struct vio_dev *vdev)
{
- int i = vdev->unit_address;
+ struct veth_lpar_connection *cnx;
struct net_device *dev;
+ struct veth_port *port;
+ int i;
- dev = veth_dev[i];
- if (dev != NULL) {
- veth_dev[i] = NULL;
- unregister_netdev(dev);
- free_netdev(dev);
+ dev = veth_dev[vdev->unit_address];
+
+ if (! dev)
+ return 0;
+
+ port = netdev_priv(dev);
+
+ for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
+ cnx = veth_cnx[i];
+
+ if (cnx && (port->lpar_map & (1 << i))) {
+ /* Drop our reference to connections on our VLAN */
+ kref_put(&cnx->refcount, veth_stop_connection);
+ }
}
+
+ veth_dev[vdev->unit_address] = NULL;
+ unregister_netdev(dev);
+ free_netdev(dev);
+
return 0;
}
@@ -1368,6 +1387,7 @@ static int veth_probe(struct vio_dev *vd
{
int i = vdev->unit_address;
struct net_device *dev;
+ struct veth_port *port;
dev = veth_probe_one(i, &vdev->dev);
if (dev == NULL) {
@@ -1376,11 +1396,19 @@ static int veth_probe(struct vio_dev *vd
}
veth_dev[i] = dev;
- /* Start the state machine on each connection, to commence
- * link negotiation */
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++)
- if (veth_cnx[i])
+ port = (struct veth_port*)netdev_priv(dev);
+
+ /* Start the state machine on each connection on this vlan. If we're
+ * the first dev to do so this will commence link negotiation */
+ for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
+ if (! (port->lpar_map & (1 << i)))
+ continue;
+
+ if (veth_cnx[i]) {
+ kref_get(&(veth_cnx[i]->refcount));
veth_kick_statemachine(veth_cnx[i]);
+ }
+ }
return 0;
}
@@ -1409,26 +1437,31 @@ static struct vio_driver veth_driver = {
void __exit veth_module_cleanup(void)
{
int i;
+ struct veth_lpar_connection *cnx;
- /* Stop the queues first to stop any new packets being sent. */
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++)
- if (veth_dev[i])
- netif_stop_queue(veth_dev[i]);
+ /* Drop the driver's references to the connections. */
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+ cnx = veth_cnx[i];
- /* Stop the connections before we unregister the driver. This
- * ensures there's no skbs lying around holding the device open. */
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
- veth_stop_connection(i);
+ if (cnx) {
+ kref_put(&cnx->refcount, veth_stop_connection);
+ }
+ }
- HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
+ /* Unregister the driver, which will close all the netdevs and stop
+ * the connections when they're no longer referenced. */
+ vio_unregister_driver(&veth_driver);
- /* Hypervisor callbacks may have scheduled more work while we
- * were stoping connections. Now that we've disconnected from
- * the hypervisor make sure everything's finished. */
+ /* Make sure each connection's state machine has run to completion. */
flush_scheduled_work();
- vio_unregister_driver(&veth_driver);
+ /* Disconnect our "irq" to stop events coming from the Hypervisor. */
+ HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
+
+ /* Make sure any work queued from Hypervisor callbacks is finished. */
+ flush_scheduled_work();
+ /* Deallocate everything. */
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
veth_destroy_connection(i);
next prev parent reply other threads:[~2005-06-30 10:52 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-06-30 10:16 [RFC/PATCH 0/12] Updates & bug fixes for iseries_veth network driver Michael Ellerman
2005-06-30 10:20 ` [PATCH 5/12] iseries_veth: Try to avoid pathological reset behaviour Michael Ellerman
2005-06-30 10:20 ` [PATCH 1/12] iseries_veth: Make error messages more user friendly, and add a debug macro Michael Ellerman
2005-06-30 10:20 ` [PATCH 6/12] iseries_veth: Fix broken promiscuous handling Michael Ellerman
2005-06-30 10:20 ` [PATCH 10/12] iseries_veth: Remove TX timeout code Michael Ellerman
2005-06-30 10:20 ` Michael Ellerman [this message]
2005-06-30 10:20 ` [PATCH 2/12] iseries_veth: Cleanup error and debug messages Michael Ellerman
2005-06-30 10:20 ` [PATCH 4/12] iseries_veth: Remove a FIXME WRT deletion of the ack_timer Michael Ellerman
2005-06-30 10:20 ` [PATCH 8/12] iseries_veth: Replace lock-protected atomic with an ordinary variable Michael Ellerman
2005-06-30 10:20 ` [PATCH 7/12] iseries_veth: Remove redundant message stack lock Michael Ellerman
2005-06-30 10:20 ` [PATCH 3/12] iseries_veth: Make init_connection() & destroy_connection() symmetrical Michael Ellerman
2005-06-30 10:20 ` [PATCH 12/12] iseries_veth: Simplify full-queue handling Michael Ellerman
2005-06-30 10:20 ` [PATCH 11/12] iseries_veth: Add a per-connection ack timer Michael Ellerman
2005-06-30 14:41 ` [RFC/PATCH 0/12] Updates & bug fixes for iseries_veth network driver Jeff Garzik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1120126839.794259.894526862881.qpatch@concordia \
--to=michael@ellerman.id.au \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc64-dev@ozlabs.org \
--cc=netdev@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®