diff options
| author | Steffen Klassert <steffen.klassert@secunet.com> | 2011-12-21 16:48:08 -0500 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-12-21 16:48:08 -0500 | 
| commit | c0ed1c14a72ca9ebacd51fb94a8aca488b0d361e (patch) | |
| tree | e689f7fd62e7633b9b254f9a456b65a1150c6e23 | |
| parent | 9f28a2fc0bd77511f649c0a788c7bf9a5fd04edb (diff) | |
| download | olio-linux-3.10-c0ed1c14a72ca9ebacd51fb94a8aca488b0d361e.tar.xz olio-linux-3.10-c0ed1c14a72ca9ebacd51fb94a8aca488b0d361e.zip  | |
net: Add a flow_cache_flush_deferred function
flow_cach_flush() might sleep but can be called from
atomic context via the xfrm garbage collector. So add
a flow_cache_flush_deferred() function and use this if
the xfrm garbage colector is invoked from within the
packet path.
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Acked-by: Timo Teräs <timo.teras@iki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/flow.h | 1 | ||||
| -rw-r--r-- | net/core/flow.c | 12 | ||||
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 18 | 
3 files changed, 27 insertions, 4 deletions
diff --git a/include/net/flow.h b/include/net/flow.h index a09447749e2..57f15a7f1cd 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -207,6 +207,7 @@ extern struct flow_cache_object *flow_cache_lookup(  		u8 dir, flow_resolve_t resolver, void *ctx);  extern void flow_cache_flush(void); +extern void flow_cache_flush_deferred(void);  extern atomic_t flow_cache_genid;  #endif diff --git a/net/core/flow.c b/net/core/flow.c index 8ae42de9c79..e318c7e9804 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -358,6 +358,18 @@ void flow_cache_flush(void)  	put_online_cpus();  } +static void flow_cache_flush_task(struct work_struct *work) +{ +	flow_cache_flush(); +} + +static DECLARE_WORK(flow_cache_flush_work, flow_cache_flush_task); + +void flow_cache_flush_deferred(void) +{ +	schedule_work(&flow_cache_flush_work); +} +  static int __cpuinit flow_cache_cpu_prepare(struct flow_cache *fc, int cpu)  {  	struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 2118d644663..9049a5caeb2 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2276,8 +2276,6 @@ static void __xfrm_garbage_collect(struct net *net)  {  	struct dst_entry *head, *next; -	flow_cache_flush(); -  	spin_lock_bh(&xfrm_policy_sk_bundle_lock);  	head = xfrm_policy_sk_bundles;  	xfrm_policy_sk_bundles = NULL; @@ -2290,6 +2288,18 @@ static void __xfrm_garbage_collect(struct net *net)  	}  } +static void xfrm_garbage_collect(struct net *net) +{ +	flow_cache_flush(); +	__xfrm_garbage_collect(net); +} + +static void xfrm_garbage_collect_deferred(struct net *net) +{ +	flow_cache_flush_deferred(); +	__xfrm_garbage_collect(net); +} +  static void xfrm_init_pmtu(struct dst_entry *dst)  {  	do { @@ -2422,7 +2432,7 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)  		if (likely(dst_ops->neigh_lookup == NULL))  			dst_ops->neigh_lookup = xfrm_neigh_lookup;  		if (likely(afinfo->garbage_collect == NULL)) -			afinfo->garbage_collect = __xfrm_garbage_collect; +			afinfo->garbage_collect = xfrm_garbage_collect_deferred;  		xfrm_policy_afinfo[afinfo->family] = afinfo;  	}  	write_unlock_bh(&xfrm_policy_afinfo_lock); @@ -2516,7 +2526,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void  	switch (event) {  	case NETDEV_DOWN: -		__xfrm_garbage_collect(dev_net(dev)); +		xfrm_garbage_collect(dev_net(dev));  	}  	return NOTIFY_DONE;  }  |