netns xfrm: per-netns km_waitq
Disallow spurious wakeups in __xfrm_lookup(). Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c78371441c
commit
50a30657fd
|
@ -2,6 +2,7 @@
|
||||||
#define __NETNS_XFRM_H
|
#define __NETNS_XFRM_H
|
||||||
|
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
struct netns_xfrm {
|
struct netns_xfrm {
|
||||||
|
@ -22,6 +23,8 @@ struct netns_xfrm {
|
||||||
struct work_struct state_hash_work;
|
struct work_struct state_hash_work;
|
||||||
struct hlist_head state_gc_list;
|
struct hlist_head state_gc_list;
|
||||||
struct work_struct state_gc_work;
|
struct work_struct state_gc_work;
|
||||||
|
|
||||||
|
wait_queue_head_t km_waitq;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1459,7 +1459,6 @@ extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
|
||||||
struct xfrm_kmaddress *k);
|
struct xfrm_kmaddress *k);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern wait_queue_head_t km_waitq;
|
|
||||||
extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
|
extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
|
||||||
extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid);
|
extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid);
|
||||||
extern int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
|
extern int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
|
||||||
|
|
|
@ -1411,7 +1411,7 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *
|
||||||
spin_lock_bh(&x->lock);
|
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;
|
x->km.state = XFRM_STATE_ERROR;
|
||||||
wake_up(&km_waitq);
|
wake_up(&init_net.xfrm.km_waitq);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&x->lock);
|
spin_unlock_bh(&x->lock);
|
||||||
xfrm_state_put(x);
|
xfrm_state_put(x);
|
||||||
|
|
|
@ -1691,11 +1691,11 @@ restart:
|
||||||
if (err == -EAGAIN && (flags & XFRM_LOOKUP_WAIT)) {
|
if (err == -EAGAIN && (flags & XFRM_LOOKUP_WAIT)) {
|
||||||
DECLARE_WAITQUEUE(wait, current);
|
DECLARE_WAITQUEUE(wait, current);
|
||||||
|
|
||||||
add_wait_queue(&km_waitq, &wait);
|
add_wait_queue(&init_net.xfrm.km_waitq, &wait);
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
schedule();
|
schedule();
|
||||||
set_current_state(TASK_RUNNING);
|
set_current_state(TASK_RUNNING);
|
||||||
remove_wait_queue(&km_waitq, &wait);
|
remove_wait_queue(&init_net.xfrm.km_waitq, &wait);
|
||||||
|
|
||||||
nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
|
nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
|
||||||
|
|
||||||
|
|
|
@ -170,9 +170,6 @@ out_unlock:
|
||||||
mutex_unlock(&hash_resize_mutex);
|
mutex_unlock(&hash_resize_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_WAIT_QUEUE_HEAD(km_waitq);
|
|
||||||
EXPORT_SYMBOL(km_waitq);
|
|
||||||
|
|
||||||
static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
|
static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
|
||||||
static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
|
static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
|
||||||
|
|
||||||
|
@ -399,7 +396,7 @@ static void xfrm_state_gc_task(struct work_struct *work)
|
||||||
hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
|
hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
|
||||||
xfrm_state_gc_destroy(x);
|
xfrm_state_gc_destroy(x);
|
||||||
|
|
||||||
wake_up(&km_waitq);
|
wake_up(&net->xfrm.km_waitq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long make_jiffies(long secs)
|
static inline unsigned long make_jiffies(long secs)
|
||||||
|
@ -470,7 +467,7 @@ resched:
|
||||||
expired:
|
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;
|
x->km.state = XFRM_STATE_EXPIRED;
|
||||||
wake_up(&km_waitq);
|
wake_up(&init_net.xfrm.km_waitq);
|
||||||
next = 2;
|
next = 2;
|
||||||
goto resched;
|
goto resched;
|
||||||
}
|
}
|
||||||
|
@ -638,7 +635,7 @@ restart:
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock_bh(&xfrm_state_lock);
|
spin_unlock_bh(&xfrm_state_lock);
|
||||||
wake_up(&km_waitq);
|
wake_up(&init_net.xfrm.km_waitq);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(xfrm_state_flush);
|
EXPORT_SYMBOL(xfrm_state_flush);
|
||||||
|
@ -929,7 +926,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
|
||||||
if (x->replay_maxage)
|
if (x->replay_maxage)
|
||||||
mod_timer(&x->rtimer, jiffies + x->replay_maxage);
|
mod_timer(&x->rtimer, jiffies + x->replay_maxage);
|
||||||
|
|
||||||
wake_up(&km_waitq);
|
wake_up(&init_net.xfrm.km_waitq);
|
||||||
|
|
||||||
init_net.xfrm.state_num++;
|
init_net.xfrm.state_num++;
|
||||||
|
|
||||||
|
@ -1743,7 +1740,7 @@ void km_state_expired(struct xfrm_state *x, int hard, u32 pid)
|
||||||
km_state_notify(x, &c);
|
km_state_notify(x, &c);
|
||||||
|
|
||||||
if (hard)
|
if (hard)
|
||||||
wake_up(&km_waitq);
|
wake_up(&init_net.xfrm.km_waitq);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(km_state_expired);
|
EXPORT_SYMBOL(km_state_expired);
|
||||||
|
@ -1794,7 +1791,7 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid)
|
||||||
km_policy_notify(pol, dir, &c);
|
km_policy_notify(pol, dir, &c);
|
||||||
|
|
||||||
if (hard)
|
if (hard)
|
||||||
wake_up(&km_waitq);
|
wake_up(&init_net.xfrm.km_waitq);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(km_policy_expired);
|
EXPORT_SYMBOL(km_policy_expired);
|
||||||
|
|
||||||
|
@ -2089,6 +2086,7 @@ int __net_init xfrm_state_init(struct net *net)
|
||||||
INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
|
INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize);
|
||||||
INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
|
INIT_HLIST_HEAD(&net->xfrm.state_gc_list);
|
||||||
INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
|
INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task);
|
||||||
|
init_waitqueue_head(&net->xfrm.km_waitq);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_byspi:
|
out_byspi:
|
||||||
|
|
Loading…
Reference in a new issue