]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/3a4410c4504e |
2 | # HG changeset 849 patch | |
3 | # User Keir Fraser <keir.fraser@citrix.com> | |
4 | # Date 1238497253 -3600 | |
5 | # Node ID 3a4410c4504ea64f2c1e873df3234938366050ad | |
6 | # Parent ab1d4fbbe4bf93f203e0c4d62c18bd248e4f1d4a | |
7 | Subject: sfc_netfront: Only clear tx_skb when ready for netif_wake_queue | |
8 | (doing otherwise could result in a lost packet) and document use of | |
9 | locks to protect tx_skb | |
10 | References: bnc#489721 | |
11 | Patch-mainline: obsolete | |
12 | ||
13 | Signed-off-by: Kieran Mansley <kmansley@solarflare.com> | |
14 | Acked-by: jbeulich@novell.com | |
15 | ||
16 | --- sle11-2009-04-09.orig/drivers/xen/sfc_netfront/accel.h 2009-04-09 14:23:18.000000000 +0200 | |
17 | +++ sle11-2009-04-09/drivers/xen/sfc_netfront/accel.h 2009-04-09 14:41:38.000000000 +0200 | |
18 | @@ -261,8 +261,10 @@ typedef struct netfront_accel_vnic { | |
19 | ||
20 | int poll_enabled; | |
21 | ||
22 | - /** A spare slot for a TX packet. This is treated as an extension | |
23 | - * of the DMA queue. */ | |
24 | + /** A spare slot for a TX packet. This is treated as an | |
25 | + * extension of the DMA queue. Reads require either | |
26 | + * netfront's tx_lock or the vnic tx_lock; writes require both | |
27 | + * locks */ | |
28 | struct sk_buff *tx_skb; | |
29 | ||
30 | /** Keep track of fragments of SSR packets */ | |
31 | --- sle11-2009-04-09.orig/drivers/xen/sfc_netfront/accel_netfront.c 2009-03-30 16:16:28.000000000 +0200 | |
32 | +++ sle11-2009-04-09/drivers/xen/sfc_netfront/accel_netfront.c 2009-04-09 14:42:13.000000000 +0200 | |
33 | @@ -65,7 +65,7 @@ static int netfront_accel_netdev_start_x | |
34 | BUG_ON(vnic->net_dev != net_dev); | |
35 | DPRINTK("%s stopping queue\n", __FUNCTION__); | |
36 | ||
37 | - /* Netfront's lock protects tx_skb */ | |
38 | + /* Need netfront's tx_lock and vnic tx_lock to write tx_skb */ | |
39 | spin_lock_irqsave(&np->tx_lock, flags2); | |
40 | BUG_ON(vnic->tx_skb != NULL); | |
41 | vnic->tx_skb = skb; | |
42 | @@ -183,7 +183,7 @@ static int netfront_accel_check_ready(st | |
43 | ||
44 | BUG_ON(vnic == NULL); | |
45 | ||
46 | - /* This is protected by netfront's lock */ | |
47 | + /* Read of tx_skb is protected by netfront's tx_lock */ | |
48 | return vnic->tx_skb == NULL; | |
49 | } | |
50 | ||
51 | --- sle11-2009-04-09.orig/drivers/xen/sfc_netfront/accel_vi.c 2009-04-09 14:23:18.000000000 +0200 | |
52 | +++ sle11-2009-04-09/drivers/xen/sfc_netfront/accel_vi.c 2009-04-09 14:41:38.000000000 +0200 | |
53 | @@ -980,39 +980,35 @@ static void netfront_accel_vi_not_busy(n | |
54 | { | |
55 | struct netfront_info *np = ((struct netfront_info *) | |
56 | netdev_priv(vnic->net_dev)); | |
57 | - struct sk_buff *skb; | |
58 | int handled; | |
59 | unsigned long flags; | |
60 | - | |
61 | + | |
62 | /* | |
63 | - * TODO if we could safely check tx_skb == NULL and return | |
64 | - * early without taking the lock, that would obviously help | |
65 | - * performance | |
66 | + * We hold the vnic tx_lock which is sufficient to exclude | |
67 | + * writes to tx_skb | |
68 | */ | |
69 | ||
70 | - /* Take the netfront lock which protects tx_skb. */ | |
71 | - spin_lock_irqsave(&np->tx_lock, flags); | |
72 | if (vnic->tx_skb != NULL) { | |
73 | DPRINTK("%s trying to send spare buffer\n", __FUNCTION__); | |
74 | ||
75 | - skb = vnic->tx_skb; | |
76 | - vnic->tx_skb = NULL; | |
77 | - | |
78 | - spin_unlock_irqrestore(&np->tx_lock, flags); | |
79 | - | |
80 | - handled = netfront_accel_vi_tx_post(vnic, skb); | |
81 | + handled = netfront_accel_vi_tx_post(vnic, vnic->tx_skb); | |
82 | ||
83 | - spin_lock_irqsave(&np->tx_lock, flags); | |
84 | - | |
85 | if (handled != NETFRONT_ACCEL_STATUS_BUSY) { | |
86 | DPRINTK("%s restarting tx\n", __FUNCTION__); | |
87 | + | |
88 | + /* Need netfront tx_lock and vnic tx_lock to | |
89 | + * write tx_skb */ | |
90 | + spin_lock_irqsave(&np->tx_lock, flags); | |
91 | + | |
92 | + vnic->tx_skb = NULL; | |
93 | + | |
94 | if (netfront_check_queue_ready(vnic->net_dev)) { | |
95 | netif_wake_queue(vnic->net_dev); | |
96 | NETFRONT_ACCEL_STATS_OP | |
97 | (vnic->stats.queue_wakes++); | |
98 | } | |
99 | - } else { | |
100 | - vnic->tx_skb = skb; | |
101 | + spin_unlock_irqrestore(&np->tx_lock, flags); | |
102 | + | |
103 | } | |
104 | ||
105 | /* | |
106 | @@ -1021,7 +1017,6 @@ static void netfront_accel_vi_not_busy(n | |
107 | */ | |
108 | BUG_ON(handled == NETFRONT_ACCEL_STATUS_CANT); | |
109 | } | |
110 | - spin_unlock_irqrestore(&np->tx_lock, flags); | |
111 | } | |
112 | ||
113 |