aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_state.c
diff options
context:
space:
mode:
authorSimon Horman <horms@verge.net.au>2008-10-06 17:40:11 -0400
committerSimon Horman <horms@verge.net.au>2008-10-06 17:40:11 -0400
commita5e8546a8bff5d2047adc279df5753c44ba7b1a1 (patch)
treed9ca91f74d8279adbb1d3e942cc7ab145780ee29 /net/xfrm/xfrm_state.c
parentcb7f6a7b716e801097b564dec3ccb58d330aef56 (diff)
parentc7004482e8dcb7c3c72666395cfa98a216a4fb70 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6 into lvs-next-2.6
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r--net/xfrm/xfrm_state.c109
1 files changed, 47 insertions, 62 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index abbe2702c400..508337f97249 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -59,11 +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
67static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); 62static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
68static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); 63static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
69 64
@@ -196,8 +191,7 @@ static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
196static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; 191static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
197 192
198static struct work_struct xfrm_state_gc_work; 193static struct work_struct xfrm_state_gc_work;
199static LIST_HEAD(xfrm_state_gc_leftovers); 194static HLIST_HEAD(xfrm_state_gc_list);
200static LIST_HEAD(xfrm_state_gc_list);
201static DEFINE_SPINLOCK(xfrm_state_gc_lock); 195static DEFINE_SPINLOCK(xfrm_state_gc_lock);
202 196
203int __xfrm_state_delete(struct xfrm_state *x); 197int __xfrm_state_delete(struct xfrm_state *x);
@@ -409,23 +403,16 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
409 403
410static void xfrm_state_gc_task(struct work_struct *data) 404static void xfrm_state_gc_task(struct work_struct *data)
411{ 405{
412 struct xfrm_state *x, *tmp; 406 struct xfrm_state *x;
413 unsigned long completed; 407 struct hlist_node *entry, *tmp;
408 struct hlist_head gc_list;
414 409
415 mutex_lock(&xfrm_cfg_mutex);
416 spin_lock_bh(&xfrm_state_gc_lock); 410 spin_lock_bh(&xfrm_state_gc_lock);
417 list_splice_tail_init(&xfrm_state_gc_list, &xfrm_state_gc_leftovers); 411 hlist_move_list(&xfrm_state_gc_list, &gc_list);
418 spin_unlock_bh(&xfrm_state_gc_lock); 412 spin_unlock_bh(&xfrm_state_gc_lock);
419 413
420 completed = xfrm_state_walk_completed; 414 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
421 mutex_unlock(&xfrm_cfg_mutex);
422
423 list_for_each_entry_safe(x, tmp, &xfrm_state_gc_leftovers, gclist) {
424 if ((long)(x->lastused - completed) > 0)
425 break;
426 list_del(&x->gclist);
427 xfrm_state_gc_destroy(x); 415 xfrm_state_gc_destroy(x);
428 }
429 416
430 wake_up(&km_waitq); 417 wake_up(&km_waitq);
431} 418}
@@ -526,7 +513,7 @@ struct xfrm_state *xfrm_state_alloc(void)
526 if (x) { 513 if (x) {
527 atomic_set(&x->refcnt, 1); 514 atomic_set(&x->refcnt, 1);
528 atomic_set(&x->tunnel_users, 0); 515 atomic_set(&x->tunnel_users, 0);
529 INIT_LIST_HEAD(&x->all); 516 INIT_LIST_HEAD(&x->km.all);
530 INIT_HLIST_NODE(&x->bydst); 517 INIT_HLIST_NODE(&x->bydst);
531 INIT_HLIST_NODE(&x->bysrc); 518 INIT_HLIST_NODE(&x->bysrc);
532 INIT_HLIST_NODE(&x->byspi); 519 INIT_HLIST_NODE(&x->byspi);
@@ -553,7 +540,7 @@ void __xfrm_state_destroy(struct xfrm_state *x)
553 WARN_ON(x->km.state != XFRM_STATE_DEAD); 540 WARN_ON(x->km.state != XFRM_STATE_DEAD);
554 541
555 spin_lock_bh(&xfrm_state_gc_lock); 542 spin_lock_bh(&xfrm_state_gc_lock);
556 list_add_tail(&x->gclist, &xfrm_state_gc_list); 543 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
557 spin_unlock_bh(&xfrm_state_gc_lock); 544 spin_unlock_bh(&xfrm_state_gc_lock);
558 schedule_work(&xfrm_state_gc_work); 545 schedule_work(&xfrm_state_gc_work);
559} 546}
@@ -566,8 +553,7 @@ int __xfrm_state_delete(struct xfrm_state *x)
566 if (x->km.state != XFRM_STATE_DEAD) { 553 if (x->km.state != XFRM_STATE_DEAD) {
567 x->km.state = XFRM_STATE_DEAD; 554 x->km.state = XFRM_STATE_DEAD;
568 spin_lock(&xfrm_state_lock); 555 spin_lock(&xfrm_state_lock);
569 x->lastused = xfrm_state_walk_ongoing; 556 list_del(&x->km.all);
570 list_del_rcu(&x->all);
571 hlist_del(&x->bydst); 557 hlist_del(&x->bydst);
572 hlist_del(&x->bysrc); 558 hlist_del(&x->bysrc);
573 if (x->id.spi) 559 if (x->id.spi)
@@ -868,7 +854,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
868 854
869 if (km_query(x, tmpl, pol) == 0) { 855 if (km_query(x, tmpl, pol) == 0) {
870 x->km.state = XFRM_STATE_ACQ; 856 x->km.state = XFRM_STATE_ACQ;
871 list_add_tail(&x->all, &xfrm_state_all); 857 list_add(&x->km.all, &xfrm_state_all);
872 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 858 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
873 h = xfrm_src_hash(daddr, saddr, family); 859 h = xfrm_src_hash(daddr, saddr, family);
874 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 860 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -937,7 +923,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
937 923
938 x->genid = ++xfrm_state_genid; 924 x->genid = ++xfrm_state_genid;
939 925
940 list_add_tail(&x->all, &xfrm_state_all); 926 list_add(&x->km.all, &xfrm_state_all);
941 927
942 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 928 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
943 x->props.reqid, x->props.family); 929 x->props.reqid, x->props.family);
@@ -1066,7 +1052,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
1066 xfrm_state_hold(x); 1052 xfrm_state_hold(x);
1067 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 1053 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
1068 add_timer(&x->timer); 1054 add_timer(&x->timer);
1069 list_add_tail(&x->all, &xfrm_state_all); 1055 list_add(&x->km.all, &xfrm_state_all);
1070 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 1056 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
1071 h = xfrm_src_hash(daddr, saddr, family); 1057 h = xfrm_src_hash(daddr, saddr, family);
1072 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 1058 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -1563,61 +1549,59 @@ int xfrm_state_walk(struct xfrm_state_walk *walk,
1563 int (*func)(struct xfrm_state *, int, void*), 1549 int (*func)(struct xfrm_state *, int, void*),
1564 void *data) 1550 void *data)
1565{ 1551{
1566 struct xfrm_state *old, *x, *last = NULL; 1552 struct xfrm_state *state;
1553 struct xfrm_state_walk *x;
1567 int err = 0; 1554 int err = 0;
1568 1555
1569 if (walk->state == NULL && walk->count != 0) 1556 if (walk->seq != 0 && list_empty(&walk->all))
1570 return 0; 1557 return 0;
1571 1558
1572 old = x = walk->state;
1573 walk->state = NULL;
1574 spin_lock_bh(&xfrm_state_lock); 1559 spin_lock_bh(&xfrm_state_lock);
1575 if (x == NULL) 1560 if (list_empty(&walk->all))
1576 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);
1577 list_for_each_entry_from(x, &xfrm_state_all, all) { 1564 list_for_each_entry_from(x, &xfrm_state_all, all) {
1578 if (x->km.state == XFRM_STATE_DEAD) 1565 if (x->state == XFRM_STATE_DEAD)
1579 continue; 1566 continue;
1580 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))
1581 continue; 1569 continue;
1582 if (last) { 1570 err = func(state, walk->seq, data);
1583 err = func(last, walk->count, data); 1571 if (err) {
1584 if (err) { 1572 list_move_tail(&walk->all, &x->all);
1585 xfrm_state_hold(last); 1573 goto out;
1586 walk->state = last;
1587 xfrm_state_walk_ongoing++;
1588 goto out;
1589 }
1590 } 1574 }
1591 last = x; 1575 walk->seq++;
1592 walk->count++;
1593 } 1576 }
1594 if (walk->count == 0) { 1577 if (walk->seq == 0) {
1595 err = -ENOENT; 1578 err = -ENOENT;
1596 goto out; 1579 goto out;
1597 } 1580 }
1598 if (last) 1581 list_del_init(&walk->all);
1599 err = func(last, 0, data);
1600out: 1582out:
1601 spin_unlock_bh(&xfrm_state_lock); 1583 spin_unlock_bh(&xfrm_state_lock);
1602 if (old != NULL) {
1603 xfrm_state_put(old);
1604 xfrm_state_walk_completed++;
1605 if (!list_empty(&xfrm_state_gc_leftovers))
1606 schedule_work(&xfrm_state_gc_work);
1607 }
1608 return err; 1584 return err;
1609} 1585}
1610EXPORT_SYMBOL(xfrm_state_walk); 1586EXPORT_SYMBOL(xfrm_state_walk);
1611 1587
1588void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1589{
1590 INIT_LIST_HEAD(&walk->all);
1591 walk->proto = proto;
1592 walk->state = XFRM_STATE_DEAD;
1593 walk->seq = 0;
1594}
1595EXPORT_SYMBOL(xfrm_state_walk_init);
1596
1612void xfrm_state_walk_done(struct xfrm_state_walk *walk) 1597void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1613{ 1598{
1614 if (walk->state != NULL) { 1599 if (list_empty(&walk->all))
1615 xfrm_state_put(walk->state); 1600 return;
1616 walk->state = NULL; 1601
1617 xfrm_state_walk_completed++; 1602 spin_lock_bh(&xfrm_state_lock);
1618 if (!list_empty(&xfrm_state_gc_leftovers)) 1603 list_del(&walk->all);
1619 schedule_work(&xfrm_state_gc_work); 1604 spin_lock_bh(&xfrm_state_lock);
1620 }
1621} 1605}
1622EXPORT_SYMBOL(xfrm_state_walk_done); 1606EXPORT_SYMBOL(xfrm_state_walk_done);
1623 1607
@@ -1830,7 +1814,8 @@ EXPORT_SYMBOL(km_policy_expired);
1830 1814
1831#ifdef CONFIG_XFRM_MIGRATE 1815#ifdef CONFIG_XFRM_MIGRATE
1832int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 1816int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
1833 struct xfrm_migrate *m, int num_migrate) 1817 struct xfrm_migrate *m, int num_migrate,
1818 struct xfrm_kmaddress *k)
1834{ 1819{
1835 int err = -EINVAL; 1820 int err = -EINVAL;
1836 int ret; 1821 int ret;
@@ -1839,7 +1824,7 @@ int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
1839 read_lock(&xfrm_km_lock); 1824 read_lock(&xfrm_km_lock);
1840 list_for_each_entry(km, &xfrm_km_list, list) { 1825 list_for_each_entry(km, &xfrm_km_list, list) {
1841 if (km->migrate) { 1826 if (km->migrate) {
1842 ret = km->migrate(sel, dir, type, m, num_migrate); 1827 ret = km->migrate(sel, dir, type, m, num_migrate, k);
1843 if (!ret) 1828 if (!ret)
1844 err = ret; 1829 err = ret;
1845 } 1830 }