Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wireless extensions: make netns aware

This makes wireless extensions netns aware. The
tasklet sending the events is converted to a work
struct so that we can rtnl_lock() in it.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Johannes Berg and committed by
David S. Miller
b333b3d2 97fd5bc7

+32 -32
+3
include/net/net_namespace.h
··· 80 80 #ifdef CONFIG_XFRM 81 81 struct netns_xfrm xfrm; 82 82 #endif 83 + #ifdef CONFIG_WIRELESS_EXT 84 + struct sk_buff_head wext_nlevents; 85 + #endif 83 86 struct net_generic *gen; 84 87 }; 85 88
+29 -32
net/wireless/wext.c
··· 1257 1257 } 1258 1258 #endif 1259 1259 1260 - /************************* EVENT PROCESSING *************************/ 1261 - /* 1262 - * Process events generated by the wireless layer or the driver. 1263 - * Most often, the event will be propagated through rtnetlink 1264 - */ 1260 + static int __net_init wext_pernet_init(struct net *net) 1261 + { 1262 + skb_queue_head_init(&net->wext_nlevents); 1263 + return 0; 1264 + } 1265 1265 1266 - /* ---------------------------------------------------------------- */ 1267 - /* 1268 - * Locking... 1269 - * ---------- 1270 - * 1271 - * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing 1272 - * the locking issue in here and implementing this code ! 1273 - * 1274 - * The issue : wireless_send_event() is often called in interrupt context, 1275 - * while the Netlink layer can never be called in interrupt context. 1276 - * The fully formed RtNetlink events are queued, and then a tasklet is run 1277 - * to feed those to Netlink. 1278 - * The skb_queue is interrupt safe, and its lock is not held while calling 1279 - * Netlink, so there is no possibility of dealock. 1280 - * Jean II 1281 - */ 1266 + static void __net_exit wext_pernet_exit(struct net *net) 1267 + { 1268 + skb_queue_purge(&net->wext_nlevents); 1269 + } 1282 1270 1283 - static struct sk_buff_head wireless_nlevent_queue; 1271 + static struct pernet_operations wext_pernet_ops = { 1272 + .init = wext_pernet_init, 1273 + .exit = wext_pernet_exit, 1274 + }; 1284 1275 1285 1276 static int __init wireless_nlevent_init(void) 1286 1277 { 1287 - skb_queue_head_init(&wireless_nlevent_queue); 1278 + return register_pernet_subsys(&wext_pernet_ops); 1288 1279 return 0; 1289 1280 } 1290 1281 1291 1282 subsys_initcall(wireless_nlevent_init); 1292 1283 1293 - static void wireless_nlevent_process(unsigned long data) 1284 + /* Process events generated by the wireless layer or the driver. */ 1285 + static void wireless_nlevent_process(struct work_struct *work) 1294 1286 { 1295 1287 struct sk_buff *skb; 1288 + struct net *net; 1296 1289 1297 - while ((skb = skb_dequeue(&wireless_nlevent_queue))) 1298 - rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 1290 + rtnl_lock(); 1291 + 1292 + for_each_net(net) { 1293 + while ((skb = skb_dequeue(&net->wext_nlevents))) 1294 + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, 1295 + GFP_KERNEL); 1296 + } 1297 + 1298 + rtnl_unlock(); 1299 1299 } 1300 1300 1301 - static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); 1301 + static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); 1302 1302 1303 1303 /* ---------------------------------------------------------------- */ 1304 1304 /* ··· 1348 1348 struct sk_buff *skb; 1349 1349 int err; 1350 1350 1351 - if (!net_eq(dev_net(dev), &init_net)) 1352 - return; 1353 - 1354 1351 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1355 1352 if (!skb) 1356 1353 return; ··· 1360 1363 } 1361 1364 1362 1365 NETLINK_CB(skb).dst_group = RTNLGRP_LINK; 1363 - skb_queue_tail(&wireless_nlevent_queue, skb); 1364 - tasklet_schedule(&wireless_nlevent_tasklet); 1366 + skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); 1367 + schedule_work(&wireless_nlevent_work); 1365 1368 } 1366 1369 1367 1370 /* ---------------------------------------------------------------- */