diff options
author | Ed Cashin <ecashin@coraid.com> | 2012-10-04 20:16:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 14:05:25 -0400 |
commit | eb086ec59667df5b07d58176e21a5f523ead1d66 (patch) | |
tree | 85c0fa90b4791659f128518115ca0df4ece88586 /drivers/block | |
parent | 69cf2d85de773d998798e47e3335b85e5645d157 (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')
-rw-r--r-- | drivers/block/aoe/aoe.h | 2 | ||||
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 4 | ||||
-rw-r--r-- | drivers/block/aoe/aoenet.c | 37 |
3 files changed, 40 insertions, 3 deletions
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 8c4f6d942e05..d0087de1780e 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h | |||
@@ -210,6 +210,8 @@ struct sk_buff *aoecmd_ata_id(struct aoedev *); | |||
210 | void aoe_freetframe(struct frame *); | 210 | void aoe_freetframe(struct frame *); |
211 | void aoe_flush_iocq(void); | 211 | void aoe_flush_iocq(void); |
212 | void aoe_end_request(struct aoedev *, struct request *, int); | 212 | void aoe_end_request(struct aoedev *, struct request *, int); |
213 | int aoe_ktstart(struct ktstate *k); | ||
214 | void aoe_ktstop(struct ktstate *k); | ||
213 | 215 | ||
214 | int aoedev_init(void); | 216 | int aoedev_init(void); |
215 | void aoedev_exit(void); | 217 | void aoedev_exit(void); |
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 5928a08c1f3f..a1c5e8aa08c0 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c | |||
@@ -1110,14 +1110,14 @@ kthread(void *vp) | |||
1110 | return 0; | 1110 | return 0; |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | static void | 1113 | void |
1114 | aoe_ktstop(struct ktstate *k) | 1114 | aoe_ktstop(struct ktstate *k) |
1115 | { | 1115 | { |
1116 | kthread_stop(k->task); | 1116 | kthread_stop(k->task); |
1117 | wait_for_completion(&k->rendez); | 1117 | wait_for_completion(&k->rendez); |
1118 | } | 1118 | } |
1119 | 1119 | ||
1120 | static int | 1120 | int |
1121 | aoe_ktstart(struct ktstate *k) | 1121 | aoe_ktstart(struct ktstate *k) |
1122 | { | 1122 | { |
1123 | struct task_struct *task; | 1123 | struct task_struct *task; |
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]; | |||
33 | module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600); | 33 | module_param_string(aoe_iflist, aoe_iflist, IFLISTSZ, 0600); |
34 | MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\""); | 34 | MODULE_PARM_DESC(aoe_iflist, "aoe_iflist=\"dev1 [dev2 ...]\""); |
35 | 35 | ||
36 | static wait_queue_head_t txwq; | ||
37 | static struct ktstate kts; | ||
38 | |||
36 | #ifndef MODULE | 39 | #ifndef MODULE |
37 | static int __init aoe_iflist_setup(char *str) | 40 | static 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 | ||
50 | static spinlock_t txlock; | ||
51 | static struct sk_buff_head skbtxq; | ||
52 | |||
53 | /* enters with txlock held */ | ||
54 | static int | ||
55 | tx(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 | |||
47 | int | 67 | int |
48 | is_aoe_netif(struct net_device *ifp) | 68 | is_aoe_netif(struct net_device *ifp) |
49 | { | 69 | { |
@@ -88,10 +108,14 @@ void | |||
88 | aoenet_xmit(struct sk_buff_head *queue) | 108 | aoenet_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 = { | |||
169 | int __init | 193 | int __init |
170 | aoenet_init(void) | 194 | aoenet_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) | |||
176 | void | 209 | void |
177 | aoenet_exit(void) | 210 | aoenet_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 | ||