aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/aoe/aoenet.c
diff options
context:
space:
mode:
authorEd Cashin <ecashin@coraid.com>2012-10-04 20:16:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-05 14:05:25 -0400
commiteb086ec59667df5b07d58176e21a5f523ead1d66 (patch)
tree85c0fa90b4791659f128518115ca0df4ece88586 /drivers/block/aoe/aoenet.c
parent69cf2d85de773d998798e47e3335b85e5645d157 (diff)
aoe: use a kernel thread for transmissions
The dev_queue_xmit function needs to have interrupts enabled, so the most simple way to get the locking right but still fulfill that requirement is to use a process that can call dev_queue_xmit serially over queued transmissions. Signed-off-by: Ed Cashin <ecashin@coraid.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block/aoe/aoenet.c')
-rw-r--r--drivers/block/aoe/aoenet.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index 000eff2b53a8..5f43710601ab 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -33,6 +33,9 @@ static char aoe_iflist[IFLISTSZ];
33module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600); 33module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600);
34MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\""); 34MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\"");
35 35
36static wait_queue_head_t txwq;
37static struct ktstate kts;
38
36#ifndef MODULE 39#ifndef MODULE
37static int __init aoe_iflist_setup(char *str) 40static int __init aoe_iflist_setup(char *str)
38{ 41{
@@ -44,6 +47,23 @@ static int __init aoe_iflist_setup(char *str)
44__setup("aoe_iflist=", aoe_iflist_setup); 47__setup("aoe_iflist=", aoe_iflist_setup);
45#endif 48#endif
46 49
50static spinlock_t txlock;
51static struct sk_buff_head skbtxq;
52
53/* enters with txlock held */
54static int
55tx(void)
56{
57 struct sk_buff *skb;
58
59 while ((skb = skb_dequeue(&skbtxq))) {
60 spin_unlock_irq(&txlock);
61 dev_queue_xmit(skb);
62 spin_lock_irq(&txlock);
63 }
64 return 0;
65}
66
47int 67int
48is_aoe_netif(struct net_device *ifp) 68is_aoe_netif(struct net_device *ifp)
49{ 69{
@@ -88,10 +108,14 @@ void
88aoenet_xmit(struct sk_buff_head *queue) 108aoenet_xmit(struct sk_buff_head *queue)
89{ 109{
90 struct sk_buff *skb, *tmp; 110 struct sk_buff *skb, *tmp;
111 ulong flags;
91 112
92 skb_queue_walk_safe(queue, skb, tmp) { 113 skb_queue_walk_safe(queue, skb, tmp) {
93 __skb_unlink(skb, queue); 114 __skb_unlink(skb, queue);
94 dev_queue_xmit(skb); 115 spin_lock_irqsave(&txlock, flags);
116 skb_queue_tail(&skbtxq, skb);
117 spin_unlock_irqrestore(&txlock, flags);
118 wake_up(&txwq);
95 } 119 }
96} 120}
97 121
@@ -169,6 +193,15 @@ static struct packet_type aoe_pt __read_mostly = {
169int __init 193int __init
170aoenet_init(void) 194aoenet_init(void)
171{ 195{
196 skb_queue_head_init(&skbtxq);
197 init_waitqueue_head(&txwq);
198 spin_lock_init(&txlock);
199 kts.lock = &txlock;
200 kts.fn = tx;
201 kts.waitq = &txwq;
202 kts.name = "aoe_tx";
203 if (aoe_ktstart(&kts))
204 return -EAGAIN;
172 dev_add_pack(&aoe_pt); 205 dev_add_pack(&aoe_pt);
173 return 0; 206 return 0;
174} 207}
@@ -176,6 +209,8 @@ aoenet_init(void)
176void 209void
177aoenet_exit(void) 210aoenet_exit(void)
178{ 211{
212 aoe_ktstop(&kts);
213 skb_queue_purge(&skbtxq);
179 dev_remove_pack(&aoe_pt); 214 dev_remove_pack(&aoe_pt);
180} 215}
181 216