diff options
| author | David S. Miller <davem@davemloft.net> | 2014-11-10 21:05:43 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-11-10 21:05:43 -0500 |
| commit | d21385fadabf249afd2e288a1eae1f093ce9fa38 (patch) | |
| tree | 5b6407ada4165f5355f1f4e55f07d79f0a1fa417 | |
| parent | 6f6e741f6de5ed5eedf7d19c9c0f8c73eaa0da7d (diff) | |
| parent | df20286ab1e36eaaf1f6c7e5e2c56bea1ffc26c0 (diff) | |
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) | |||
| 559 | return 0; | 559 | return 0; |
| 560 | 560 | ||
| 561 | end = pkt->end_idx; | 561 | end = pkt->end_idx; |
| 562 | if (unlikely(!idx_is_pending(dr, end))) | ||
| 563 | return 0; | ||
| 564 | |||
| 565 | vp = port->vp; | 562 | vp = port->vp; |
| 566 | dev = vp->dev; | 563 | dev = vp->dev; |
| 564 | netif_tx_lock(dev); | ||
| 565 | if (unlikely(!idx_is_pending(dr, end))) { | ||
| 566 | netif_tx_unlock(dev); | ||
| 567 | return 0; | ||
| 568 | } | ||
| 569 | |||
| 567 | /* sync for race conditions with vnet_start_xmit() and tell xmit it | 570 | /* sync for race conditions with vnet_start_xmit() and tell xmit it |
| 568 | * is time to send a trigger. | 571 | * is time to send a trigger. |
| 569 | */ | 572 | */ |
| 570 | netif_tx_lock(dev); | ||
| 571 | dr->cons = next_idx(end, dr); | 573 | dr->cons = next_idx(end, dr); |
| 572 | desc = vio_dring_entry(dr, dr->cons); | 574 | desc = vio_dring_entry(dr, dr->cons); |
| 573 | if (desc->hdr.state == VIO_DESC_READY && port->start_cons) { | 575 | if (desc->hdr.state == VIO_DESC_READY && !port->start_cons) { |
| 574 | /* vnet_start_xmit() just populated this dring but missed | 576 | /* vnet_start_xmit() just populated this dring but missed |
| 575 | * sending the "start" LDC message to the consumer. | 577 | * sending the "start" LDC message to the consumer. |
| 576 | * Send a "start" trigger on its behalf. | 578 | * Send a "start" trigger on its behalf. |
| @@ -979,8 +981,10 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 979 | 981 | ||
| 980 | rcu_read_lock(); | 982 | rcu_read_lock(); |
| 981 | port = __tx_port_find(vp, skb); | 983 | port = __tx_port_find(vp, skb); |
| 982 | if (unlikely(!port)) | 984 | if (unlikely(!port)) { |
| 985 | rcu_read_unlock(); | ||
| 983 | goto out_dropped; | 986 | goto out_dropped; |
| 987 | } | ||
| 984 | 988 | ||
| 985 | if (skb->len > port->rmtu) { | 989 | if (skb->len > port->rmtu) { |
| 986 | unsigned long localmtu = port->rmtu - ETH_HLEN; | 990 | unsigned long localmtu = port->rmtu - ETH_HLEN; |
