aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r--net/xfrm/xfrm_state.c109
1 files changed, 36 insertions, 73 deletions
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