aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
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 /net/xfrm
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>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c111
-rw-r--r--net/xfrm/xfrm_state.c109
-rw-r--r--net/xfrm/xfrm_user.c4
3 files changed, 97 insertions, 127 deletions
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 }