diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-06-03 04:32:06 -0400 |
---|---|---|
committer | pablo <pablo@1984.(none)> | 2009-06-03 04:32:06 -0400 |
commit | e34d5c1a4f9919a81b4ea4591d7383245f35cb8e (patch) | |
tree | 0a19bfe3e162b2b8de9b9414dcc2bef0a07e7133 /include/net | |
parent | 17e6e4eac070607a35464ea7e2c5eceac32e5eca (diff) |
netfilter: conntrack: replace notify chain by function pointer
This patch removes the notify chain infrastructure and replace it
by a simple function pointer. This issue has been mentioned in the
mailing list several times: the use of the notify chain adds
too much overhead for something that is only used by ctnetlink.
This patch also changes nfnetlink_send(). It seems that gfp_any()
returns GFP_KERNEL for user-context request, like those via
ctnetlink, inside the RCU read-side section which is not valid.
Using GFP_KERNEL is also evil since netlink may schedule(),
this leads to "scheduling while atomic" bug reports.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'include/net')
-rw-r--r-- | include/net/netfilter/nf_conntrack_ecache.h | 68 |
1 files changed, 48 insertions, 20 deletions
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 2e17a2d0eb3b..1afb907e015a 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h | |||
@@ -6,7 +6,6 @@ | |||
6 | #define _NF_CONNTRACK_ECACHE_H | 6 | #define _NF_CONNTRACK_ECACHE_H |
7 | #include <net/netfilter/nf_conntrack.h> | 7 | #include <net/netfilter/nf_conntrack.h> |
8 | 8 | ||
9 | #include <linux/notifier.h> | ||
10 | #include <linux/interrupt.h> | 9 | #include <linux/interrupt.h> |
11 | #include <net/net_namespace.h> | 10 | #include <net/net_namespace.h> |
12 | #include <net/netfilter/nf_conntrack_expect.h> | 11 | #include <net/netfilter/nf_conntrack_expect.h> |
@@ -69,9 +68,13 @@ struct nf_ct_event { | |||
69 | int report; | 68 | int report; |
70 | }; | 69 | }; |
71 | 70 | ||
72 | extern struct atomic_notifier_head nf_conntrack_chain; | 71 | struct nf_ct_event_notifier { |
73 | extern int nf_conntrack_register_notifier(struct notifier_block *nb); | 72 | int (*fcn)(unsigned int events, struct nf_ct_event *item); |
74 | extern int nf_conntrack_unregister_notifier(struct notifier_block *nb); | 73 | }; |
74 | |||
75 | extern struct nf_ct_event_notifier *nf_conntrack_event_cb; | ||
76 | extern int nf_conntrack_register_notifier(struct nf_ct_event_notifier *nb); | ||
77 | extern void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *nb); | ||
75 | 78 | ||
76 | extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); | 79 | extern void nf_ct_deliver_cached_events(const struct nf_conn *ct); |
77 | extern void __nf_ct_event_cache_init(struct nf_conn *ct); | 80 | extern void __nf_ct_event_cache_init(struct nf_conn *ct); |
@@ -97,13 +100,23 @@ nf_conntrack_event_report(enum ip_conntrack_events event, | |||
97 | u32 pid, | 100 | u32 pid, |
98 | int report) | 101 | int report) |
99 | { | 102 | { |
100 | struct nf_ct_event item = { | 103 | struct nf_ct_event_notifier *notify; |
101 | .ct = ct, | 104 | |
102 | .pid = pid, | 105 | rcu_read_lock(); |
103 | .report = report | 106 | notify = rcu_dereference(nf_conntrack_event_cb); |
104 | }; | 107 | if (notify == NULL) |
105 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) | 108 | goto out_unlock; |
106 | atomic_notifier_call_chain(&nf_conntrack_chain, event, &item); | 109 | |
110 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { | ||
111 | struct nf_ct_event item = { | ||
112 | .ct = ct, | ||
113 | .pid = pid, | ||
114 | .report = report | ||
115 | }; | ||
116 | notify->fcn(event, &item); | ||
117 | } | ||
118 | out_unlock: | ||
119 | rcu_read_unlock(); | ||
107 | } | 120 | } |
108 | 121 | ||
109 | static inline void | 122 | static inline void |
@@ -118,9 +131,13 @@ struct nf_exp_event { | |||
118 | int report; | 131 | int report; |
119 | }; | 132 | }; |
120 | 133 | ||
121 | extern struct atomic_notifier_head nf_ct_expect_chain; | 134 | struct nf_exp_event_notifier { |
122 | extern int nf_ct_expect_register_notifier(struct notifier_block *nb); | 135 | int (*fcn)(unsigned int events, struct nf_exp_event *item); |
123 | extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb); | 136 | }; |
137 | |||
138 | extern struct nf_exp_event_notifier *nf_expect_event_cb; | ||
139 | extern int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *nb); | ||
140 | extern void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *nb); | ||
124 | 141 | ||
125 | static inline void | 142 | static inline void |
126 | nf_ct_expect_event_report(enum ip_conntrack_expect_events event, | 143 | nf_ct_expect_event_report(enum ip_conntrack_expect_events event, |
@@ -128,12 +145,23 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event, | |||
128 | u32 pid, | 145 | u32 pid, |
129 | int report) | 146 | int report) |
130 | { | 147 | { |
131 | struct nf_exp_event item = { | 148 | struct nf_exp_event_notifier *notify; |
132 | .exp = exp, | 149 | |
133 | .pid = pid, | 150 | rcu_read_lock(); |
134 | .report = report | 151 | notify = rcu_dereference(nf_expect_event_cb); |
135 | }; | 152 | if (notify == NULL) |
136 | atomic_notifier_call_chain(&nf_ct_expect_chain, event, &item); | 153 | goto out_unlock; |
154 | |||
155 | { | ||
156 | struct nf_exp_event item = { | ||
157 | .exp = exp, | ||
158 | .pid = pid, | ||
159 | .report = report | ||
160 | }; | ||
161 | notify->fcn(event, &item); | ||
162 | } | ||
163 | out_unlock: | ||
164 | rcu_read_unlock(); | ||
137 | } | 165 | } |
138 | 166 | ||
139 | static inline void | 167 | static inline void |