decnet: RCU conversion and get rid of dev_base_lock
While tracking dev_base_lock users, I found decnet used it in dnet_select_source(), but for a wrong purpose: Writers only hold RTNL, not dev_base_lock, so readers must use RCU if they cannot use RTNL. Adds an rcu_head in struct dn_ifaddr and handle proper RCU management. Adds __rcu annotation in dn_route as well. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Acked-by: Steven Whitehouse <swhiteho@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e4a7b93bd5
commit
fc766e4c49
8 changed files with 127 additions and 88 deletions
|
@ -951,7 +951,7 @@ struct net_device {
|
||||||
#endif
|
#endif
|
||||||
void *atalk_ptr; /* AppleTalk link */
|
void *atalk_ptr; /* AppleTalk link */
|
||||||
struct in_device __rcu *ip_ptr; /* IPv4 specific data */
|
struct in_device __rcu *ip_ptr; /* IPv4 specific data */
|
||||||
void *dn_ptr; /* DECnet specific data */
|
struct dn_dev __rcu *dn_ptr; /* DECnet specific data */
|
||||||
struct inet6_dev __rcu *ip6_ptr; /* IPv6 specific data */
|
struct inet6_dev __rcu *ip6_ptr; /* IPv6 specific data */
|
||||||
void *ec_ptr; /* Econet specific data */
|
void *ec_ptr; /* Econet specific data */
|
||||||
void *ax25_ptr; /* AX.25 specific data */
|
void *ax25_ptr; /* AX.25 specific data */
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
struct dn_dev;
|
struct dn_dev;
|
||||||
|
|
||||||
struct dn_ifaddr {
|
struct dn_ifaddr {
|
||||||
struct dn_ifaddr *ifa_next;
|
struct dn_ifaddr __rcu *ifa_next;
|
||||||
struct dn_dev *ifa_dev;
|
struct dn_dev *ifa_dev;
|
||||||
__le16 ifa_local;
|
__le16 ifa_local;
|
||||||
__le16 ifa_address;
|
__le16 ifa_address;
|
||||||
__u8 ifa_flags;
|
__u8 ifa_flags;
|
||||||
__u8 ifa_scope;
|
__u8 ifa_scope;
|
||||||
char ifa_label[IFNAMSIZ];
|
char ifa_label[IFNAMSIZ];
|
||||||
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DN_DEV_S_RU 0 /* Run - working normally */
|
#define DN_DEV_S_RU 0 /* Run - working normally */
|
||||||
|
@ -83,7 +84,7 @@ struct dn_dev_parms {
|
||||||
|
|
||||||
|
|
||||||
struct dn_dev {
|
struct dn_dev {
|
||||||
struct dn_ifaddr *ifa_list;
|
struct dn_ifaddr __rcu *ifa_list;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct dn_dev_parms parms;
|
struct dn_dev_parms parms;
|
||||||
char use_long;
|
char use_long;
|
||||||
|
@ -171,19 +172,27 @@ extern int unregister_dnaddr_notifier(struct notifier_block *nb);
|
||||||
|
|
||||||
static inline int dn_dev_islocal(struct net_device *dev, __le16 addr)
|
static inline int dn_dev_islocal(struct net_device *dev, __le16 addr)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db;
|
||||||
struct dn_ifaddr *ifa;
|
struct dn_ifaddr *ifa;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
dn_db = rcu_dereference(dev->dn_ptr);
|
||||||
if (dn_db == NULL) {
|
if (dn_db == NULL) {
|
||||||
printk(KERN_DEBUG "dn_dev_islocal: Called for non DECnet device\n");
|
printk(KERN_DEBUG "dn_dev_islocal: Called for non DECnet device\n");
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next)
|
for (ifa = rcu_dereference(dn_db->ifa_list);
|
||||||
if ((addr ^ ifa->ifa_local) == 0)
|
ifa != NULL;
|
||||||
return 1;
|
ifa = rcu_dereference(ifa->ifa_next))
|
||||||
|
if ((addr ^ ifa->ifa_local) == 0) {
|
||||||
return 0;
|
res = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _NET_DN_DEV_H */
|
#endif /* _NET_DN_DEV_H */
|
||||||
|
|
|
@ -94,10 +94,10 @@ struct dst_entry {
|
||||||
int __use;
|
int __use;
|
||||||
unsigned long lastuse;
|
unsigned long lastuse;
|
||||||
union {
|
union {
|
||||||
struct dst_entry *next;
|
struct dst_entry *next;
|
||||||
struct rtable __rcu *rt_next;
|
struct rtable __rcu *rt_next;
|
||||||
struct rt6_info *rt6_next;
|
struct rt6_info *rt6_next;
|
||||||
struct dn_route *dn_next;
|
struct dn_route __rcu *dn_next;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1848,7 +1848,7 @@ unsigned dn_mss_from_pmtu(struct net_device *dev, int mtu)
|
||||||
{
|
{
|
||||||
unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER;
|
unsigned mss = 230 - DN_MAX_NSP_DATA_HEADER;
|
||||||
if (dev) {
|
if (dev) {
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
|
||||||
mtu -= LL_RESERVED_SPACE(dev);
|
mtu -= LL_RESERVED_SPACE(dev);
|
||||||
if (dn_db->use_long)
|
if (dn_db->use_long)
|
||||||
mtu -= 21;
|
mtu -= 21;
|
||||||
|
|
|
@ -267,7 +267,7 @@ static int dn_forwarding_proc(ctl_table *table, int write,
|
||||||
if (table->extra1 == NULL)
|
if (table->extra1 == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dn_db = dev->dn_ptr;
|
dn_db = rcu_dereference_raw(dev->dn_ptr);
|
||||||
old = dn_db->parms.forwarding;
|
old = dn_db->parms.forwarding;
|
||||||
|
|
||||||
err = proc_dointvec(table, write, buffer, lenp, ppos);
|
err = proc_dointvec(table, write, buffer, lenp, ppos);
|
||||||
|
@ -332,14 +332,19 @@ static struct dn_ifaddr *dn_dev_alloc_ifa(void)
|
||||||
return ifa;
|
return ifa;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __inline__ void dn_dev_free_ifa(struct dn_ifaddr *ifa)
|
static void dn_dev_free_ifa_rcu(struct rcu_head *head)
|
||||||
{
|
{
|
||||||
kfree(ifa);
|
kfree(container_of(head, struct dn_ifaddr, rcu));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int destroy)
|
static void dn_dev_free_ifa(struct dn_ifaddr *ifa)
|
||||||
{
|
{
|
||||||
struct dn_ifaddr *ifa1 = *ifap;
|
call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy)
|
||||||
|
{
|
||||||
|
struct dn_ifaddr *ifa1 = rtnl_dereference(*ifap);
|
||||||
unsigned char mac_addr[6];
|
unsigned char mac_addr[6];
|
||||||
struct net_device *dev = dn_db->dev;
|
struct net_device *dev = dn_db->dev;
|
||||||
|
|
||||||
|
@ -373,7 +378,9 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
/* Check for duplicates */
|
/* Check for duplicates */
|
||||||
for(ifa1 = dn_db->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
|
for (ifa1 = rtnl_dereference(dn_db->ifa_list);
|
||||||
|
ifa1 != NULL;
|
||||||
|
ifa1 = rtnl_dereference(ifa1->ifa_next)) {
|
||||||
if (ifa1->ifa_local == ifa->ifa_local)
|
if (ifa1->ifa_local == ifa->ifa_local)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
@ -386,7 +393,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
|
||||||
}
|
}
|
||||||
|
|
||||||
ifa->ifa_next = dn_db->ifa_list;
|
ifa->ifa_next = dn_db->ifa_list;
|
||||||
dn_db->ifa_list = ifa;
|
rcu_assign_pointer(dn_db->ifa_list, ifa);
|
||||||
|
|
||||||
dn_ifaddr_notify(RTM_NEWADDR, ifa);
|
dn_ifaddr_notify(RTM_NEWADDR, ifa);
|
||||||
blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
|
blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
|
||||||
|
@ -396,7 +403,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
|
||||||
|
|
||||||
static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
|
static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (dn_db == NULL) {
|
if (dn_db == NULL) {
|
||||||
|
@ -425,7 +432,8 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg)
|
||||||
struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr;
|
struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr;
|
||||||
struct dn_dev *dn_db;
|
struct dn_dev *dn_db;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct dn_ifaddr *ifa = NULL, **ifap = NULL;
|
struct dn_ifaddr *ifa = NULL;
|
||||||
|
struct dn_ifaddr __rcu **ifap = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))
|
if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))
|
||||||
|
@ -454,8 +462,10 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dn_db = dev->dn_ptr) != NULL) {
|
if ((dn_db = rtnl_dereference(dev->dn_ptr)) != NULL) {
|
||||||
for (ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next)
|
for (ifap = &dn_db->ifa_list;
|
||||||
|
(ifa = rtnl_dereference(*ifap)) != NULL;
|
||||||
|
ifap = &ifa->ifa_next)
|
||||||
if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0)
|
if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -558,7 +568,7 @@ static struct dn_dev *dn_dev_by_index(int ifindex)
|
||||||
|
|
||||||
dev = __dev_get_by_index(&init_net, ifindex);
|
dev = __dev_get_by_index(&init_net, ifindex);
|
||||||
if (dev)
|
if (dev)
|
||||||
dn_dev = dev->dn_ptr;
|
dn_dev = rtnl_dereference(dev->dn_ptr);
|
||||||
|
|
||||||
return dn_dev;
|
return dn_dev;
|
||||||
}
|
}
|
||||||
|
@ -576,7 +586,8 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
||||||
struct nlattr *tb[IFA_MAX+1];
|
struct nlattr *tb[IFA_MAX+1];
|
||||||
struct dn_dev *dn_db;
|
struct dn_dev *dn_db;
|
||||||
struct ifaddrmsg *ifm;
|
struct ifaddrmsg *ifm;
|
||||||
struct dn_ifaddr *ifa, **ifap;
|
struct dn_ifaddr *ifa;
|
||||||
|
struct dn_ifaddr __rcu **ifap;
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
if (!net_eq(net, &init_net))
|
if (!net_eq(net, &init_net))
|
||||||
|
@ -592,7 +603,9 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
||||||
goto errout;
|
goto errout;
|
||||||
|
|
||||||
err = -EADDRNOTAVAIL;
|
err = -EADDRNOTAVAIL;
|
||||||
for (ifap = &dn_db->ifa_list; (ifa = *ifap); ifap = &ifa->ifa_next) {
|
for (ifap = &dn_db->ifa_list;
|
||||||
|
(ifa = rtnl_dereference(*ifap)) != NULL;
|
||||||
|
ifap = &ifa->ifa_next) {
|
||||||
if (tb[IFA_LOCAL] &&
|
if (tb[IFA_LOCAL] &&
|
||||||
nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2))
|
nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2))
|
||||||
continue;
|
continue;
|
||||||
|
@ -632,7 +645,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
||||||
if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL)
|
if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if ((dn_db = dev->dn_ptr) == NULL) {
|
if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) {
|
||||||
dn_db = dn_dev_create(dev, &err);
|
dn_db = dn_dev_create(dev, &err);
|
||||||
if (!dn_db)
|
if (!dn_db)
|
||||||
return err;
|
return err;
|
||||||
|
@ -748,11 +761,11 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
skip_naddr = 0;
|
skip_naddr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dn_db = dev->dn_ptr) == NULL)
|
if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL)
|
||||||
goto cont;
|
goto cont;
|
||||||
|
|
||||||
for (ifa = dn_db->ifa_list, dn_idx = 0; ifa;
|
for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
|
||||||
ifa = ifa->ifa_next, dn_idx++) {
|
ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) {
|
||||||
if (dn_idx < skip_naddr)
|
if (dn_idx < skip_naddr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -773,21 +786,22 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
|
|
||||||
static int dn_dev_get_first(struct net_device *dev, __le16 *addr)
|
static int dn_dev_get_first(struct net_device *dev, __le16 *addr)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
|
struct dn_dev *dn_db;
|
||||||
struct dn_ifaddr *ifa;
|
struct dn_ifaddr *ifa;
|
||||||
int rv = -ENODEV;
|
int rv = -ENODEV;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
dn_db = rcu_dereference(dev->dn_ptr);
|
||||||
if (dn_db == NULL)
|
if (dn_db == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
rtnl_lock();
|
ifa = rcu_dereference(dn_db->ifa_list);
|
||||||
ifa = dn_db->ifa_list;
|
|
||||||
if (ifa != NULL) {
|
if (ifa != NULL) {
|
||||||
*addr = ifa->ifa_local;
|
*addr = ifa->ifa_local;
|
||||||
rv = 0;
|
rv = 0;
|
||||||
}
|
}
|
||||||
rtnl_unlock();
|
|
||||||
out:
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,7 +837,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
|
||||||
struct endnode_hello_message *msg;
|
struct endnode_hello_message *msg;
|
||||||
struct sk_buff *skb = NULL;
|
struct sk_buff *skb = NULL;
|
||||||
__le16 *pktlen;
|
__le16 *pktlen;
|
||||||
struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
|
||||||
|
|
||||||
if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
|
if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -889,7 +903,7 @@ static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn
|
||||||
static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
|
static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
|
||||||
struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
|
struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -960,7 +974,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
|
||||||
|
|
||||||
static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
|
static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
|
||||||
|
|
||||||
if (dn_db->parms.forwarding == 0)
|
if (dn_db->parms.forwarding == 0)
|
||||||
dn_send_endnode_hello(dev, ifa);
|
dn_send_endnode_hello(dev, ifa);
|
||||||
|
@ -998,7 +1012,7 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
|
||||||
|
|
||||||
static int dn_eth_up(struct net_device *dev)
|
static int dn_eth_up(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
|
||||||
|
|
||||||
if (dn_db->parms.forwarding == 0)
|
if (dn_db->parms.forwarding == 0)
|
||||||
dev_mc_add(dev, dn_rt_all_end_mcast);
|
dev_mc_add(dev, dn_rt_all_end_mcast);
|
||||||
|
@ -1012,7 +1026,7 @@ static int dn_eth_up(struct net_device *dev)
|
||||||
|
|
||||||
static void dn_eth_down(struct net_device *dev)
|
static void dn_eth_down(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
|
||||||
|
|
||||||
if (dn_db->parms.forwarding == 0)
|
if (dn_db->parms.forwarding == 0)
|
||||||
dev_mc_del(dev, dn_rt_all_end_mcast);
|
dev_mc_del(dev, dn_rt_all_end_mcast);
|
||||||
|
@ -1025,12 +1039,16 @@ static void dn_dev_set_timer(struct net_device *dev);
|
||||||
static void dn_dev_timer_func(unsigned long arg)
|
static void dn_dev_timer_func(unsigned long arg)
|
||||||
{
|
{
|
||||||
struct net_device *dev = (struct net_device *)arg;
|
struct net_device *dev = (struct net_device *)arg;
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db;
|
||||||
struct dn_ifaddr *ifa;
|
struct dn_ifaddr *ifa;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
dn_db = rcu_dereference(dev->dn_ptr);
|
||||||
if (dn_db->t3 <= dn_db->parms.t2) {
|
if (dn_db->t3 <= dn_db->parms.t2) {
|
||||||
if (dn_db->parms.timer3) {
|
if (dn_db->parms.timer3) {
|
||||||
for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) {
|
for (ifa = rcu_dereference(dn_db->ifa_list);
|
||||||
|
ifa;
|
||||||
|
ifa = rcu_dereference(ifa->ifa_next)) {
|
||||||
if (!(ifa->ifa_flags & IFA_F_SECONDARY))
|
if (!(ifa->ifa_flags & IFA_F_SECONDARY))
|
||||||
dn_db->parms.timer3(dev, ifa);
|
dn_db->parms.timer3(dev, ifa);
|
||||||
}
|
}
|
||||||
|
@ -1039,13 +1057,13 @@ static void dn_dev_timer_func(unsigned long arg)
|
||||||
} else {
|
} else {
|
||||||
dn_db->t3 -= dn_db->parms.t2;
|
dn_db->t3 -= dn_db->parms.t2;
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
dn_dev_set_timer(dev);
|
dn_dev_set_timer(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dn_dev_set_timer(struct net_device *dev)
|
static void dn_dev_set_timer(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
|
||||||
|
|
||||||
if (dn_db->parms.t2 > dn_db->parms.t3)
|
if (dn_db->parms.t2 > dn_db->parms.t3)
|
||||||
dn_db->parms.t2 = dn_db->parms.t3;
|
dn_db->parms.t2 = dn_db->parms.t3;
|
||||||
|
@ -1077,8 +1095,8 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
|
memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
|
||||||
smp_wmb();
|
|
||||||
dev->dn_ptr = dn_db;
|
rcu_assign_pointer(dev->dn_ptr, dn_db);
|
||||||
dn_db->dev = dev;
|
dn_db->dev = dev;
|
||||||
init_timer(&dn_db->timer);
|
init_timer(&dn_db->timer);
|
||||||
|
|
||||||
|
@ -1086,7 +1104,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
|
||||||
|
|
||||||
dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
|
dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
|
||||||
if (!dn_db->neigh_parms) {
|
if (!dn_db->neigh_parms) {
|
||||||
dev->dn_ptr = NULL;
|
rcu_assign_pointer(dev->dn_ptr, NULL);
|
||||||
kfree(dn_db);
|
kfree(dn_db);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1125,7 +1143,7 @@ void dn_dev_up(struct net_device *dev)
|
||||||
struct dn_ifaddr *ifa;
|
struct dn_ifaddr *ifa;
|
||||||
__le16 addr = decnet_address;
|
__le16 addr = decnet_address;
|
||||||
int maybe_default = 0;
|
int maybe_default = 0;
|
||||||
struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
|
struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
|
||||||
|
|
||||||
if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
|
if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
|
||||||
return;
|
return;
|
||||||
|
@ -1176,7 +1194,7 @@ void dn_dev_up(struct net_device *dev)
|
||||||
|
|
||||||
static void dn_dev_delete(struct net_device *dev)
|
static void dn_dev_delete(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
|
||||||
|
|
||||||
if (dn_db == NULL)
|
if (dn_db == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -1204,13 +1222,13 @@ static void dn_dev_delete(struct net_device *dev)
|
||||||
|
|
||||||
void dn_dev_down(struct net_device *dev)
|
void dn_dev_down(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
|
||||||
struct dn_ifaddr *ifa;
|
struct dn_ifaddr *ifa;
|
||||||
|
|
||||||
if (dn_db == NULL)
|
if (dn_db == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while((ifa = dn_db->ifa_list) != NULL) {
|
while ((ifa = rtnl_dereference(dn_db->ifa_list)) != NULL) {
|
||||||
dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0);
|
dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0);
|
||||||
dn_dev_free_ifa(ifa);
|
dn_dev_free_ifa(ifa);
|
||||||
}
|
}
|
||||||
|
@ -1270,7 +1288,7 @@ static inline int is_dn_dev(struct net_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
|
static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
|
||||||
__acquires(rcu)
|
__acquires(RCU)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
@ -1313,7 +1331,7 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dn_dev_seq_stop(struct seq_file *seq, void *v)
|
static void dn_dev_seq_stop(struct seq_file *seq, void *v)
|
||||||
__releases(rcu)
|
__releases(RCU)
|
||||||
{
|
{
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
@ -1340,7 +1358,7 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v)
|
||||||
struct net_device *dev = v;
|
struct net_device *dev = v;
|
||||||
char peer_buf[DN_ASCBUF_LEN];
|
char peer_buf[DN_ASCBUF_LEN];
|
||||||
char router_buf[DN_ASCBUF_LEN];
|
char router_buf[DN_ASCBUF_LEN];
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference(dev->dn_ptr);
|
||||||
|
|
||||||
seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu"
|
seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu"
|
||||||
" %04hu %03d %02x %-10s %-7s %-7s\n",
|
" %04hu %03d %02x %-10s %-7s %-7s\n",
|
||||||
|
|
|
@ -610,10 +610,12 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
|
||||||
/* Scan device list */
|
/* Scan device list */
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
for_each_netdev_rcu(&init_net, dev) {
|
for_each_netdev_rcu(&init_net, dev) {
|
||||||
dn_db = dev->dn_ptr;
|
dn_db = rcu_dereference(dev->dn_ptr);
|
||||||
if (dn_db == NULL)
|
if (dn_db == NULL)
|
||||||
continue;
|
continue;
|
||||||
for(ifa2 = dn_db->ifa_list; ifa2; ifa2 = ifa2->ifa_next) {
|
for (ifa2 = rcu_dereference(dn_db->ifa_list);
|
||||||
|
ifa2 != NULL;
|
||||||
|
ifa2 = rcu_dereference(ifa2->ifa_next)) {
|
||||||
if (ifa2->ifa_local == ifa->ifa_local) {
|
if (ifa2->ifa_local == ifa->ifa_local) {
|
||||||
found_it = 1;
|
found_it = 1;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -391,7 +391,7 @@ int dn_neigh_router_hello(struct sk_buff *skb)
|
||||||
write_lock(&neigh->lock);
|
write_lock(&neigh->lock);
|
||||||
|
|
||||||
neigh->used = jiffies;
|
neigh->used = jiffies;
|
||||||
dn_db = (struct dn_dev *)neigh->dev->dn_ptr;
|
dn_db = rcu_dereference(neigh->dev->dn_ptr);
|
||||||
|
|
||||||
if (!(neigh->nud_state & NUD_PERMANENT)) {
|
if (!(neigh->nud_state & NUD_PERMANENT)) {
|
||||||
neigh->updated = jiffies;
|
neigh->updated = jiffies;
|
||||||
|
|
|
@ -93,7 +93,7 @@
|
||||||
|
|
||||||
struct dn_rt_hash_bucket
|
struct dn_rt_hash_bucket
|
||||||
{
|
{
|
||||||
struct dn_route *chain;
|
struct dn_route __rcu *chain;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,15 +157,17 @@ static inline void dnrt_drop(struct dn_route *rt)
|
||||||
static void dn_dst_check_expire(unsigned long dummy)
|
static void dn_dst_check_expire(unsigned long dummy)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct dn_route *rt, **rtp;
|
struct dn_route *rt;
|
||||||
|
struct dn_route __rcu **rtp;
|
||||||
unsigned long now = jiffies;
|
unsigned long now = jiffies;
|
||||||
unsigned long expire = 120 * HZ;
|
unsigned long expire = 120 * HZ;
|
||||||
|
|
||||||
for(i = 0; i <= dn_rt_hash_mask; i++) {
|
for (i = 0; i <= dn_rt_hash_mask; i++) {
|
||||||
rtp = &dn_rt_hash_table[i].chain;
|
rtp = &dn_rt_hash_table[i].chain;
|
||||||
|
|
||||||
spin_lock(&dn_rt_hash_table[i].lock);
|
spin_lock(&dn_rt_hash_table[i].lock);
|
||||||
while((rt=*rtp) != NULL) {
|
while ((rt = rcu_dereference_protected(*rtp,
|
||||||
|
lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) {
|
||||||
if (atomic_read(&rt->dst.__refcnt) ||
|
if (atomic_read(&rt->dst.__refcnt) ||
|
||||||
(now - rt->dst.lastuse) < expire) {
|
(now - rt->dst.lastuse) < expire) {
|
||||||
rtp = &rt->dst.dn_next;
|
rtp = &rt->dst.dn_next;
|
||||||
|
@ -186,17 +188,19 @@ static void dn_dst_check_expire(unsigned long dummy)
|
||||||
|
|
||||||
static int dn_dst_gc(struct dst_ops *ops)
|
static int dn_dst_gc(struct dst_ops *ops)
|
||||||
{
|
{
|
||||||
struct dn_route *rt, **rtp;
|
struct dn_route *rt;
|
||||||
|
struct dn_route __rcu **rtp;
|
||||||
int i;
|
int i;
|
||||||
unsigned long now = jiffies;
|
unsigned long now = jiffies;
|
||||||
unsigned long expire = 10 * HZ;
|
unsigned long expire = 10 * HZ;
|
||||||
|
|
||||||
for(i = 0; i <= dn_rt_hash_mask; i++) {
|
for (i = 0; i <= dn_rt_hash_mask; i++) {
|
||||||
|
|
||||||
spin_lock_bh(&dn_rt_hash_table[i].lock);
|
spin_lock_bh(&dn_rt_hash_table[i].lock);
|
||||||
rtp = &dn_rt_hash_table[i].chain;
|
rtp = &dn_rt_hash_table[i].chain;
|
||||||
|
|
||||||
while((rt=*rtp) != NULL) {
|
while ((rt = rcu_dereference_protected(*rtp,
|
||||||
|
lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) {
|
||||||
if (atomic_read(&rt->dst.__refcnt) ||
|
if (atomic_read(&rt->dst.__refcnt) ||
|
||||||
(now - rt->dst.lastuse) < expire) {
|
(now - rt->dst.lastuse) < expire) {
|
||||||
rtp = &rt->dst.dn_next;
|
rtp = &rt->dst.dn_next;
|
||||||
|
@ -227,7 +231,7 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
|
||||||
{
|
{
|
||||||
u32 min_mtu = 230;
|
u32 min_mtu = 230;
|
||||||
struct dn_dev *dn = dst->neighbour ?
|
struct dn_dev *dn = dst->neighbour ?
|
||||||
(struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL;
|
rcu_dereference_raw(dst->neighbour->dev->dn_ptr) : NULL;
|
||||||
|
|
||||||
if (dn && dn->use_long == 0)
|
if (dn && dn->use_long == 0)
|
||||||
min_mtu -= 6;
|
min_mtu -= 6;
|
||||||
|
@ -277,13 +281,15 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
|
||||||
|
|
||||||
static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp)
|
static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp)
|
||||||
{
|
{
|
||||||
struct dn_route *rth, **rthp;
|
struct dn_route *rth;
|
||||||
|
struct dn_route __rcu **rthp;
|
||||||
unsigned long now = jiffies;
|
unsigned long now = jiffies;
|
||||||
|
|
||||||
rthp = &dn_rt_hash_table[hash].chain;
|
rthp = &dn_rt_hash_table[hash].chain;
|
||||||
|
|
||||||
spin_lock_bh(&dn_rt_hash_table[hash].lock);
|
spin_lock_bh(&dn_rt_hash_table[hash].lock);
|
||||||
while((rth = *rthp) != NULL) {
|
while ((rth = rcu_dereference_protected(*rthp,
|
||||||
|
lockdep_is_held(&dn_rt_hash_table[hash].lock))) != NULL) {
|
||||||
if (compare_keys(&rth->fl, &rt->fl)) {
|
if (compare_keys(&rth->fl, &rt->fl)) {
|
||||||
/* Put it first */
|
/* Put it first */
|
||||||
*rthp = rth->dst.dn_next;
|
*rthp = rth->dst.dn_next;
|
||||||
|
@ -315,15 +321,15 @@ static void dn_run_flush(unsigned long dummy)
|
||||||
int i;
|
int i;
|
||||||
struct dn_route *rt, *next;
|
struct dn_route *rt, *next;
|
||||||
|
|
||||||
for(i = 0; i < dn_rt_hash_mask; i++) {
|
for (i = 0; i < dn_rt_hash_mask; i++) {
|
||||||
spin_lock_bh(&dn_rt_hash_table[i].lock);
|
spin_lock_bh(&dn_rt_hash_table[i].lock);
|
||||||
|
|
||||||
if ((rt = xchg(&dn_rt_hash_table[i].chain, NULL)) == NULL)
|
if ((rt = xchg((struct dn_route **)&dn_rt_hash_table[i].chain, NULL)) == NULL)
|
||||||
goto nothing_to_declare;
|
goto nothing_to_declare;
|
||||||
|
|
||||||
for(; rt; rt=next) {
|
for(; rt; rt = next) {
|
||||||
next = rt->dst.dn_next;
|
next = rcu_dereference_raw(rt->dst.dn_next);
|
||||||
rt->dst.dn_next = NULL;
|
RCU_INIT_POINTER(rt->dst.dn_next, NULL);
|
||||||
dst_free((struct dst_entry *)rt);
|
dst_free((struct dst_entry *)rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,15 +464,16 @@ static int dn_return_long(struct sk_buff *skb)
|
||||||
*/
|
*/
|
||||||
static int dn_route_rx_packet(struct sk_buff *skb)
|
static int dn_route_rx_packet(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
struct dn_skb_cb *cb;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if ((err = dn_route_input(skb)) == 0)
|
if ((err = dn_route_input(skb)) == 0)
|
||||||
return dst_input(skb);
|
return dst_input(skb);
|
||||||
|
|
||||||
|
cb = DN_SKB_CB(skb);
|
||||||
if (decnet_debug_level & 4) {
|
if (decnet_debug_level & 4) {
|
||||||
char *devname = skb->dev ? skb->dev->name : "???";
|
char *devname = skb->dev ? skb->dev->name : "???";
|
||||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
|
||||||
printk(KERN_DEBUG
|
printk(KERN_DEBUG
|
||||||
"DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n",
|
"DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n",
|
||||||
(int)cb->rt_flags, devname, skb->len,
|
(int)cb->rt_flags, devname, skb->len,
|
||||||
|
@ -573,7 +580,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
|
||||||
struct dn_skb_cb *cb;
|
struct dn_skb_cb *cb;
|
||||||
unsigned char flags = 0;
|
unsigned char flags = 0;
|
||||||
__u16 len = le16_to_cpu(*(__le16 *)skb->data);
|
__u16 len = le16_to_cpu(*(__le16 *)skb->data);
|
||||||
struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr;
|
struct dn_dev *dn = rcu_dereference(dev->dn_ptr);
|
||||||
unsigned char padlen = 0;
|
unsigned char padlen = 0;
|
||||||
|
|
||||||
if (!net_eq(dev_net(dev), &init_net))
|
if (!net_eq(dev_net(dev), &init_net))
|
||||||
|
@ -728,7 +735,7 @@ static int dn_forward(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
struct dn_skb_cb *cb = DN_SKB_CB(skb);
|
||||||
struct dst_entry *dst = skb_dst(skb);
|
struct dst_entry *dst = skb_dst(skb);
|
||||||
struct dn_dev *dn_db = dst->dev->dn_ptr;
|
struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr);
|
||||||
struct dn_route *rt;
|
struct dn_route *rt;
|
||||||
struct neighbour *neigh = dst->neighbour;
|
struct neighbour *neigh = dst->neighbour;
|
||||||
int header_len;
|
int header_len;
|
||||||
|
@ -835,13 +842,16 @@ static inline int dn_match_addr(__le16 addr1, __le16 addr2)
|
||||||
static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope)
|
static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope)
|
||||||
{
|
{
|
||||||
__le16 saddr = 0;
|
__le16 saddr = 0;
|
||||||
struct dn_dev *dn_db = dev->dn_ptr;
|
struct dn_dev *dn_db;
|
||||||
struct dn_ifaddr *ifa;
|
struct dn_ifaddr *ifa;
|
||||||
int best_match = 0;
|
int best_match = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
read_lock(&dev_base_lock);
|
rcu_read_lock();
|
||||||
for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) {
|
dn_db = rcu_dereference(dev->dn_ptr);
|
||||||
|
for (ifa = rcu_dereference(dn_db->ifa_list);
|
||||||
|
ifa != NULL;
|
||||||
|
ifa = rcu_dereference(ifa->ifa_next)) {
|
||||||
if (ifa->ifa_scope > scope)
|
if (ifa->ifa_scope > scope)
|
||||||
continue;
|
continue;
|
||||||
if (!daddr) {
|
if (!daddr) {
|
||||||
|
@ -854,7 +864,7 @@ static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int
|
||||||
if (best_match == 0)
|
if (best_match == 0)
|
||||||
saddr = ifa->ifa_local;
|
saddr = ifa->ifa_local;
|
||||||
}
|
}
|
||||||
read_unlock(&dev_base_lock);
|
rcu_read_unlock();
|
||||||
|
|
||||||
return saddr;
|
return saddr;
|
||||||
}
|
}
|
||||||
|
@ -1020,7 +1030,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
if (dev_out == NULL)
|
if (dev_out == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
dn_db = dev_out->dn_ptr;
|
dn_db = rcu_dereference_raw(dev_out->dn_ptr);
|
||||||
/* Possible improvement - check all devices for local addr */
|
/* Possible improvement - check all devices for local addr */
|
||||||
if (dn_dev_islocal(dev_out, fl.fld_dst)) {
|
if (dn_dev_islocal(dev_out, fl.fld_dst)) {
|
||||||
dev_put(dev_out);
|
dev_put(dev_out);
|
||||||
|
@ -1233,7 +1243,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
|
||||||
|
|
||||||
dev_hold(in_dev);
|
dev_hold(in_dev);
|
||||||
|
|
||||||
if ((dn_db = in_dev->dn_ptr) == NULL)
|
if ((dn_db = rcu_dereference(in_dev->dn_ptr)) == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Zero source addresses are not allowed */
|
/* Zero source addresses are not allowed */
|
||||||
|
@ -1677,15 +1687,15 @@ static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_rou
|
||||||
{
|
{
|
||||||
struct dn_rt_cache_iter_state *s = seq->private;
|
struct dn_rt_cache_iter_state *s = seq->private;
|
||||||
|
|
||||||
rt = rt->dst.dn_next;
|
rt = rcu_dereference_bh(rt->dst.dn_next);
|
||||||
while(!rt) {
|
while (!rt) {
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock_bh();
|
||||||
if (--s->bucket < 0)
|
if (--s->bucket < 0)
|
||||||
break;
|
break;
|
||||||
rcu_read_lock_bh();
|
rcu_read_lock_bh();
|
||||||
rt = dn_rt_hash_table[s->bucket].chain;
|
rt = rcu_dereference_bh(dn_rt_hash_table[s->bucket].chain);
|
||||||
}
|
}
|
||||||
return rcu_dereference_bh(rt);
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
|
static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
|
||||||
|
|
Loading…
Add table
Reference in a new issue