diff options
author | Simon Horman <horms@verge.net.au> | 2008-10-06 17:40:11 -0400 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2008-10-06 17:40:11 -0400 |
commit | a5e8546a8bff5d2047adc279df5753c44ba7b1a1 (patch) | |
tree | d9ca91f74d8279adbb1d3e942cc7ab145780ee29 /net/xfrm/xfrm_state.c | |
parent | cb7f6a7b716e801097b564dec3ccb58d330aef56 (diff) | |
parent | c7004482e8dcb7c3c72666395cfa98a216a4fb70 (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.c | 109 |
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; | |||
59 | static unsigned int xfrm_state_num; | 59 | static unsigned int xfrm_state_num; |
60 | static unsigned int xfrm_state_genid; | 60 | static unsigned int xfrm_state_genid; |
61 | 61 | ||
62 | /* Counter indicating ongoing walk, protected by xfrm_state_lock. */ | ||
63 | static unsigned long xfrm_state_walk_ongoing; | ||
64 | /* Counter indicating walk completion, protected by xfrm_cfg_mutex. */ | ||
65 | static unsigned long xfrm_state_walk_completed; | ||
66 | |||
67 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | 62 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); |
68 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 63 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
69 | 64 | ||
@@ -196,8 +191,7 @@ static DEFINE_RWLOCK(xfrm_state_afinfo_lock); | |||
196 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; | 191 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; |
197 | 192 | ||
198 | static struct work_struct xfrm_state_gc_work; | 193 | static struct work_struct xfrm_state_gc_work; |
199 | static LIST_HEAD(xfrm_state_gc_leftovers); | 194 | static HLIST_HEAD(xfrm_state_gc_list); |
200 | static LIST_HEAD(xfrm_state_gc_list); | ||
201 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); | 195 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); |
202 | 196 | ||
203 | int __xfrm_state_delete(struct xfrm_state *x); | 197 | int __xfrm_state_delete(struct xfrm_state *x); |
@@ -409,23 +403,16 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
409 | 403 | ||
410 | static void xfrm_state_gc_task(struct work_struct *data) | 404 | static 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); | ||
1600 | out: | 1582 | out: |
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 | } |
1610 | EXPORT_SYMBOL(xfrm_state_walk); | 1586 | EXPORT_SYMBOL(xfrm_state_walk); |
1611 | 1587 | ||
1588 | void 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 | } | ||
1595 | EXPORT_SYMBOL(xfrm_state_walk_init); | ||
1596 | |||
1612 | void xfrm_state_walk_done(struct xfrm_state_walk *walk) | 1597 | void 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 | } |
1622 | EXPORT_SYMBOL(xfrm_state_walk_done); | 1606 | EXPORT_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 |
1832 | int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1816 | int 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 | } |