diff options
author | David S. Miller <davem@davemloft.net> | 2014-11-11 03:05:43 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-11 03:05:43 +0100 |
commit | d21385fadabf249afd2e288a1eae1f093ce9fa38 (patch) | |
tree | 5b6407ada4165f5355f1f4e55f07d79f0a1fa417 | |
parent | 8139too: Allow using the largest possible MTU (diff) | |
parent | sunvnet: Add missing rcu_read_unlock() in vnet_start_xmit (diff) | |
download | linux-d21385fadabf249afd2e288a1eae1f093ce9fa38.tar.xz linux-d21385fadabf249afd2e288a1eae1f093ce9fa38.zip |
Merge branch 'sunvnet-next'
Sowmini Varadhan says:
====================
sunvnet: edge-case/race-conditions bug fixes
This patch series contains fixes for race-conditions in sunvnet,
that can encountered when there is a difference in latency between
producer and consumer.
Patch 1 addresses a case when the STOPPED LDC ack from a peer is
processed before vnet_start_xmit can finish updating the dr->prod
state.
Patch 2 fixes the edge-case when outgoing data and incoming
stopped-ack cross each other in flight.
Patch 3 adds a missing rcu_read_unlock(), found by code-inspection.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 5c5fb59adf76..55d66c9a6627 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -559,18 +559,20 @@ static int vnet_ack(struct vnet_port *port, void *msgbuf) return 0; end = pkt->end_idx; - if (unlikely(!idx_is_pending(dr, end))) - return 0; - vp = port->vp; dev = vp->dev; + netif_tx_lock(dev); + if (unlikely(!idx_is_pending(dr, end))) { + netif_tx_unlock(dev); + return 0; + } + /* sync for race conditions with vnet_start_xmit() and tell xmit it * is time to send a trigger. */ - netif_tx_lock(dev); dr->cons = next_idx(end, dr); desc = vio_dring_entry(dr, dr->cons); - if (desc->hdr.state == VIO_DESC_READY && port->start_cons) { + if (desc->hdr.state == VIO_DESC_READY && !port->start_cons) { /* vnet_start_xmit() just populated this dring but missed * sending the "start" LDC message to the consumer. * Send a "start" trigger on its behalf. @@ -979,8 +981,10 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) rcu_read_lock(); port = __tx_port_find(vp, skb); - if (unlikely(!port)) + if (unlikely(!port)) { + rcu_read_unlock(); goto out_dropped; + } if (skb->len > port->rmtu) { unsigned long localmtu = port->rmtu - ETH_HLEN; |