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>
This commit is contained in:
Rémi Denis-Courmont 2009-11-13 05:01:19 +00:00 committed by David S. Miller
parent 7ed0132f23
commit 888801357f

View File

@ -34,7 +34,7 @@
#include <net/phonet/pn_dev.h> #include <net/phonet/pn_dev.h>
struct phonet_routes { struct phonet_routes {
spinlock_t lock; struct mutex lock;
struct net_device *table[64]; struct net_device *table[64];
}; };
@ -248,17 +248,22 @@ static void phonet_route_autodel(struct net_device *dev)
/* Remove left-over Phonet routes */ /* Remove left-over Phonet routes */
bitmap_zero(deleted, 64); bitmap_zero(deleted, 64);
spin_lock_bh(&pnn->routes.lock); mutex_lock(&pnn->routes.lock);
for (i = 0; i < 64; i++) for (i = 0; i < 64; i++)
if (dev == pnn->routes.table[i]) { if (dev == pnn->routes.table[i]) {
rcu_assign_pointer(pnn->routes.table[i], NULL);
set_bit(i, deleted); set_bit(i, deleted);
pnn->routes.table[i] = NULL;
dev_put(dev);
} }
spin_unlock_bh(&pnn->routes.lock); mutex_unlock(&pnn->routes.lock);
if (bitmap_empty(deleted, 64))
return; /* short-circuit RCU */
synchronize_rcu();
for (i = find_first_bit(deleted, 64); i < 64; for (i = find_first_bit(deleted, 64); i < 64;
i = find_next_bit(deleted, 64, i + 1)) i = find_next_bit(deleted, 64, i + 1)) {
rtm_phonet_notify(RTM_DELROUTE, dev, i); rtm_phonet_notify(RTM_DELROUTE, dev, i);
dev_put(dev);
}
} }
/* notify Phonet of device events */ /* notify Phonet of device events */
@ -300,7 +305,7 @@ static int phonet_init_net(struct net *net)
INIT_LIST_HEAD(&pnn->pndevs.list); INIT_LIST_HEAD(&pnn->pndevs.list);
spin_lock_init(&pnn->pndevs.lock); spin_lock_init(&pnn->pndevs.lock);
spin_lock_init(&pnn->routes.lock); mutex_init(&pnn->routes.lock);
net_assign_generic(net, phonet_net_id, pnn); net_assign_generic(net, phonet_net_id, pnn);
return 0; return 0;
} }
@ -361,13 +366,13 @@ int phonet_route_add(struct net_device *dev, u8 daddr)
int err = -EEXIST; int err = -EEXIST;
daddr = daddr >> 2; daddr = daddr >> 2;
spin_lock_bh(&routes->lock); mutex_lock(&routes->lock);
if (routes->table[daddr] == NULL) { if (routes->table[daddr] == NULL) {
routes->table[daddr] = dev; rcu_assign_pointer(routes->table[daddr], dev);
dev_hold(dev); dev_hold(dev);
err = 0; err = 0;
} }
spin_unlock_bh(&routes->lock); mutex_unlock(&routes->lock);
return err; return err;
} }
@ -375,17 +380,20 @@ int phonet_route_del(struct net_device *dev, u8 daddr)
{ {
struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id); struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
struct phonet_routes *routes = &pnn->routes; struct phonet_routes *routes = &pnn->routes;
int err = -ENOENT;
daddr = daddr >> 2; daddr = daddr >> 2;
spin_lock_bh(&routes->lock); mutex_lock(&routes->lock);
if (dev == routes->table[daddr]) { if (dev == routes->table[daddr])
routes->table[daddr] = NULL; rcu_assign_pointer(routes->table[daddr], NULL);
dev_put(dev); else
err = 0; dev = NULL;
} mutex_unlock(&routes->lock);
spin_unlock_bh(&routes->lock);
return err; if (!dev)
return -ENOENT;
synchronize_rcu();
dev_put(dev);
return 0;
} }
struct net_device *phonet_route_get(struct net *net, u8 daddr) 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)
ASSERT_RTNL(); /* no need to hold the device */ ASSERT_RTNL(); /* no need to hold the device */
daddr >>= 2; daddr >>= 2;
spin_lock_bh(&routes->lock); rcu_read_lock();
dev = routes->table[daddr]; dev = rcu_dereference(routes->table[daddr]);
spin_unlock_bh(&routes->lock); rcu_read_unlock();
return dev; return dev;
} }
@ -409,11 +417,12 @@ struct net_device *phonet_route_output(struct net *net, u8 daddr)
struct phonet_routes *routes = &pnn->routes; struct phonet_routes *routes = &pnn->routes;
struct net_device *dev; struct net_device *dev;
spin_lock_bh(&routes->lock); daddr >>= 2;
dev = routes->table[daddr >> 2]; rcu_read_lock();
dev = rcu_dereference(routes->table[daddr]);
if (dev) if (dev)
dev_hold(dev); dev_hold(dev);
spin_unlock_bh(&routes->lock); rcu_read_unlock();
if (!dev) if (!dev)
dev = phonet_device_get(net); /* Default route */ dev = phonet_device_get(net); /* Default route */