diff options
author | Rémi Denis-Courmont <remi.denis-courmont@nokia.com> | 2009-11-13 00:01:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-13 23:47:02 -0500 |
commit | 888801357f240daee5d310327867d834bc05183b (patch) | |
tree | 80ac945f3dfac07f6f8368f5a024511814b8d1e0 /net/phonet | |
parent | 7ed0132f232b11ae58b6d868e8d7ada9dfa066d7 (diff) |
Phonet: convert routing table to RCU
Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/phonet')
-rw-r--r-- | net/phonet/pn_dev.c | 59 |
1 files changed, 34 insertions, 25 deletions
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 6d64fda1afc9..3287f8f0b5cc 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <net/phonet/pn_dev.h> | 34 | #include <net/phonet/pn_dev.h> |
35 | 35 | ||
36 | struct phonet_routes { | 36 | struct phonet_routes { |
37 | spinlock_t lock; | 37 | struct mutex lock; |
38 | struct net_device *table[64]; | 38 | struct net_device *table[64]; |
39 | }; | 39 | }; |
40 | 40 | ||
@@ -248,17 +248,22 @@ static void phonet_route_autodel(struct net_device *dev) | |||
248 | 248 | ||
249 | /* Remove left-over Phonet routes */ | 249 | /* Remove left-over Phonet routes */ |
250 | bitmap_zero(deleted, 64); | 250 | bitmap_zero(deleted, 64); |
251 | spin_lock_bh(&pnn->routes.lock); | 251 | mutex_lock(&pnn->routes.lock); |
252 | for (i = 0; i < 64; i++) | 252 | for (i = 0; i < 64; i++) |
253 | if (dev == pnn->routes.table[i]) { | 253 | if (dev == pnn->routes.table[i]) { |
254 | rcu_assign_pointer(pnn->routes.table[i], NULL); | ||
254 | set_bit(i, deleted); | 255 | set_bit(i, deleted); |
255 | pnn->routes.table[i] = NULL; | ||
256 | dev_put(dev); | ||
257 | } | 256 | } |
258 | spin_unlock_bh(&pnn->routes.lock); | 257 | mutex_unlock(&pnn->routes.lock); |
258 | |||
259 | if (bitmap_empty(deleted, 64)) | ||
260 | return; /* short-circuit RCU */ | ||
261 | synchronize_rcu(); | ||
259 | for (i = find_first_bit(deleted, 64); i < 64; | 262 | for (i = find_first_bit(deleted, 64); i < 64; |
260 | i = find_next_bit(deleted, 64, i + 1)) | 263 | i = find_next_bit(deleted, 64, i + 1)) { |
261 | rtm_phonet_notify(RTM_DELROUTE, dev, i); | 264 | rtm_phonet_notify(RTM_DELROUTE, dev, i); |
265 | dev_put(dev); | ||
266 | } | ||
262 | } | 267 | } |
263 | 268 | ||
264 | /* notify Phonet of device events */ | 269 | /* notify Phonet of device events */ |
@@ -300,7 +305,7 @@ static int phonet_init_net(struct net *net) | |||
300 | 305 | ||
301 | INIT_LIST_HEAD(&pnn->pndevs.list); | 306 | INIT_LIST_HEAD(&pnn->pndevs.list); |
302 | spin_lock_init(&pnn->pndevs.lock); | 307 | spin_lock_init(&pnn->pndevs.lock); |
303 | spin_lock_init(&pnn->routes.lock); | 308 | mutex_init(&pnn->routes.lock); |
304 | net_assign_generic(net, phonet_net_id, pnn); | 309 | net_assign_generic(net, phonet_net_id, pnn); |
305 | return 0; | 310 | return 0; |
306 | } | 311 | } |
@@ -361,13 +366,13 @@ int phonet_route_add(struct net_device *dev, u8 daddr) | |||
361 | int err = -EEXIST; | 366 | int err = -EEXIST; |
362 | 367 | ||
363 | daddr = daddr >> 2; | 368 | daddr = daddr >> 2; |
364 | spin_lock_bh(&routes->lock); | 369 | mutex_lock(&routes->lock); |
365 | if (routes->table[daddr] == NULL) { | 370 | if (routes->table[daddr] == NULL) { |
366 | routes->table[daddr] = dev; | 371 | rcu_assign_pointer(routes->table[daddr], dev); |
367 | dev_hold(dev); | 372 | dev_hold(dev); |
368 | err = 0; | 373 | err = 0; |
369 | } | 374 | } |
370 | spin_unlock_bh(&routes->lock); | 375 | mutex_unlock(&routes->lock); |
371 | return err; | 376 | return err; |
372 | } | 377 | } |
373 | 378 | ||
@@ -375,17 +380,20 @@ int phonet_route_del(struct net_device *dev, u8 daddr) | |||
375 | { | 380 | { |
376 | struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id); | 381 | struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id); |
377 | struct phonet_routes *routes = &pnn->routes; | 382 | struct phonet_routes *routes = &pnn->routes; |
378 | int err = -ENOENT; | ||
379 | 383 | ||
380 | daddr = daddr >> 2; | 384 | daddr = daddr >> 2; |
381 | spin_lock_bh(&routes->lock); | 385 | mutex_lock(&routes->lock); |
382 | if (dev == routes->table[daddr]) { | 386 | if (dev == routes->table[daddr]) |
383 | routes->table[daddr] = NULL; | 387 | rcu_assign_pointer(routes->table[daddr], NULL); |
384 | dev_put(dev); | 388 | else |
385 | err = 0; | 389 | dev = NULL; |
386 | } | 390 | mutex_unlock(&routes->lock); |
387 | spin_unlock_bh(&routes->lock); | 391 | |
388 | return err; | 392 | if (!dev) |
393 | return -ENOENT; | ||
394 | synchronize_rcu(); | ||
395 | dev_put(dev); | ||
396 | return 0; | ||
389 | } | 397 | } |
390 | 398 | ||
391 | struct net_device *phonet_route_get(struct net *net, u8 daddr) | 399 | struct net_device *phonet_route_get(struct net *net, u8 daddr) |
@@ -397,9 +405,9 @@ struct net_device *phonet_route_get(struct net *net, u8 daddr) | |||
397 | ASSERT_RTNL(); /* no need to hold the device */ | 405 | ASSERT_RTNL(); /* no need to hold the device */ |
398 | 406 | ||
399 | daddr >>= 2; | 407 | daddr >>= 2; |
400 | spin_lock_bh(&routes->lock); | 408 | rcu_read_lock(); |
401 | dev = routes->table[daddr]; | 409 | dev = rcu_dereference(routes->table[daddr]); |
402 | spin_unlock_bh(&routes->lock); | 410 | rcu_read_unlock(); |
403 | return dev; | 411 | return dev; |
404 | } | 412 | } |
405 | 413 | ||
@@ -409,11 +417,12 @@ struct net_device *phonet_route_output(struct net *net, u8 daddr) | |||
409 | struct phonet_routes *routes = &pnn->routes; | 417 | struct phonet_routes *routes = &pnn->routes; |
410 | struct net_device *dev; | 418 | struct net_device *dev; |
411 | 419 | ||
412 | spin_lock_bh(&routes->lock); | 420 | daddr >>= 2; |
413 | dev = routes->table[daddr >> 2]; | 421 | rcu_read_lock(); |
422 | dev = rcu_dereference(routes->table[daddr]); | ||
414 | if (dev) | 423 | if (dev) |
415 | dev_hold(dev); | 424 | dev_hold(dev); |
416 | spin_unlock_bh(&routes->lock); | 425 | rcu_read_unlock(); |
417 | 426 | ||
418 | if (!dev) | 427 | if (!dev) |
419 | dev = phonet_device_get(net); /* Default route */ | 428 | dev = phonet_device_get(net); /* Default route */ |