Skip to content

Commit

Permalink
xfrm: Remove ancient sleeping when the SA is in acquire state
Browse files Browse the repository at this point in the history
We now queue packets to the policy if the states are not yet resolved,
this replaces the ancient sleeping code. Also the sleeping can cause
indefinite task hangs if the needed state does not get resolved.

Signed-off-by: Steffen Klassert <[email protected]>
  • Loading branch information
klassert committed Dec 6, 2013
1 parent 283bc9f commit 5b8ef34
Show file tree
Hide file tree
Showing 4 changed files with 5 additions and 44 deletions.
2 changes: 0 additions & 2 deletions include/net/netns/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ struct netns_xfrm {
struct hlist_head state_gc_list;
struct work_struct state_gc_work;

wait_queue_head_t km_waitq;

struct list_head policy_all;
struct hlist_head *policy_byidx;
unsigned int policy_idx_hmask;
Expand Down
5 changes: 2 additions & 3 deletions net/key/af_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -1380,10 +1380,9 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, const struct sadb
return 0;

spin_lock_bh(&x->lock);
if (x->km.state == XFRM_STATE_ACQ) {
if (x->km.state == XFRM_STATE_ACQ)
x->km.state = XFRM_STATE_ERROR;
wake_up(&net->xfrm.km_waitq);
}

spin_unlock_bh(&x->lock);
xfrm_state_put(x);
return 0;
Expand Down
21 changes: 2 additions & 19 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -1901,8 +1901,7 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
if (IS_ERR(xdst))
return xdst;

if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0 ||
(fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP))
if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0)
return xdst;

dst1 = &xdst->u.dst;
Expand Down Expand Up @@ -2077,7 +2076,6 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
int i, err, num_pols, num_xfrms = 0, drop_pols = 0;

restart:
dst = NULL;
xdst = NULL;
route = NULL;
Expand Down Expand Up @@ -2157,23 +2155,8 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,

return make_blackhole(net, family, dst_orig);
}
if (fl->flowi_flags & FLOWI_FLAG_CAN_SLEEP) {
DECLARE_WAITQUEUE(wait, current);

add_wait_queue(&net->xfrm.km_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
set_current_state(TASK_RUNNING);
remove_wait_queue(&net->xfrm.km_waitq, &wait);

if (!signal_pending(current)) {
dst_release(dst);
goto restart;
}

err = -ERESTART;
} else
err = -EAGAIN;
err = -EAGAIN;

XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
goto error;
Expand Down
21 changes: 1 addition & 20 deletions net/xfrm/xfrm_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,6 @@ static void xfrm_state_gc_task(struct work_struct *work)

hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
xfrm_state_gc_destroy(x);

wake_up(&net->xfrm.km_waitq);
}

static inline unsigned long make_jiffies(long secs)
Expand All @@ -388,7 +386,6 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
{
struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer);
struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer);
struct net *net = xs_net(x);
unsigned long now = get_seconds();
long next = LONG_MAX;
int warn = 0;
Expand Down Expand Up @@ -458,12 +455,8 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
goto out;

expired:
if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) {
if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0)
x->km.state = XFRM_STATE_EXPIRED;
wake_up(&net->xfrm.km_waitq);
next = 2;
goto resched;
}

err = __xfrm_state_delete(x);
if (!err)
Expand Down Expand Up @@ -635,7 +628,6 @@ int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info)

out:
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
wake_up(&net->xfrm.km_waitq);
return err;
}
EXPORT_SYMBOL(xfrm_state_flush);
Expand Down Expand Up @@ -948,8 +940,6 @@ static void __xfrm_state_insert(struct xfrm_state *x)
if (x->replay_maxage)
mod_timer(&x->rtimer, jiffies + x->replay_maxage);

wake_up(&net->xfrm.km_waitq);

net->xfrm.state_num++;

xfrm_hash_grow_check(net, x->bydst.next != NULL);
Expand Down Expand Up @@ -1658,16 +1648,12 @@ EXPORT_SYMBOL(km_state_notify);

void km_state_expired(struct xfrm_state *x, int hard, u32 portid)
{
struct net *net = xs_net(x);
struct km_event c;

c.data.hard = hard;
c.portid = portid;
c.event = XFRM_MSG_EXPIRE;
km_state_notify(x, &c);

if (hard)
wake_up(&net->xfrm.km_waitq);
}

EXPORT_SYMBOL(km_state_expired);
Expand Down Expand Up @@ -1710,16 +1696,12 @@ EXPORT_SYMBOL(km_new_mapping);

void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid)
{
struct net *net = xp_net(pol);
struct km_event c;

c.data.hard = hard;
c.portid = portid;
c.event = XFRM_MSG_POLEXPIRE;
km_policy_notify(pol, dir, &c);

if (hard)
wake_up(&net->xfrm.km_waitq);
}
EXPORT_SYMBOL(km_policy_expired);

Expand Down Expand Up @@ -2028,7 +2010,6 @@ int __net_init xfrm_state_init(struct net *net)
INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
init_waitqueue_head(&net->xfrm.km_waitq);
spin_lock_init(&net->xfrm.xfrm_state_lock);
return 0;

Expand Down

0 comments on commit 5b8ef34

Please sign in to comment.