|  | Subject: net: netfilter: Serialize xt_write_recseq sections on RT | 
|  | From: Thomas Gleixner <tglx@linutronix.de> | 
|  | Date: Sun, 28 Oct 2012 11:18:08 +0100 | 
|  |  | 
|  | The netfilter code relies only on the implicit semantics of | 
|  | local_bh_disable() for serializing wt_write_recseq sections. RT breaks | 
|  | that and needs explicit serialization here. | 
|  |  | 
|  | Reported-by: Peter LaDow <petela@gocougs.wsu.edu> | 
|  | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | 
|  |  | 
|  | --- | 
|  | include/linux/netfilter/x_tables.h |    7 +++++++ | 
|  | net/netfilter/core.c               |    6 ++++++ | 
|  | 2 files changed, 13 insertions(+) | 
|  |  | 
|  | --- a/include/linux/netfilter/x_tables.h | 
|  | +++ b/include/linux/netfilter/x_tables.h | 
|  | @@ -6,6 +6,7 @@ | 
|  | #include <linux/netdevice.h> | 
|  | #include <linux/static_key.h> | 
|  | #include <linux/netfilter.h> | 
|  | +#include <linux/locallock.h> | 
|  | #include <uapi/linux/netfilter/x_tables.h> | 
|  |  | 
|  | /* Test a struct->invflags and a boolean for inequality */ | 
|  | @@ -343,6 +344,8 @@ void xt_free_table_info(struct xt_table_ | 
|  | */ | 
|  | DECLARE_PER_CPU(seqcount_t, xt_recseq); | 
|  |  | 
|  | +DECLARE_LOCAL_IRQ_LOCK(xt_write_lock); | 
|  | + | 
|  | /* xt_tee_enabled - true if x_tables needs to handle reentrancy | 
|  | * | 
|  | * Enabled if current ip(6)tables ruleset has at least one -j TEE rule. | 
|  | @@ -363,6 +366,9 @@ static inline unsigned int xt_write_recs | 
|  | { | 
|  | unsigned int addend; | 
|  |  | 
|  | +	/* RT protection */ | 
|  | +	local_lock(xt_write_lock); | 
|  | + | 
|  | /* | 
|  | * Low order bit of sequence is set if we already | 
|  | * called xt_write_recseq_begin(). | 
|  | @@ -393,6 +399,7 @@ static inline void xt_write_recseq_end(u | 
|  | /* this is kind of a write_seqcount_end(), but addend is 0 or 1 */ | 
|  | smp_wmb(); | 
|  | __this_cpu_add(xt_recseq.sequence, addend); | 
|  | +	local_unlock(xt_write_lock); | 
|  | } | 
|  |  | 
|  | /* | 
|  | --- a/net/netfilter/core.c | 
|  | +++ b/net/netfilter/core.c | 
|  | @@ -20,6 +20,7 @@ | 
|  | #include <linux/inetdevice.h> | 
|  | #include <linux/proc_fs.h> | 
|  | #include <linux/mutex.h> | 
|  | +#include <linux/locallock.h> | 
|  | #include <linux/mm.h> | 
|  | #include <linux/rcupdate.h> | 
|  | #include <net/net_namespace.h> | 
|  | @@ -27,6 +28,11 @@ | 
|  |  | 
|  | #include "nf_internals.h" | 
|  |  | 
|  | +#ifdef CONFIG_PREEMPT_RT_BASE | 
|  | +DEFINE_LOCAL_IRQ_LOCK(xt_write_lock); | 
|  | +EXPORT_PER_CPU_SYMBOL(xt_write_lock); | 
|  | +#endif | 
|  | + | 
|  | const struct nf_ipv6_ops __rcu *nf_ipv6_ops __read_mostly; | 
|  | EXPORT_SYMBOL_GPL(nf_ipv6_ops); | 
|  |  |