aboutsummaryrefslogtreecommitdiffstats
path: root/net/decnet
diff options
context:
space:
mode:
authorSteven Whitehouse <steve@chygwyn.com>2006-03-21 01:43:28 -0500
committerDavid S. Miller <davem@davemloft.net>2006-03-21 01:43:28 -0500
commitecba320f2e95c9a0c35011d1ecb1db4419980536 (patch)
treea994a09e48452db4f1b251d5e5b210424c7dbe92 /net/decnet
parentc60992db464bc3c459a6e2d3694fe1ae1a5ec784 (diff)
[DECnet]: Use RCU locking in dn_rules.c
As per Robert Olsson's patch for ipv4, this is the DECnet version to keep the code "in step". It changes the list of rules to use RCU rather than an rwlock. Inspired-by: Robert Olsson <robert.olsson@its.uu.se> Signed-off-by: Steven Whitehouse <steve@chygwyn.com> Signed-off-by: Patrick Caulfield <patrick@tykepenguin.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/decnet')
-rw-r--r--net/decnet/dn_rules.c97
1 files changed, 53 insertions, 44 deletions
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
index f2c299dfe030..446faafe2065 100644
--- a/net/decnet/dn_rules.c
+++ b/net/decnet/dn_rules.c
@@ -27,6 +27,8 @@
27#include <linux/timer.h> 27#include <linux/timer.h>
28#include <linux/spinlock.h> 28#include <linux/spinlock.h>
29#include <linux/in_route.h> 29#include <linux/in_route.h>
30#include <linux/list.h>
31#include <linux/rcupdate.h>
30#include <asm/atomic.h> 32#include <asm/atomic.h>
31#include <asm/uaccess.h> 33#include <asm/uaccess.h>
32#include <net/neighbour.h> 34#include <net/neighbour.h>
@@ -39,7 +41,7 @@
39 41
40struct dn_fib_rule 42struct dn_fib_rule
41{ 43{
42 struct dn_fib_rule *r_next; 44 struct hlist_node r_hlist;
43 atomic_t r_clntref; 45 atomic_t r_clntref;
44 u32 r_preference; 46 u32 r_preference;
45 unsigned char r_table; 47 unsigned char r_table;
@@ -58,6 +60,7 @@ struct dn_fib_rule
58 int r_ifindex; 60 int r_ifindex;
59 char r_ifname[IFNAMSIZ]; 61 char r_ifname[IFNAMSIZ];
60 int r_dead; 62 int r_dead;
63 struct rcu_head rcu;
61}; 64};
62 65
63static struct dn_fib_rule default_rule = { 66static struct dn_fib_rule default_rule = {
@@ -67,18 +70,17 @@ static struct dn_fib_rule default_rule = {
67 .r_action = RTN_UNICAST 70 .r_action = RTN_UNICAST
68}; 71};
69 72
70static struct dn_fib_rule *dn_fib_rules = &default_rule; 73static struct hlist_head dn_fib_rules;
71static DEFINE_RWLOCK(dn_fib_rules_lock);
72
73 74
74int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 75int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
75{ 76{
76 struct rtattr **rta = arg; 77 struct rtattr **rta = arg;
77 struct rtmsg *rtm = NLMSG_DATA(nlh); 78 struct rtmsg *rtm = NLMSG_DATA(nlh);
78 struct dn_fib_rule *r, **rp; 79 struct dn_fib_rule *r;
80 struct hlist_node *node;
79 int err = -ESRCH; 81 int err = -ESRCH;
80 82
81 for(rp=&dn_fib_rules; (r=*rp) != NULL; rp = &r->r_next) { 83 hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
82 if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) && 84 if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) &&
83 rtm->rtm_src_len == r->r_src_len && 85 rtm->rtm_src_len == r->r_src_len &&
84 rtm->rtm_dst_len == r->r_dst_len && 86 rtm->rtm_dst_len == r->r_dst_len &&
@@ -95,10 +97,8 @@ int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
95 if (r == &default_rule) 97 if (r == &default_rule)
96 break; 98 break;
97 99
98 write_lock_bh(&dn_fib_rules_lock); 100 hlist_del_rcu(&r->r_hlist);
99 *rp = r->r_next;
100 r->r_dead = 1; 101 r->r_dead = 1;
101 write_unlock_bh(&dn_fib_rules_lock);
102 dn_fib_rule_put(r); 102 dn_fib_rule_put(r);
103 err = 0; 103 err = 0;
104 break; 104 break;
@@ -108,11 +108,17 @@ int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
108 return err; 108 return err;
109} 109}
110 110
111static inline void dn_fib_rule_put_rcu(struct rcu_head *head)
112{
113 struct dn_fib_rule *r = container_of(head, struct dn_fib_rule, rcu);
114 kfree(r);
115}
116
111void dn_fib_rule_put(struct dn_fib_rule *r) 117void dn_fib_rule_put(struct dn_fib_rule *r)
112{ 118{
113 if (atomic_dec_and_test(&r->r_clntref)) { 119 if (atomic_dec_and_test(&r->r_clntref)) {
114 if (r->r_dead) 120 if (r->r_dead)
115 kfree(r); 121 call_rcu(&r->rcu, dn_fib_rule_put_rcu);
116 else 122 else
117 printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n"); 123 printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n");
118 } 124 }
@@ -123,7 +129,8 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
123{ 129{
124 struct rtattr **rta = arg; 130 struct rtattr **rta = arg;
125 struct rtmsg *rtm = NLMSG_DATA(nlh); 131 struct rtmsg *rtm = NLMSG_DATA(nlh);
126 struct dn_fib_rule *r, *new_r, **rp; 132 struct dn_fib_rule *r, *new_r, *last = NULL;
133 struct hlist_node *node = NULL;
127 unsigned char table_id; 134 unsigned char table_id;
128 135
129 if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16) 136 if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16)
@@ -149,6 +156,7 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
149 if (!new_r) 156 if (!new_r)
150 return -ENOMEM; 157 return -ENOMEM;
151 memset(new_r, 0, sizeof(*new_r)); 158 memset(new_r, 0, sizeof(*new_r));
159
152 if (rta[RTA_SRC-1]) 160 if (rta[RTA_SRC-1])
153 memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2); 161 memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2);
154 if (rta[RTA_DST-1]) 162 if (rta[RTA_DST-1])
@@ -179,27 +187,26 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
179 } 187 }
180 } 188 }
181 189
182 rp = &dn_fib_rules; 190 r = container_of(dn_fib_rules.first, struct dn_fib_rule, r_hlist);
183 if (!new_r->r_preference) { 191 if (!new_r->r_preference) {
184 r = dn_fib_rules; 192 if (r && r->r_hlist.next != NULL) {
185 if (r && (r = r->r_next) != NULL) { 193 r = container_of(r->r_hlist.next, struct dn_fib_rule, r_hlist);
186 rp = &dn_fib_rules->r_next;
187 if (r->r_preference) 194 if (r->r_preference)
188 new_r->r_preference = r->r_preference - 1; 195 new_r->r_preference = r->r_preference - 1;
189 } 196 }
190 } 197 }
191 198
192 while((r=*rp) != NULL) { 199 hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
193 if (r->r_preference > new_r->r_preference) 200 if (r->r_preference > new_r->r_preference)
194 break; 201 break;
195 rp = &r->r_next; 202 last = r;
196 } 203 }
197
198 new_r->r_next = r;
199 atomic_inc(&new_r->r_clntref); 204 atomic_inc(&new_r->r_clntref);
200 write_lock_bh(&dn_fib_rules_lock); 205
201 *rp = new_r; 206 if (last)
202 write_unlock_bh(&dn_fib_rules_lock); 207 hlist_add_after_rcu(&last->r_hlist, &new_r->r_hlist);
208 else
209 hlist_add_before_rcu(&new_r->r_hlist, &r->r_hlist);
203 return 0; 210 return 0;
204} 211}
205 212
@@ -210,10 +217,12 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
210 struct dn_fib_table *tb; 217 struct dn_fib_table *tb;
211 __le16 saddr = flp->fld_src; 218 __le16 saddr = flp->fld_src;
212 __le16 daddr = flp->fld_dst; 219 __le16 daddr = flp->fld_dst;
220 struct hlist_node *node;
213 int err; 221 int err;
214 222
215 read_lock(&dn_fib_rules_lock); 223 rcu_read_lock();
216 for(r = dn_fib_rules; r; r = r->r_next) { 224
225 hlist_for_each_entry_rcu(r, node, &dn_fib_rules, r_hlist) {
217 if (((saddr^r->r_src) & r->r_srcmask) || 226 if (((saddr^r->r_src) & r->r_srcmask) ||
218 ((daddr^r->r_dst) & r->r_dstmask) || 227 ((daddr^r->r_dst) & r->r_dstmask) ||
219#ifdef CONFIG_DECNET_ROUTE_FWMARK 228#ifdef CONFIG_DECNET_ROUTE_FWMARK
@@ -228,14 +237,14 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
228 policy = r; 237 policy = r;
229 break; 238 break;
230 case RTN_UNREACHABLE: 239 case RTN_UNREACHABLE:
231 read_unlock(&dn_fib_rules_lock); 240 rcu_read_unlock();
232 return -ENETUNREACH; 241 return -ENETUNREACH;
233 default: 242 default:
234 case RTN_BLACKHOLE: 243 case RTN_BLACKHOLE:
235 read_unlock(&dn_fib_rules_lock); 244 rcu_read_unlock();
236 return -EINVAL; 245 return -EINVAL;
237 case RTN_PROHIBIT: 246 case RTN_PROHIBIT:
238 read_unlock(&dn_fib_rules_lock); 247 rcu_read_unlock();
239 return -EACCES; 248 return -EACCES;
240 } 249 }
241 250
@@ -246,16 +255,16 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res)
246 res->r = policy; 255 res->r = policy;
247 if (policy) 256 if (policy)
248 atomic_inc(&policy->r_clntref); 257 atomic_inc(&policy->r_clntref);
249 read_unlock(&dn_fib_rules_lock); 258 rcu_read_unlock();
250 return 0; 259 return 0;
251 } 260 }
252 if (err < 0 && err != -EAGAIN) { 261 if (err < 0 && err != -EAGAIN) {
253 read_unlock(&dn_fib_rules_lock); 262 rcu_read_unlock();
254 return err; 263 return err;
255 } 264 }
256 } 265 }
257 266
258 read_unlock(&dn_fib_rules_lock); 267 rcu_read_unlock();
259 return -ESRCH; 268 return -ESRCH;
260} 269}
261 270
@@ -297,27 +306,23 @@ __le16 dn_fib_rules_policy(__le16 saddr, struct dn_fib_res *res, unsigned *flags
297 306
298static void dn_fib_rules_detach(struct net_device *dev) 307static void dn_fib_rules_detach(struct net_device *dev)
299{ 308{
309 struct hlist_node *node;
300 struct dn_fib_rule *r; 310 struct dn_fib_rule *r;
301 311
302 for(r = dn_fib_rules; r; r = r->r_next) { 312 hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
303 if (r->r_ifindex == dev->ifindex) { 313 if (r->r_ifindex == dev->ifindex)
304 write_lock_bh(&dn_fib_rules_lock);
305 r->r_ifindex = -1; 314 r->r_ifindex = -1;
306 write_unlock_bh(&dn_fib_rules_lock);
307 }
308 } 315 }
309} 316}
310 317
311static void dn_fib_rules_attach(struct net_device *dev) 318static void dn_fib_rules_attach(struct net_device *dev)
312{ 319{
320 struct hlist_node *node;
313 struct dn_fib_rule *r; 321 struct dn_fib_rule *r;
314 322
315 for(r = dn_fib_rules; r; r = r->r_next) { 323 hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
316 if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) { 324 if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0)
317 write_lock_bh(&dn_fib_rules_lock);
318 r->r_ifindex = dev->ifindex; 325 r->r_ifindex = dev->ifindex;
319 write_unlock_bh(&dn_fib_rules_lock);
320 }
321 } 326 }
322} 327}
323 328
@@ -387,18 +392,20 @@ rtattr_failure:
387 392
388int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) 393int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
389{ 394{
390 int idx; 395 int idx = 0;
391 int s_idx = cb->args[0]; 396 int s_idx = cb->args[0];
392 struct dn_fib_rule *r; 397 struct dn_fib_rule *r;
398 struct hlist_node *node;
393 399
394 read_lock(&dn_fib_rules_lock); 400 rcu_read_lock();
395 for(r = dn_fib_rules, idx = 0; r; r = r->r_next, idx++) { 401 hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) {
396 if (idx < s_idx) 402 if (idx < s_idx)
397 continue; 403 continue;
398 if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0) 404 if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0)
399 break; 405 break;
406 idx++;
400 } 407 }
401 read_unlock(&dn_fib_rules_lock); 408 rcu_read_unlock();
402 cb->args[0] = idx; 409 cb->args[0] = idx;
403 410
404 return skb->len; 411 return skb->len;
@@ -406,6 +413,8 @@ int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
406 413
407void __init dn_fib_rules_init(void) 414void __init dn_fib_rules_init(void)
408{ 415{
416 INIT_HLIST_HEAD(&dn_fib_rules);
417 hlist_add_head(&default_rule.r_hlist, &dn_fib_rules);
409 register_netdevice_notifier(&dn_fib_rules_notifier); 418 register_netdevice_notifier(&dn_fib_rules_notifier);
410} 419}
411 420