aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-10-01 10:03:24 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-01 10:03:24 -0400
commit12a169e7d8f4b1c95252d8b04ed0f1033ed7cfe2 (patch)
tree9630d7798d4fdfc06d6001ccd057aff68f39f908
parentb262e60309e1b0eb25d300c7e739427d5316abb1 (diff)
ipsec: Put dumpers on the dump list
Herbert Xu came up with the idea and the original patch to make xfrm_state dump list contain also dumpers: As it is we go to extraordinary lengths to ensure that states don't go away while dumpers go to sleep. It's much easier if we just put the dumpers themselves on the list since they can't go away while they're going. I've also changed the order of addition on new states to prevent a never-ending dump. Timo Teräs improved the patch to apply cleanly to latest tree, modified iteration code to be more readable by using a common struct for entries in the list, implemented the same idea for xfrm_policy dumping and moved the af_key specific "last" entry caching to af_key. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Timo Teras <timo.teras@iki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netlink.h2
-rw-r--r--include/net/xfrm.h70
-rw-r--r--net/key/af_key.c38
-rw-r--r--net/xfrm/xfrm_policy.c111
-rw-r--r--net/xfrm/xfrm_state.c109
-rw-r--r--net/xfrm/xfrm_user.c4
6 files changed, 159 insertions, 175 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index cbba7760545b..9ff1b54908f3 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -220,7 +220,7 @@ struct netlink_callback
220 int (*dump)(struct sk_buff * skb, struct netlink_callback *cb); 220 int (*dump)(struct sk_buff * skb, struct netlink_callback *cb);
221 int (*done)(struct netlink_callback *cb); 221 int (*done)(struct netlink_callback *cb);
222 int family; 222 int family;
223 long args[7]; 223 long args[6];
224}; 224};
225 225
226struct netlink_notify 226struct netlink_notify
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 48630b266593..b98d2056f27f 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -117,12 +117,21 @@ extern struct mutex xfrm_cfg_mutex;
117 metrics. Plus, it will be made via sk->sk_dst_cache. Solved. 117 metrics. Plus, it will be made via sk->sk_dst_cache. Solved.
118 */ 118 */
119 119
120struct xfrm_state_walk {
121 struct list_head all;
122 u8 state;
123 union {
124 u8 dying;
125 u8 proto;
126 };
127 u32 seq;
128};
129
120/* Full description of state of transformer. */ 130/* Full description of state of transformer. */
121struct xfrm_state 131struct xfrm_state
122{ 132{
123 struct list_head all;
124 union { 133 union {
125 struct list_head gclist; 134 struct hlist_node gclist;
126 struct hlist_node bydst; 135 struct hlist_node bydst;
127 }; 136 };
128 struct hlist_node bysrc; 137 struct hlist_node bysrc;
@@ -136,12 +145,8 @@ struct xfrm_state
136 145
137 u32 genid; 146 u32 genid;
138 147
139 /* Key manger bits */ 148 /* Key manager bits */
140 struct { 149 struct xfrm_state_walk km;
141 u8 state;
142 u8 dying;
143 u32 seq;
144 } km;
145 150
146 /* Parameters of this state. */ 151 /* Parameters of this state. */
147 struct { 152 struct {
@@ -449,10 +454,20 @@ struct xfrm_tmpl
449 454
450#define XFRM_MAX_DEPTH 6 455#define XFRM_MAX_DEPTH 6
451 456
457struct xfrm_policy_walk_entry {
458 struct list_head all;
459 u8 dead;
460};
461
462struct xfrm_policy_walk {
463 struct xfrm_policy_walk_entry walk;
464 u8 type;
465 u32 seq;
466};
467
452struct xfrm_policy 468struct xfrm_policy
453{ 469{
454 struct xfrm_policy *next; 470 struct xfrm_policy *next;
455 struct list_head bytype;
456 struct hlist_node bydst; 471 struct hlist_node bydst;
457 struct hlist_node byidx; 472 struct hlist_node byidx;
458 473
@@ -467,13 +482,12 @@ struct xfrm_policy
467 struct xfrm_lifetime_cfg lft; 482 struct xfrm_lifetime_cfg lft;
468 struct xfrm_lifetime_cur curlft; 483 struct xfrm_lifetime_cur curlft;
469 struct dst_entry *bundles; 484 struct dst_entry *bundles;
470 u16 family; 485 struct xfrm_policy_walk_entry walk;
471 u8 type; 486 u8 type;
472 u8 action; 487 u8 action;
473 u8 flags; 488 u8 flags;
474 u8 dead;
475 u8 xfrm_nr; 489 u8 xfrm_nr;
476 /* XXX 1 byte hole, try to pack */ 490 u16 family;
477 struct xfrm_sec_ctx *security; 491 struct xfrm_sec_ctx *security;
478 struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; 492 struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
479}; 493};
@@ -1245,20 +1259,6 @@ struct xfrm6_tunnel {
1245 int priority; 1259 int priority;
1246}; 1260};
1247 1261
1248struct xfrm_state_walk {
1249 struct list_head list;
1250 unsigned long genid;
1251 struct xfrm_state *state;
1252 int count;
1253 u8 proto;
1254};
1255
1256struct xfrm_policy_walk {
1257 struct xfrm_policy *policy;
1258 int count;
1259 u8 type, cur_type;
1260};
1261
1262extern void xfrm_init(void); 1262extern void xfrm_init(void);
1263extern void xfrm4_init(void); 1263extern void xfrm4_init(void);
1264extern void xfrm_state_init(void); 1264extern void xfrm_state_init(void);
@@ -1410,24 +1410,10 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
1410 1410
1411struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); 1411struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
1412 1412
1413static inline void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) 1413extern void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
1414{
1415 walk->cur_type = XFRM_POLICY_TYPE_MAIN;
1416 walk->type = type;
1417 walk->policy = NULL;
1418 walk->count = 0;
1419}
1420
1421static inline void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
1422{
1423 if (walk->policy != NULL) {
1424 xfrm_pol_put(walk->policy);
1425 walk->policy = NULL;
1426 }
1427}
1428
1429extern int xfrm_policy_walk(struct xfrm_policy_walk *walk, 1414extern int xfrm_policy_walk(struct xfrm_policy_walk *walk,
1430 int (*func)(struct xfrm_policy *, int, int, void*), void *); 1415 int (*func)(struct xfrm_policy *, int, int, void*), void *);
1416extern void xfrm_policy_walk_done(struct xfrm_policy_walk *walk);
1431int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); 1417int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
1432struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, 1418struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
1433 struct xfrm_selector *sel, 1419 struct xfrm_selector *sel,
diff --git a/net/key/af_key.c b/net/key/af_key.c
index b7f5a1c353ee..7ae641df70bd 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -58,6 +58,7 @@ struct pfkey_sock {
58 struct xfrm_policy_walk policy; 58 struct xfrm_policy_walk policy;
59 struct xfrm_state_walk state; 59 struct xfrm_state_walk state;
60 } u; 60 } u;
61 struct sk_buff *skb;
61 } dump; 62 } dump;
62}; 63};
63 64
@@ -76,6 +77,10 @@ static int pfkey_can_dump(struct sock *sk)
76static void pfkey_terminate_dump(struct pfkey_sock *pfk) 77static void pfkey_terminate_dump(struct pfkey_sock *pfk)
77{ 78{
78 if (pfk->dump.dump) { 79 if (pfk->dump.dump) {
80 if (pfk->dump.skb) {
81 kfree_skb(pfk->dump.skb);
82 pfk->dump.skb = NULL;
83 }
79 pfk->dump.done(pfk); 84 pfk->dump.done(pfk);
80 pfk->dump.dump = NULL; 85 pfk->dump.dump = NULL;
81 pfk->dump.done = NULL; 86 pfk->dump.done = NULL;
@@ -308,12 +313,25 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
308 313
309static int pfkey_do_dump(struct pfkey_sock *pfk) 314static int pfkey_do_dump(struct pfkey_sock *pfk)
310{ 315{
316 struct sadb_msg *hdr;
311 int rc; 317 int rc;
312 318
313 rc = pfk->dump.dump(pfk); 319 rc = pfk->dump.dump(pfk);
314 if (rc == -ENOBUFS) 320 if (rc == -ENOBUFS)
315 return 0; 321 return 0;
316 322
323 if (pfk->dump.skb) {
324 if (!pfkey_can_dump(&pfk->sk))
325 return 0;
326
327 hdr = (struct sadb_msg *) pfk->dump.skb->data;
328 hdr->sadb_msg_seq = 0;
329 hdr->sadb_msg_errno = rc;
330 pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
331 &pfk->sk);
332 pfk->dump.skb = NULL;
333 }
334
317 pfkey_terminate_dump(pfk); 335 pfkey_terminate_dump(pfk);
318 return rc; 336 return rc;
319} 337}
@@ -1744,9 +1762,14 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr)
1744 out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 1762 out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
1745 out_hdr->sadb_msg_errno = 0; 1763 out_hdr->sadb_msg_errno = 0;
1746 out_hdr->sadb_msg_reserved = 0; 1764 out_hdr->sadb_msg_reserved = 0;
1747 out_hdr->sadb_msg_seq = count; 1765 out_hdr->sadb_msg_seq = count + 1;
1748 out_hdr->sadb_msg_pid = pfk->dump.msg_pid; 1766 out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
1749 pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); 1767
1768 if (pfk->dump.skb)
1769 pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
1770 &pfk->sk);
1771 pfk->dump.skb = out_skb;
1772
1750 return 0; 1773 return 0;
1751} 1774}
1752 1775
@@ -2245,7 +2268,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
2245 return 0; 2268 return 0;
2246 2269
2247out: 2270out:
2248 xp->dead = 1; 2271 xp->walk.dead = 1;
2249 xfrm_policy_destroy(xp); 2272 xfrm_policy_destroy(xp);
2250 return err; 2273 return err;
2251} 2274}
@@ -2583,9 +2606,14 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
2583 out_hdr->sadb_msg_type = SADB_X_SPDDUMP; 2606 out_hdr->sadb_msg_type = SADB_X_SPDDUMP;
2584 out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; 2607 out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
2585 out_hdr->sadb_msg_errno = 0; 2608 out_hdr->sadb_msg_errno = 0;
2586 out_hdr->sadb_msg_seq = count; 2609 out_hdr->sadb_msg_seq = count + 1;
2587 out_hdr->sadb_msg_pid = pfk->dump.msg_pid; 2610 out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
2588 pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); 2611
2612 if (pfk->dump.skb)
2613 pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
2614 &pfk->sk);
2615 pfk->dump.skb = out_skb;
2616
2589 return 0; 2617 return 0;
2590} 2618}
2591 2619
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index ef9ccbc38752..b7ec08025ffb 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,7 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex);
46 46
47static DEFINE_RWLOCK(xfrm_policy_lock); 47static DEFINE_RWLOCK(xfrm_policy_lock);
48 48
49static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX]; 49static struct list_head xfrm_policy_all;
50unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; 50unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
51EXPORT_SYMBOL(xfrm_policy_count); 51EXPORT_SYMBOL(xfrm_policy_count);
52 52
@@ -164,7 +164,7 @@ static void xfrm_policy_timer(unsigned long data)
164 164
165 read_lock(&xp->lock); 165 read_lock(&xp->lock);
166 166
167 if (xp->dead) 167 if (xp->walk.dead)
168 goto out; 168 goto out;
169 169
170 dir = xfrm_policy_id2dir(xp->index); 170 dir = xfrm_policy_id2dir(xp->index);
@@ -236,7 +236,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp)
236 policy = kzalloc(sizeof(struct xfrm_policy), gfp); 236 policy = kzalloc(sizeof(struct xfrm_policy), gfp);
237 237
238 if (policy) { 238 if (policy) {
239 INIT_LIST_HEAD(&policy->bytype); 239 INIT_LIST_HEAD(&policy->walk.all);
240 INIT_HLIST_NODE(&policy->bydst); 240 INIT_HLIST_NODE(&policy->bydst);
241 INIT_HLIST_NODE(&policy->byidx); 241 INIT_HLIST_NODE(&policy->byidx);
242 rwlock_init(&policy->lock); 242 rwlock_init(&policy->lock);
@@ -252,17 +252,13 @@ EXPORT_SYMBOL(xfrm_policy_alloc);
252 252
253void xfrm_policy_destroy(struct xfrm_policy *policy) 253void xfrm_policy_destroy(struct xfrm_policy *policy)
254{ 254{
255 BUG_ON(!policy->dead); 255 BUG_ON(!policy->walk.dead);
256 256
257 BUG_ON(policy->bundles); 257 BUG_ON(policy->bundles);
258 258
259 if (del_timer(&policy->timer)) 259 if (del_timer(&policy->timer))
260 BUG(); 260 BUG();
261 261
262 write_lock_bh(&xfrm_policy_lock);
263 list_del(&policy->bytype);
264 write_unlock_bh(&xfrm_policy_lock);
265
266 security_xfrm_policy_free(policy->security); 262 security_xfrm_policy_free(policy->security);
267 kfree(policy); 263 kfree(policy);
268} 264}
@@ -310,8 +306,8 @@ static void xfrm_policy_kill(struct xfrm_policy *policy)
310 int dead; 306 int dead;
311 307
312 write_lock_bh(&policy->lock); 308 write_lock_bh(&policy->lock);
313 dead = policy->dead; 309 dead = policy->walk.dead;
314 policy->dead = 1; 310 policy->walk.dead = 1;
315 write_unlock_bh(&policy->lock); 311 write_unlock_bh(&policy->lock);
316 312
317 if (unlikely(dead)) { 313 if (unlikely(dead)) {
@@ -609,6 +605,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
609 if (delpol) { 605 if (delpol) {
610 hlist_del(&delpol->bydst); 606 hlist_del(&delpol->bydst);
611 hlist_del(&delpol->byidx); 607 hlist_del(&delpol->byidx);
608 list_del(&delpol->walk.all);
612 xfrm_policy_count[dir]--; 609 xfrm_policy_count[dir]--;
613 } 610 }
614 policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); 611 policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir);
@@ -617,7 +614,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
617 policy->curlft.use_time = 0; 614 policy->curlft.use_time = 0;
618 if (!mod_timer(&policy->timer, jiffies + HZ)) 615 if (!mod_timer(&policy->timer, jiffies + HZ))
619 xfrm_pol_hold(policy); 616 xfrm_pol_hold(policy);
620 list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]); 617 list_add(&policy->walk.all, &xfrm_policy_all);
621 write_unlock_bh(&xfrm_policy_lock); 618 write_unlock_bh(&xfrm_policy_lock);
622 619
623 if (delpol) 620 if (delpol)
@@ -684,6 +681,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
684 } 681 }
685 hlist_del(&pol->bydst); 682 hlist_del(&pol->bydst);
686 hlist_del(&pol->byidx); 683 hlist_del(&pol->byidx);
684 list_del(&pol->walk.all);
687 xfrm_policy_count[dir]--; 685 xfrm_policy_count[dir]--;
688 } 686 }
689 ret = pol; 687 ret = pol;
@@ -727,6 +725,7 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete,
727 } 725 }
728 hlist_del(&pol->bydst); 726 hlist_del(&pol->bydst);
729 hlist_del(&pol->byidx); 727 hlist_del(&pol->byidx);
728 list_del(&pol->walk.all);
730 xfrm_policy_count[dir]--; 729 xfrm_policy_count[dir]--;
731 } 730 }
732 ret = pol; 731 ret = pol;
@@ -840,6 +839,7 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info)
840 continue; 839 continue;
841 hlist_del(&pol->bydst); 840 hlist_del(&pol->bydst);
842 hlist_del(&pol->byidx); 841 hlist_del(&pol->byidx);
842 list_del(&pol->walk.all);
843 write_unlock_bh(&xfrm_policy_lock); 843 write_unlock_bh(&xfrm_policy_lock);
844 844
845 xfrm_audit_policy_delete(pol, 1, 845 xfrm_audit_policy_delete(pol, 1,
@@ -867,60 +867,68 @@ int xfrm_policy_walk(struct xfrm_policy_walk *walk,
867 int (*func)(struct xfrm_policy *, int, int, void*), 867 int (*func)(struct xfrm_policy *, int, int, void*),
868 void *data) 868 void *data)
869{ 869{
870 struct xfrm_policy *old, *pol, *last = NULL; 870 struct xfrm_policy *pol;
871 struct xfrm_policy_walk_entry *x;
871 int error = 0; 872 int error = 0;
872 873
873 if (walk->type >= XFRM_POLICY_TYPE_MAX && 874 if (walk->type >= XFRM_POLICY_TYPE_MAX &&
874 walk->type != XFRM_POLICY_TYPE_ANY) 875 walk->type != XFRM_POLICY_TYPE_ANY)
875 return -EINVAL; 876 return -EINVAL;
876 877
877 if (walk->policy == NULL && walk->count != 0) 878 if (list_empty(&walk->walk.all) && walk->seq != 0)
878 return 0; 879 return 0;
879 880
880 old = pol = walk->policy; 881 write_lock_bh(&xfrm_policy_lock);
881 walk->policy = NULL; 882 if (list_empty(&walk->walk.all))
882 read_lock_bh(&xfrm_policy_lock); 883 x = list_first_entry(&xfrm_policy_all, struct xfrm_policy_walk_entry, all);
883 884 else
884 for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) { 885 x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all);
885 if (walk->type != walk->cur_type && 886 list_for_each_entry_from(x, &xfrm_policy_all, all) {
886 walk->type != XFRM_POLICY_TYPE_ANY) 887 if (x->dead)
887 continue; 888 continue;
888 889 pol = container_of(x, struct xfrm_policy, walk);
889 if (pol == NULL) { 890 if (walk->type != XFRM_POLICY_TYPE_ANY &&
890 pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type], 891 walk->type != pol->type)
891 struct xfrm_policy, bytype); 892 continue;
892 } 893 error = func(pol, xfrm_policy_id2dir(pol->index),
893 list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) { 894 walk->seq, data);
894 if (pol->dead) 895 if (error) {
895 continue; 896 list_move_tail(&walk->walk.all, &x->all);
896 if (last) { 897 goto out;
897 error = func(last, xfrm_policy_id2dir(last->index),
898 walk->count, data);
899 if (error) {
900 xfrm_pol_hold(last);
901 walk->policy = last;
902 goto out;
903 }
904 }
905 last = pol;
906 walk->count++;
907 } 898 }
908 pol = NULL; 899 walk->seq++;
909 } 900 }
910 if (walk->count == 0) { 901 if (walk->seq == 0) {
911 error = -ENOENT; 902 error = -ENOENT;
912 goto out; 903 goto out;
913 } 904 }
914 if (last) 905 list_del_init(&walk->walk.all);
915 error = func(last, xfrm_policy_id2dir(last->index), 0, data);
916out: 906out:
917 read_unlock_bh(&xfrm_policy_lock); 907 write_unlock_bh(&xfrm_policy_lock);
918 if (old != NULL)
919 xfrm_pol_put(old);
920 return error; 908 return error;
921} 909}
922EXPORT_SYMBOL(xfrm_policy_walk); 910EXPORT_SYMBOL(xfrm_policy_walk);
923 911
912void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
913{
914 INIT_LIST_HEAD(&walk->walk.all);
915 walk->walk.dead = 1;
916 walk->type = type;
917 walk->seq = 0;
918}
919EXPORT_SYMBOL(xfrm_policy_walk_init);
920
921void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
922{
923 if (list_empty(&walk->walk.all))
924 return;
925
926 write_lock_bh(&xfrm_policy_lock);
927 list_del(&walk->walk.all);
928 write_unlock_bh(&xfrm_policy_lock);
929}
930EXPORT_SYMBOL(xfrm_policy_walk_done);
931
924/* 932/*
925 * Find policy to apply to this flow. 933 * Find policy to apply to this flow.
926 * 934 *
@@ -1077,7 +1085,7 @@ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
1077 struct hlist_head *chain = policy_hash_bysel(&pol->selector, 1085 struct hlist_head *chain = policy_hash_bysel(&pol->selector,
1078 pol->family, dir); 1086 pol->family, dir);
1079 1087
1080 list_add_tail(&pol->bytype, &xfrm_policy_bytype[pol->type]); 1088 list_add(&pol->walk.all, &xfrm_policy_all);
1081 hlist_add_head(&pol->bydst, chain); 1089 hlist_add_head(&pol->bydst, chain);
1082 hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); 1090 hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index));
1083 xfrm_policy_count[dir]++; 1091 xfrm_policy_count[dir]++;
@@ -1095,6 +1103,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
1095 1103
1096 hlist_del(&pol->bydst); 1104 hlist_del(&pol->bydst);
1097 hlist_del(&pol->byidx); 1105 hlist_del(&pol->byidx);
1106 list_del(&pol->walk.all);
1098 xfrm_policy_count[dir]--; 1107 xfrm_policy_count[dir]--;
1099 1108
1100 return pol; 1109 return pol;
@@ -1720,7 +1729,7 @@ restart:
1720 1729
1721 for (pi = 0; pi < npols; pi++) { 1730 for (pi = 0; pi < npols; pi++) {
1722 read_lock_bh(&pols[pi]->lock); 1731 read_lock_bh(&pols[pi]->lock);
1723 pol_dead |= pols[pi]->dead; 1732 pol_dead |= pols[pi]->walk.dead;
1724 read_unlock_bh(&pols[pi]->lock); 1733 read_unlock_bh(&pols[pi]->lock);
1725 } 1734 }
1726 1735
@@ -2415,9 +2424,7 @@ static void __init xfrm_policy_init(void)
2415 panic("XFRM: failed to allocate bydst hash\n"); 2424 panic("XFRM: failed to allocate bydst hash\n");
2416 } 2425 }
2417 2426
2418 for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++) 2427 INIT_LIST_HEAD(&xfrm_policy_all);
2419 INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
2420
2421 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); 2428 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
2422 register_netdevice_notifier(&xfrm_dev_notifier); 2429 register_netdevice_notifier(&xfrm_dev_notifier);
2423} 2430}
@@ -2601,7 +2608,7 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol,
2601 int i, j, n = 0; 2608 int i, j, n = 0;
2602 2609
2603 write_lock_bh(&pol->lock); 2610 write_lock_bh(&pol->lock);
2604 if (unlikely(pol->dead)) { 2611 if (unlikely(pol->walk.dead)) {
2605 /* target policy has been deleted */ 2612 /* target policy has been deleted */
2606 write_unlock_bh(&pol->lock); 2613 write_unlock_bh(&pol->lock);
2607 return -ENOENT; 2614 return -ENOENT;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 053970e8765d..747fd8c291a7 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -59,14 +59,6 @@ static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
59static unsigned int xfrm_state_num; 59static unsigned int xfrm_state_num;
60static unsigned int xfrm_state_genid; 60static unsigned int xfrm_state_genid;
61 61
62/* Counter indicating ongoing walk, protected by xfrm_state_lock. */
63static unsigned long xfrm_state_walk_ongoing;
64/* Counter indicating walk completion, protected by xfrm_cfg_mutex. */
65static unsigned long xfrm_state_walk_completed;
66
67/* List of outstanding state walks used to set the completed counter. */
68static LIST_HEAD(xfrm_state_walks);
69
70static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); 62static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
71static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); 63static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
72 64
@@ -199,8 +191,7 @@ static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
199static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; 191static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
200 192
201static struct work_struct xfrm_state_gc_work; 193static struct work_struct xfrm_state_gc_work;
202static LIST_HEAD(xfrm_state_gc_leftovers); 194static HLIST_HEAD(xfrm_state_gc_list);
203static LIST_HEAD(xfrm_state_gc_list);
204static DEFINE_SPINLOCK(xfrm_state_gc_lock); 195static DEFINE_SPINLOCK(xfrm_state_gc_lock);
205 196
206int __xfrm_state_delete(struct xfrm_state *x); 197int __xfrm_state_delete(struct xfrm_state *x);
@@ -412,23 +403,16 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
412 403
413static void xfrm_state_gc_task(struct work_struct *data) 404static void xfrm_state_gc_task(struct work_struct *data)
414{ 405{
415 struct xfrm_state *x, *tmp; 406 struct xfrm_state *x;
416 unsigned long completed; 407 struct hlist_node *entry, *tmp;
408 struct hlist_head gc_list;
417 409
418 mutex_lock(&xfrm_cfg_mutex);
419 spin_lock_bh(&xfrm_state_gc_lock); 410 spin_lock_bh(&xfrm_state_gc_lock);
420 list_splice_tail_init(&xfrm_state_gc_list, &xfrm_state_gc_leftovers); 411 hlist_move_list(&xfrm_state_gc_list, &gc_list);
421 spin_unlock_bh(&xfrm_state_gc_lock); 412 spin_unlock_bh(&xfrm_state_gc_lock);
422 413
423 completed = xfrm_state_walk_completed; 414 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
424 mutex_unlock(&xfrm_cfg_mutex);
425
426 list_for_each_entry_safe(x, tmp, &xfrm_state_gc_leftovers, gclist) {
427 if ((long)(x->lastused - completed) > 0)
428 break;
429 list_del(&x->gclist);
430 xfrm_state_gc_destroy(x); 415 xfrm_state_gc_destroy(x);
431 }
432 416
433 wake_up(&km_waitq); 417 wake_up(&km_waitq);
434} 418}
@@ -529,7 +513,7 @@ struct xfrm_state *xfrm_state_alloc(void)
529 if (x) { 513 if (x) {
530 atomic_set(&x->refcnt, 1); 514 atomic_set(&x->refcnt, 1);
531 atomic_set(&x->tunnel_users, 0); 515 atomic_set(&x->tunnel_users, 0);
532 INIT_LIST_HEAD(&x->all); 516 INIT_LIST_HEAD(&x->km.all);
533 INIT_HLIST_NODE(&x->bydst); 517 INIT_HLIST_NODE(&x->bydst);
534 INIT_HLIST_NODE(&x->bysrc); 518 INIT_HLIST_NODE(&x->bysrc);
535 INIT_HLIST_NODE(&x->byspi); 519 INIT_HLIST_NODE(&x->byspi);
@@ -556,7 +540,7 @@ void __xfrm_state_destroy(struct xfrm_state *x)
556 WARN_ON(x->km.state != XFRM_STATE_DEAD); 540 WARN_ON(x->km.state != XFRM_STATE_DEAD);
557 541
558 spin_lock_bh(&xfrm_state_gc_lock); 542 spin_lock_bh(&xfrm_state_gc_lock);
559 list_add_tail(&x->gclist, &xfrm_state_gc_list); 543 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
560 spin_unlock_bh(&xfrm_state_gc_lock); 544 spin_unlock_bh(&xfrm_state_gc_lock);
561 schedule_work(&xfrm_state_gc_work); 545 schedule_work(&xfrm_state_gc_work);
562} 546}
@@ -569,8 +553,7 @@ int __xfrm_state_delete(struct xfrm_state *x)
569 if (x->km.state != XFRM_STATE_DEAD) { 553 if (x->km.state != XFRM_STATE_DEAD) {
570 x->km.state = XFRM_STATE_DEAD; 554 x->km.state = XFRM_STATE_DEAD;
571 spin_lock(&xfrm_state_lock); 555 spin_lock(&xfrm_state_lock);
572 x->lastused = xfrm_state_walk_ongoing; 556 list_del(&x->km.all);
573 list_del_rcu(&x->all);
574 hlist_del(&x->bydst); 557 hlist_del(&x->bydst);
575 hlist_del(&x->bysrc); 558 hlist_del(&x->bysrc);
576 if (x->id.spi) 559 if (x->id.spi)
@@ -871,7 +854,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
871 854
872 if (km_query(x, tmpl, pol) == 0) { 855 if (km_query(x, tmpl, pol) == 0) {
873 x->km.state = XFRM_STATE_ACQ; 856 x->km.state = XFRM_STATE_ACQ;
874 list_add_tail(&x->all, &xfrm_state_all); 857 list_add(&x->km.all, &xfrm_state_all);
875 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 858 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
876 h = xfrm_src_hash(daddr, saddr, family); 859 h = xfrm_src_hash(daddr, saddr, family);
877 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 860 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -940,7 +923,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
940 923
941 x->genid = ++xfrm_state_genid; 924 x->genid = ++xfrm_state_genid;
942 925
943 list_add_tail(&x->all, &xfrm_state_all); 926 list_add(&x->km.all, &xfrm_state_all);
944 927
945 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 928 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
946 x->props.reqid, x->props.family); 929 x->props.reqid, x->props.family);
@@ -1069,7 +1052,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
1069 xfrm_state_hold(x); 1052 xfrm_state_hold(x);
1070 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 1053 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
1071 add_timer(&x->timer); 1054 add_timer(&x->timer);
1072 list_add_tail(&x->all, &xfrm_state_all); 1055 list_add(&x->km.all, &xfrm_state_all);
1073 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 1056 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
1074 h = xfrm_src_hash(daddr, saddr, family); 1057 h = xfrm_src_hash(daddr, saddr, family);
1075 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 1058 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -1566,79 +1549,59 @@ int xfrm_state_walk(struct xfrm_state_walk *walk,
1566 int (*func)(struct xfrm_state *, int, void*), 1549 int (*func)(struct xfrm_state *, int, void*),
1567 void *data) 1550 void *data)
1568{ 1551{
1569 struct xfrm_state *old, *x, *last = NULL; 1552 struct xfrm_state *state;
1553 struct xfrm_state_walk *x;
1570 int err = 0; 1554 int err = 0;
1571 1555
1572 if (walk->state == NULL && walk->count != 0) 1556 if (walk->seq != 0 && list_empty(&walk->all))
1573 return 0; 1557 return 0;
1574 1558
1575 old = x = walk->state;
1576 walk->state = NULL;
1577 spin_lock_bh(&xfrm_state_lock); 1559 spin_lock_bh(&xfrm_state_lock);
1578 if (x == NULL) 1560 if (list_empty(&walk->all))
1579 x = list_first_entry(&xfrm_state_all, struct xfrm_state, all); 1561 x = list_first_entry(&xfrm_state_all, struct xfrm_state_walk, all);
1562 else
1563 x = list_entry(&walk->all, struct xfrm_state_walk, all);
1580 list_for_each_entry_from(x, &xfrm_state_all, all) { 1564 list_for_each_entry_from(x, &xfrm_state_all, all) {
1581 if (x->km.state == XFRM_STATE_DEAD) 1565 if (x->state == XFRM_STATE_DEAD)
1582 continue; 1566 continue;
1583 if (!xfrm_id_proto_match(x->id.proto, walk->proto)) 1567 state = container_of(x, struct xfrm_state, km);
1568 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
1584 continue; 1569 continue;
1585 if (last) { 1570 err = func(state, walk->seq, data);
1586 err = func(last, walk->count, data); 1571 if (err) {
1587 if (err) { 1572 list_move_tail(&walk->all, &x->all);
1588 xfrm_state_hold(last); 1573 goto out;
1589 walk->state = last;
1590 goto out;
1591 }
1592 } 1574 }
1593 last = x; 1575 walk->seq++;
1594 walk->count++;
1595 } 1576 }
1596 if (walk->count == 0) { 1577 if (walk->seq == 0) {
1597 err = -ENOENT; 1578 err = -ENOENT;
1598 goto out; 1579 goto out;
1599 } 1580 }
1600 if (last) 1581 list_del_init(&walk->all);
1601 err = func(last, 0, data);
1602out: 1582out:
1603 spin_unlock_bh(&xfrm_state_lock); 1583 spin_unlock_bh(&xfrm_state_lock);
1604 if (old != NULL)
1605 xfrm_state_put(old);
1606 return err; 1584 return err;
1607} 1585}
1608EXPORT_SYMBOL(xfrm_state_walk); 1586EXPORT_SYMBOL(xfrm_state_walk);
1609 1587
1610void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto) 1588void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1611{ 1589{
1590 INIT_LIST_HEAD(&walk->all);
1612 walk->proto = proto; 1591 walk->proto = proto;
1613 walk->state = NULL; 1592 walk->state = XFRM_STATE_DEAD;
1614 walk->count = 0; 1593 walk->seq = 0;
1615 list_add_tail(&walk->list, &xfrm_state_walks);
1616 walk->genid = ++xfrm_state_walk_ongoing;
1617} 1594}
1618EXPORT_SYMBOL(xfrm_state_walk_init); 1595EXPORT_SYMBOL(xfrm_state_walk_init);
1619 1596
1620void xfrm_state_walk_done(struct xfrm_state_walk *walk) 1597void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1621{ 1598{
1622 struct list_head *prev; 1599 if (list_empty(&walk->all))
1623
1624 if (walk->state != NULL) {
1625 xfrm_state_put(walk->state);
1626 walk->state = NULL;
1627 }
1628
1629 prev = walk->list.prev;
1630 list_del(&walk->list);
1631
1632 if (prev != &xfrm_state_walks) {
1633 list_entry(prev, struct xfrm_state_walk, list)->genid =
1634 walk->genid;
1635 return; 1600 return;
1636 }
1637
1638 xfrm_state_walk_completed = walk->genid;
1639 1601
1640 if (!list_empty(&xfrm_state_gc_leftovers)) 1602 spin_lock_bh(&xfrm_state_lock);
1641 schedule_work(&xfrm_state_gc_work); 1603 list_del(&walk->all);
1604 spin_lock_bh(&xfrm_state_lock);
1642} 1605}
1643EXPORT_SYMBOL(xfrm_state_walk_done); 1606EXPORT_SYMBOL(xfrm_state_walk_done);
1644 1607
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 04c41504f84c..76f75df21e15 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1102,7 +1102,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p,
1102 return xp; 1102 return xp;
1103 error: 1103 error:
1104 *errp = err; 1104 *errp = err;
1105 xp->dead = 1; 1105 xp->walk.dead = 1;
1106 xfrm_policy_destroy(xp); 1106 xfrm_policy_destroy(xp);
1107 return NULL; 1107 return NULL;
1108} 1108}
@@ -1595,7 +1595,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
1595 return -ENOENT; 1595 return -ENOENT;
1596 1596
1597 read_lock(&xp->lock); 1597 read_lock(&xp->lock);
1598 if (xp->dead) { 1598 if (xp->walk.dead) {
1599 read_unlock(&xp->lock); 1599 read_unlock(&xp->lock);
1600 goto out; 1600 goto out;
1601 } 1601 }