diff options
author | Tom Herbert <tom@herbertland.com> | 2016-03-07 17:11:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-09 16:36:14 -0500 |
commit | cd6e111bf5be5c70aef96a86d791ee7be0c0e137 (patch) | |
tree | 6fcfcb85e5838ef670558ad548e27458b0df42f0 | |
parent | ab7ac4eb9832e32a09f4e8042705484d2fb0aad3 (diff) |
kcm: Add statistics and proc interfaces
This patch adds various counters for KCM. These include counters for
messages and bytes received or sent, as well as counters for number of
attached/unattached TCP sockets and other error or edge events.
The statistics are exposed via a proc interface. /proc/net/kcm provides
statistics per KCM socket and per psock (attached TCP sockets).
/proc/net/kcm_stats provides aggregate statistics.
Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/kcm.h | 94 | ||||
-rw-r--r-- | net/kcm/Makefile | 2 | ||||
-rw-r--r-- | net/kcm/kcmproc.c | 422 | ||||
-rw-r--r-- | net/kcm/kcmsock.c | 80 |
4 files changed, 597 insertions, 1 deletions
diff --git a/include/net/kcm.h b/include/net/kcm.h index 1bcae39070ec..39c7abe98552 100644 --- a/include/net/kcm.h +++ b/include/net/kcm.h | |||
@@ -17,6 +17,42 @@ | |||
17 | 17 | ||
18 | extern unsigned int kcm_net_id; | 18 | extern unsigned int kcm_net_id; |
19 | 19 | ||
20 | #define KCM_STATS_ADD(stat, count) ((stat) += (count)) | ||
21 | #define KCM_STATS_INCR(stat) ((stat)++) | ||
22 | |||
23 | struct kcm_psock_stats { | ||
24 | unsigned long long rx_msgs; | ||
25 | unsigned long long rx_bytes; | ||
26 | unsigned long long tx_msgs; | ||
27 | unsigned long long tx_bytes; | ||
28 | unsigned int rx_aborts; | ||
29 | unsigned int rx_mem_fail; | ||
30 | unsigned int rx_need_more_hdr; | ||
31 | unsigned int rx_bad_hdr_len; | ||
32 | unsigned long long reserved; | ||
33 | unsigned long long unreserved; | ||
34 | unsigned int tx_aborts; | ||
35 | }; | ||
36 | |||
37 | struct kcm_mux_stats { | ||
38 | unsigned long long rx_msgs; | ||
39 | unsigned long long rx_bytes; | ||
40 | unsigned long long tx_msgs; | ||
41 | unsigned long long tx_bytes; | ||
42 | unsigned int rx_ready_drops; | ||
43 | unsigned int tx_retries; | ||
44 | unsigned int psock_attach; | ||
45 | unsigned int psock_unattach_rsvd; | ||
46 | unsigned int psock_unattach; | ||
47 | }; | ||
48 | |||
49 | struct kcm_stats { | ||
50 | unsigned long long rx_msgs; | ||
51 | unsigned long long rx_bytes; | ||
52 | unsigned long long tx_msgs; | ||
53 | unsigned long long tx_bytes; | ||
54 | }; | ||
55 | |||
20 | struct kcm_tx_msg { | 56 | struct kcm_tx_msg { |
21 | unsigned int sent; | 57 | unsigned int sent; |
22 | unsigned int fragidx; | 58 | unsigned int fragidx; |
@@ -41,6 +77,8 @@ struct kcm_sock { | |||
41 | u32 done : 1; | 77 | u32 done : 1; |
42 | struct work_struct done_work; | 78 | struct work_struct done_work; |
43 | 79 | ||
80 | struct kcm_stats stats; | ||
81 | |||
44 | /* Transmit */ | 82 | /* Transmit */ |
45 | struct kcm_psock *tx_psock; | 83 | struct kcm_psock *tx_psock; |
46 | struct work_struct tx_work; | 84 | struct work_struct tx_work; |
@@ -77,6 +115,8 @@ struct kcm_psock { | |||
77 | 115 | ||
78 | struct list_head psock_list; | 116 | struct list_head psock_list; |
79 | 117 | ||
118 | struct kcm_psock_stats stats; | ||
119 | |||
80 | /* Receive */ | 120 | /* Receive */ |
81 | struct sk_buff *rx_skb_head; | 121 | struct sk_buff *rx_skb_head; |
82 | struct sk_buff **rx_skb_nextp; | 122 | struct sk_buff **rx_skb_nextp; |
@@ -86,15 +126,21 @@ struct kcm_psock { | |||
86 | struct delayed_work rx_delayed_work; | 126 | struct delayed_work rx_delayed_work; |
87 | struct bpf_prog *bpf_prog; | 127 | struct bpf_prog *bpf_prog; |
88 | struct kcm_sock *rx_kcm; | 128 | struct kcm_sock *rx_kcm; |
129 | unsigned long long saved_rx_bytes; | ||
130 | unsigned long long saved_rx_msgs; | ||
89 | 131 | ||
90 | /* Transmit */ | 132 | /* Transmit */ |
91 | struct kcm_sock *tx_kcm; | 133 | struct kcm_sock *tx_kcm; |
92 | struct list_head psock_avail_list; | 134 | struct list_head psock_avail_list; |
135 | unsigned long long saved_tx_bytes; | ||
136 | unsigned long long saved_tx_msgs; | ||
93 | }; | 137 | }; |
94 | 138 | ||
95 | /* Per net MUX list */ | 139 | /* Per net MUX list */ |
96 | struct kcm_net { | 140 | struct kcm_net { |
97 | struct mutex mutex; | 141 | struct mutex mutex; |
142 | struct kcm_psock_stats aggregate_psock_stats; | ||
143 | struct kcm_mux_stats aggregate_mux_stats; | ||
98 | struct list_head mux_list; | 144 | struct list_head mux_list; |
99 | int count; | 145 | int count; |
100 | }; | 146 | }; |
@@ -110,6 +156,9 @@ struct kcm_mux { | |||
110 | struct list_head psocks; /* List of all psocks on MUX */ | 156 | struct list_head psocks; /* List of all psocks on MUX */ |
111 | int psocks_cnt; /* Total attached sockets */ | 157 | int psocks_cnt; /* Total attached sockets */ |
112 | 158 | ||
159 | struct kcm_mux_stats stats; | ||
160 | struct kcm_psock_stats aggregate_psock_stats; | ||
161 | |||
113 | /* Receive */ | 162 | /* Receive */ |
114 | spinlock_t rx_lock ____cacheline_aligned_in_smp; | 163 | spinlock_t rx_lock ____cacheline_aligned_in_smp; |
115 | struct list_head kcm_rx_waiters; /* KCMs waiting for receiving */ | 164 | struct list_head kcm_rx_waiters; /* KCMs waiting for receiving */ |
@@ -122,4 +171,49 @@ struct kcm_mux { | |||
122 | struct list_head kcm_tx_waiters; /* KCMs waiting for a TX psock */ | 171 | struct list_head kcm_tx_waiters; /* KCMs waiting for a TX psock */ |
123 | }; | 172 | }; |
124 | 173 | ||
174 | #ifdef CONFIG_PROC_FS | ||
175 | int kcm_proc_init(void); | ||
176 | void kcm_proc_exit(void); | ||
177 | #else | ||
178 | static int kcm_proc_init(void) { return 0; } | ||
179 | static void kcm_proc_exit(void) { } | ||
180 | #endif | ||
181 | |||
182 | static inline void aggregate_psock_stats(struct kcm_psock_stats *stats, | ||
183 | struct kcm_psock_stats *agg_stats) | ||
184 | { | ||
185 | /* Save psock statistics in the mux when psock is being unattached. */ | ||
186 | |||
187 | #define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat) | ||
188 | SAVE_PSOCK_STATS(rx_msgs); | ||
189 | SAVE_PSOCK_STATS(rx_bytes); | ||
190 | SAVE_PSOCK_STATS(rx_aborts); | ||
191 | SAVE_PSOCK_STATS(rx_mem_fail); | ||
192 | SAVE_PSOCK_STATS(rx_need_more_hdr); | ||
193 | SAVE_PSOCK_STATS(rx_bad_hdr_len); | ||
194 | SAVE_PSOCK_STATS(tx_msgs); | ||
195 | SAVE_PSOCK_STATS(tx_bytes); | ||
196 | SAVE_PSOCK_STATS(reserved); | ||
197 | SAVE_PSOCK_STATS(unreserved); | ||
198 | SAVE_PSOCK_STATS(tx_aborts); | ||
199 | #undef SAVE_PSOCK_STATS | ||
200 | } | ||
201 | |||
202 | static inline void aggregate_mux_stats(struct kcm_mux_stats *stats, | ||
203 | struct kcm_mux_stats *agg_stats) | ||
204 | { | ||
205 | /* Save psock statistics in the mux when psock is being unattached. */ | ||
206 | |||
207 | #define SAVE_MUX_STATS(_stat) (agg_stats->_stat += stats->_stat) | ||
208 | SAVE_MUX_STATS(rx_msgs); | ||
209 | SAVE_MUX_STATS(rx_bytes); | ||
210 | SAVE_MUX_STATS(tx_msgs); | ||
211 | SAVE_MUX_STATS(tx_bytes); | ||
212 | SAVE_MUX_STATS(rx_ready_drops); | ||
213 | SAVE_MUX_STATS(psock_attach); | ||
214 | SAVE_MUX_STATS(psock_unattach_rsvd); | ||
215 | SAVE_MUX_STATS(psock_unattach); | ||
216 | #undef SAVE_MUX_STATS | ||
217 | } | ||
218 | |||
125 | #endif /* __NET_KCM_H_ */ | 219 | #endif /* __NET_KCM_H_ */ |
diff --git a/net/kcm/Makefile b/net/kcm/Makefile index cb525f7c5a13..71256133e677 100644 --- a/net/kcm/Makefile +++ b/net/kcm/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | obj-$(CONFIG_AF_KCM) += kcm.o | 1 | obj-$(CONFIG_AF_KCM) += kcm.o |
2 | 2 | ||
3 | kcm-y := kcmsock.o | 3 | kcm-y := kcmsock.o kcmproc.o |
diff --git a/net/kcm/kcmproc.c b/net/kcm/kcmproc.c new file mode 100644 index 000000000000..5eb9809c0f59 --- /dev/null +++ b/net/kcm/kcmproc.c | |||
@@ -0,0 +1,422 @@ | |||
1 | #include <linux/in.h> | ||
2 | #include <linux/inet.h> | ||
3 | #include <linux/list.h> | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/net.h> | ||
6 | #include <linux/proc_fs.h> | ||
7 | #include <linux/rculist.h> | ||
8 | #include <linux/seq_file.h> | ||
9 | #include <linux/socket.h> | ||
10 | #include <net/inet_sock.h> | ||
11 | #include <net/kcm.h> | ||
12 | #include <net/net_namespace.h> | ||
13 | #include <net/netns/generic.h> | ||
14 | #include <net/tcp.h> | ||
15 | |||
16 | #ifdef CONFIG_PROC_FS | ||
17 | struct kcm_seq_muxinfo { | ||
18 | char *name; | ||
19 | const struct file_operations *seq_fops; | ||
20 | const struct seq_operations seq_ops; | ||
21 | }; | ||
22 | |||
23 | static struct kcm_mux *kcm_get_first(struct seq_file *seq) | ||
24 | { | ||
25 | struct net *net = seq_file_net(seq); | ||
26 | struct kcm_net *knet = net_generic(net, kcm_net_id); | ||
27 | |||
28 | return list_first_or_null_rcu(&knet->mux_list, | ||
29 | struct kcm_mux, kcm_mux_list); | ||
30 | } | ||
31 | |||
32 | static struct kcm_mux *kcm_get_next(struct kcm_mux *mux) | ||
33 | { | ||
34 | struct kcm_net *knet = mux->knet; | ||
35 | |||
36 | return list_next_or_null_rcu(&knet->mux_list, &mux->kcm_mux_list, | ||
37 | struct kcm_mux, kcm_mux_list); | ||
38 | } | ||
39 | |||
40 | static struct kcm_mux *kcm_get_idx(struct seq_file *seq, loff_t pos) | ||
41 | { | ||
42 | struct net *net = seq_file_net(seq); | ||
43 | struct kcm_net *knet = net_generic(net, kcm_net_id); | ||
44 | struct kcm_mux *m; | ||
45 | |||
46 | list_for_each_entry_rcu(m, &knet->mux_list, kcm_mux_list) { | ||
47 | if (!pos) | ||
48 | return m; | ||
49 | --pos; | ||
50 | } | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | static void *kcm_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
55 | { | ||
56 | void *p; | ||
57 | |||
58 | if (v == SEQ_START_TOKEN) | ||
59 | p = kcm_get_first(seq); | ||
60 | else | ||
61 | p = kcm_get_next(v); | ||
62 | ++*pos; | ||
63 | return p; | ||
64 | } | ||
65 | |||
66 | static void *kcm_seq_start(struct seq_file *seq, loff_t *pos) | ||
67 | __acquires(rcu) | ||
68 | { | ||
69 | rcu_read_lock(); | ||
70 | |||
71 | if (!*pos) | ||
72 | return SEQ_START_TOKEN; | ||
73 | else | ||
74 | return kcm_get_idx(seq, *pos - 1); | ||
75 | } | ||
76 | |||
77 | static void kcm_seq_stop(struct seq_file *seq, void *v) | ||
78 | __releases(rcu) | ||
79 | { | ||
80 | rcu_read_unlock(); | ||
81 | } | ||
82 | |||
83 | struct kcm_proc_mux_state { | ||
84 | struct seq_net_private p; | ||
85 | int idx; | ||
86 | }; | ||
87 | |||
88 | static int kcm_seq_open(struct inode *inode, struct file *file) | ||
89 | { | ||
90 | struct kcm_seq_muxinfo *muxinfo = PDE_DATA(inode); | ||
91 | int err; | ||
92 | |||
93 | err = seq_open_net(inode, file, &muxinfo->seq_ops, | ||
94 | sizeof(struct kcm_proc_mux_state)); | ||
95 | if (err < 0) | ||
96 | return err; | ||
97 | return err; | ||
98 | } | ||
99 | |||
100 | static void kcm_format_mux_header(struct seq_file *seq) | ||
101 | { | ||
102 | struct net *net = seq_file_net(seq); | ||
103 | struct kcm_net *knet = net_generic(net, kcm_net_id); | ||
104 | |||
105 | seq_printf(seq, | ||
106 | "*** KCM statistics (%d MUX) ****\n", | ||
107 | knet->count); | ||
108 | |||
109 | seq_printf(seq, | ||
110 | "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s", | ||
111 | "Object", | ||
112 | "RX-Msgs", | ||
113 | "RX-Bytes", | ||
114 | "TX-Msgs", | ||
115 | "TX-Bytes", | ||
116 | "Recv-Q", | ||
117 | "Rmem", | ||
118 | "Send-Q", | ||
119 | "Smem", | ||
120 | "Status"); | ||
121 | |||
122 | /* XXX: pdsts header stuff here */ | ||
123 | seq_puts(seq, "\n"); | ||
124 | } | ||
125 | |||
126 | static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq, | ||
127 | int i, int *len) | ||
128 | { | ||
129 | seq_printf(seq, | ||
130 | " kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ", | ||
131 | kcm->index, | ||
132 | kcm->stats.rx_msgs, | ||
133 | kcm->stats.rx_bytes, | ||
134 | kcm->stats.tx_msgs, | ||
135 | kcm->stats.tx_bytes, | ||
136 | kcm->sk.sk_receive_queue.qlen, | ||
137 | sk_rmem_alloc_get(&kcm->sk), | ||
138 | kcm->sk.sk_write_queue.qlen, | ||
139 | "-"); | ||
140 | |||
141 | if (kcm->tx_psock) | ||
142 | seq_printf(seq, "Psck-%u ", kcm->tx_psock->index); | ||
143 | |||
144 | if (kcm->tx_wait) | ||
145 | seq_puts(seq, "TxWait "); | ||
146 | |||
147 | if (kcm->tx_wait_more) | ||
148 | seq_puts(seq, "WMore "); | ||
149 | |||
150 | if (kcm->rx_wait) | ||
151 | seq_puts(seq, "RxWait "); | ||
152 | |||
153 | seq_puts(seq, "\n"); | ||
154 | } | ||
155 | |||
156 | static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq, | ||
157 | int i, int *len) | ||
158 | { | ||
159 | seq_printf(seq, | ||
160 | " psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ", | ||
161 | psock->index, | ||
162 | psock->stats.rx_msgs, | ||
163 | psock->stats.rx_bytes, | ||
164 | psock->stats.tx_msgs, | ||
165 | psock->stats.tx_bytes, | ||
166 | psock->sk->sk_receive_queue.qlen, | ||
167 | atomic_read(&psock->sk->sk_rmem_alloc), | ||
168 | psock->sk->sk_write_queue.qlen, | ||
169 | atomic_read(&psock->sk->sk_wmem_alloc)); | ||
170 | |||
171 | if (psock->done) | ||
172 | seq_puts(seq, "Done "); | ||
173 | |||
174 | if (psock->tx_stopped) | ||
175 | seq_puts(seq, "TxStop "); | ||
176 | |||
177 | if (psock->rx_stopped) | ||
178 | seq_puts(seq, "RxStop "); | ||
179 | |||
180 | if (psock->tx_kcm) | ||
181 | seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index); | ||
182 | |||
183 | if (psock->ready_rx_msg) | ||
184 | seq_puts(seq, "RdyRx "); | ||
185 | |||
186 | seq_puts(seq, "\n"); | ||
187 | } | ||
188 | |||
189 | static void | ||
190 | kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq) | ||
191 | { | ||
192 | int i, len; | ||
193 | struct kcm_sock *kcm; | ||
194 | struct kcm_psock *psock; | ||
195 | |||
196 | /* mux information */ | ||
197 | seq_printf(seq, | ||
198 | "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ", | ||
199 | "mux", "", | ||
200 | mux->stats.rx_msgs, | ||
201 | mux->stats.rx_bytes, | ||
202 | mux->stats.tx_msgs, | ||
203 | mux->stats.tx_bytes, | ||
204 | "-", "-", "-", "-"); | ||
205 | |||
206 | seq_printf(seq, "KCMs: %d, Psocks %d\n", | ||
207 | mux->kcm_socks_cnt, mux->psocks_cnt); | ||
208 | |||
209 | /* kcm sock information */ | ||
210 | i = 0; | ||
211 | spin_lock_bh(&mux->lock); | ||
212 | list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) { | ||
213 | kcm_format_sock(kcm, seq, i, &len); | ||
214 | i++; | ||
215 | } | ||
216 | i = 0; | ||
217 | list_for_each_entry(psock, &mux->psocks, psock_list) { | ||
218 | kcm_format_psock(psock, seq, i, &len); | ||
219 | i++; | ||
220 | } | ||
221 | spin_unlock_bh(&mux->lock); | ||
222 | } | ||
223 | |||
224 | static int kcm_seq_show(struct seq_file *seq, void *v) | ||
225 | { | ||
226 | struct kcm_proc_mux_state *mux_state; | ||
227 | |||
228 | mux_state = seq->private; | ||
229 | if (v == SEQ_START_TOKEN) { | ||
230 | mux_state->idx = 0; | ||
231 | kcm_format_mux_header(seq); | ||
232 | } else { | ||
233 | kcm_format_mux(v, mux_state->idx, seq); | ||
234 | mux_state->idx++; | ||
235 | } | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static const struct file_operations kcm_seq_fops = { | ||
240 | .owner = THIS_MODULE, | ||
241 | .open = kcm_seq_open, | ||
242 | .read = seq_read, | ||
243 | .llseek = seq_lseek, | ||
244 | }; | ||
245 | |||
246 | static struct kcm_seq_muxinfo kcm_seq_muxinfo = { | ||
247 | .name = "kcm", | ||
248 | .seq_fops = &kcm_seq_fops, | ||
249 | .seq_ops = { | ||
250 | .show = kcm_seq_show, | ||
251 | .start = kcm_seq_start, | ||
252 | .next = kcm_seq_next, | ||
253 | .stop = kcm_seq_stop, | ||
254 | } | ||
255 | }; | ||
256 | |||
257 | static int kcm_proc_register(struct net *net, struct kcm_seq_muxinfo *muxinfo) | ||
258 | { | ||
259 | struct proc_dir_entry *p; | ||
260 | int rc = 0; | ||
261 | |||
262 | p = proc_create_data(muxinfo->name, S_IRUGO, net->proc_net, | ||
263 | muxinfo->seq_fops, muxinfo); | ||
264 | if (!p) | ||
265 | rc = -ENOMEM; | ||
266 | return rc; | ||
267 | } | ||
268 | EXPORT_SYMBOL(kcm_proc_register); | ||
269 | |||
270 | static void kcm_proc_unregister(struct net *net, | ||
271 | struct kcm_seq_muxinfo *muxinfo) | ||
272 | { | ||
273 | remove_proc_entry(muxinfo->name, net->proc_net); | ||
274 | } | ||
275 | EXPORT_SYMBOL(kcm_proc_unregister); | ||
276 | |||
277 | static int kcm_stats_seq_show(struct seq_file *seq, void *v) | ||
278 | { | ||
279 | struct kcm_psock_stats psock_stats; | ||
280 | struct kcm_mux_stats mux_stats; | ||
281 | struct kcm_mux *mux; | ||
282 | struct kcm_psock *psock; | ||
283 | struct net *net = seq->private; | ||
284 | struct kcm_net *knet = net_generic(net, kcm_net_id); | ||
285 | |||
286 | memset(&mux_stats, 0, sizeof(mux_stats)); | ||
287 | memset(&psock_stats, 0, sizeof(psock_stats)); | ||
288 | |||
289 | mutex_lock(&knet->mutex); | ||
290 | |||
291 | aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats); | ||
292 | aggregate_psock_stats(&knet->aggregate_psock_stats, | ||
293 | &psock_stats); | ||
294 | |||
295 | list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) { | ||
296 | spin_lock_bh(&mux->lock); | ||
297 | aggregate_mux_stats(&mux->stats, &mux_stats); | ||
298 | aggregate_psock_stats(&mux->aggregate_psock_stats, | ||
299 | &psock_stats); | ||
300 | list_for_each_entry(psock, &mux->psocks, psock_list) | ||
301 | aggregate_psock_stats(&psock->stats, &psock_stats); | ||
302 | spin_unlock_bh(&mux->lock); | ||
303 | } | ||
304 | |||
305 | mutex_unlock(&knet->mutex); | ||
306 | |||
307 | seq_printf(seq, | ||
308 | "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n", | ||
309 | "MUX", | ||
310 | "RX-Msgs", | ||
311 | "RX-Bytes", | ||
312 | "TX-Msgs", | ||
313 | "TX-Bytes", | ||
314 | "TX-Retries", | ||
315 | "Attach", | ||
316 | "Unattach", | ||
317 | "UnattchRsvd", | ||
318 | "RX-RdyDrops"); | ||
319 | |||
320 | seq_printf(seq, | ||
321 | "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n", | ||
322 | "", | ||
323 | mux_stats.rx_msgs, | ||
324 | mux_stats.rx_bytes, | ||
325 | mux_stats.tx_msgs, | ||
326 | mux_stats.tx_bytes, | ||
327 | mux_stats.tx_retries, | ||
328 | mux_stats.psock_attach, | ||
329 | mux_stats.psock_unattach_rsvd, | ||
330 | mux_stats.psock_unattach, | ||
331 | mux_stats.rx_ready_drops); | ||
332 | |||
333 | seq_printf(seq, | ||
334 | "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", | ||
335 | "Psock", | ||
336 | "RX-Msgs", | ||
337 | "RX-Bytes", | ||
338 | "TX-Msgs", | ||
339 | "TX-Bytes", | ||
340 | "Reserved", | ||
341 | "Unreserved", | ||
342 | "RX-Aborts", | ||
343 | "RX-MemFail", | ||
344 | "RX-NeedMor", | ||
345 | "RX-BadLen", | ||
346 | "TX-Aborts"); | ||
347 | |||
348 | seq_printf(seq, | ||
349 | "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u\n", | ||
350 | "", | ||
351 | psock_stats.rx_msgs, | ||
352 | psock_stats.rx_bytes, | ||
353 | psock_stats.tx_msgs, | ||
354 | psock_stats.tx_bytes, | ||
355 | psock_stats.reserved, | ||
356 | psock_stats.unreserved, | ||
357 | psock_stats.rx_aborts, | ||
358 | psock_stats.rx_mem_fail, | ||
359 | psock_stats.rx_need_more_hdr, | ||
360 | psock_stats.rx_bad_hdr_len, | ||
361 | psock_stats.tx_aborts); | ||
362 | |||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int kcm_stats_seq_open(struct inode *inode, struct file *file) | ||
367 | { | ||
368 | return single_open_net(inode, file, kcm_stats_seq_show); | ||
369 | } | ||
370 | |||
371 | static const struct file_operations kcm_stats_seq_fops = { | ||
372 | .owner = THIS_MODULE, | ||
373 | .open = kcm_stats_seq_open, | ||
374 | .read = seq_read, | ||
375 | .llseek = seq_lseek, | ||
376 | .release = single_release_net, | ||
377 | }; | ||
378 | |||
379 | static int kcm_proc_init_net(struct net *net) | ||
380 | { | ||
381 | int err; | ||
382 | |||
383 | if (!proc_create("kcm_stats", S_IRUGO, net->proc_net, | ||
384 | &kcm_stats_seq_fops)) { | ||
385 | err = -ENOMEM; | ||
386 | goto out_kcm_stats; | ||
387 | } | ||
388 | |||
389 | err = kcm_proc_register(net, &kcm_seq_muxinfo); | ||
390 | if (err) | ||
391 | goto out_kcm; | ||
392 | |||
393 | return 0; | ||
394 | |||
395 | out_kcm: | ||
396 | remove_proc_entry("kcm_stats", net->proc_net); | ||
397 | out_kcm_stats: | ||
398 | return err; | ||
399 | } | ||
400 | |||
401 | static void kcm_proc_exit_net(struct net *net) | ||
402 | { | ||
403 | kcm_proc_unregister(net, &kcm_seq_muxinfo); | ||
404 | remove_proc_entry("kcm_stats", net->proc_net); | ||
405 | } | ||
406 | |||
407 | static struct pernet_operations kcm_net_ops = { | ||
408 | .init = kcm_proc_init_net, | ||
409 | .exit = kcm_proc_exit_net, | ||
410 | }; | ||
411 | |||
412 | int __init kcm_proc_init(void) | ||
413 | { | ||
414 | return register_pernet_subsys(&kcm_net_ops); | ||
415 | } | ||
416 | |||
417 | void __exit kcm_proc_exit(void) | ||
418 | { | ||
419 | unregister_pernet_subsys(&kcm_net_ops); | ||
420 | } | ||
421 | |||
422 | #endif /* CONFIG_PROC_FS */ | ||
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 30ef69ac6b81..f938d7d3e6e2 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c | |||
@@ -59,6 +59,7 @@ static void kcm_abort_rx_psock(struct kcm_psock *psock, int err, | |||
59 | return; | 59 | return; |
60 | 60 | ||
61 | psock->rx_stopped = 1; | 61 | psock->rx_stopped = 1; |
62 | KCM_STATS_INCR(psock->stats.rx_aborts); | ||
62 | 63 | ||
63 | /* Report an error on the lower socket */ | 64 | /* Report an error on the lower socket */ |
64 | report_csk_error(csk, err); | 65 | report_csk_error(csk, err); |
@@ -80,6 +81,7 @@ static void kcm_abort_tx_psock(struct kcm_psock *psock, int err, | |||
80 | } | 81 | } |
81 | 82 | ||
82 | psock->tx_stopped = 1; | 83 | psock->tx_stopped = 1; |
84 | KCM_STATS_INCR(psock->stats.tx_aborts); | ||
83 | 85 | ||
84 | if (!psock->tx_kcm) { | 86 | if (!psock->tx_kcm) { |
85 | /* Take off psocks_avail list */ | 87 | /* Take off psocks_avail list */ |
@@ -101,6 +103,29 @@ static void kcm_abort_tx_psock(struct kcm_psock *psock, int err, | |||
101 | report_csk_error(csk, err); | 103 | report_csk_error(csk, err); |
102 | } | 104 | } |
103 | 105 | ||
106 | /* RX mux lock held. */ | ||
107 | static void kcm_update_rx_mux_stats(struct kcm_mux *mux, | ||
108 | struct kcm_psock *psock) | ||
109 | { | ||
110 | KCM_STATS_ADD(mux->stats.rx_bytes, | ||
111 | psock->stats.rx_bytes - psock->saved_rx_bytes); | ||
112 | mux->stats.rx_msgs += | ||
113 | psock->stats.rx_msgs - psock->saved_rx_msgs; | ||
114 | psock->saved_rx_msgs = psock->stats.rx_msgs; | ||
115 | psock->saved_rx_bytes = psock->stats.rx_bytes; | ||
116 | } | ||
117 | |||
118 | static void kcm_update_tx_mux_stats(struct kcm_mux *mux, | ||
119 | struct kcm_psock *psock) | ||
120 | { | ||
121 | KCM_STATS_ADD(mux->stats.tx_bytes, | ||
122 | psock->stats.tx_bytes - psock->saved_tx_bytes); | ||
123 | mux->stats.tx_msgs += | ||
124 | psock->stats.tx_msgs - psock->saved_tx_msgs; | ||
125 | psock->saved_tx_msgs = psock->stats.tx_msgs; | ||
126 | psock->saved_tx_bytes = psock->stats.tx_bytes; | ||
127 | } | ||
128 | |||
104 | static int kcm_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); | 129 | static int kcm_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); |
105 | 130 | ||
106 | /* KCM is ready to receive messages on its queue-- either the KCM is new or | 131 | /* KCM is ready to receive messages on its queue-- either the KCM is new or |
@@ -254,6 +279,8 @@ static struct kcm_sock *reserve_rx_kcm(struct kcm_psock *psock, | |||
254 | return psock->rx_kcm; | 279 | return psock->rx_kcm; |
255 | } | 280 | } |
256 | 281 | ||
282 | kcm_update_rx_mux_stats(mux, psock); | ||
283 | |||
257 | if (list_empty(&mux->kcm_rx_waiters)) { | 284 | if (list_empty(&mux->kcm_rx_waiters)) { |
258 | psock->ready_rx_msg = head; | 285 | psock->ready_rx_msg = head; |
259 | list_add_tail(&psock->psock_ready_list, | 286 | list_add_tail(&psock->psock_ready_list, |
@@ -356,10 +383,12 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
356 | */ | 383 | */ |
357 | orig_skb = skb_clone(orig_skb, GFP_ATOMIC); | 384 | orig_skb = skb_clone(orig_skb, GFP_ATOMIC); |
358 | if (!orig_skb) { | 385 | if (!orig_skb) { |
386 | KCM_STATS_INCR(psock->stats.rx_mem_fail); | ||
359 | desc->error = -ENOMEM; | 387 | desc->error = -ENOMEM; |
360 | return 0; | 388 | return 0; |
361 | } | 389 | } |
362 | if (!pskb_pull(orig_skb, orig_offset)) { | 390 | if (!pskb_pull(orig_skb, orig_offset)) { |
391 | KCM_STATS_INCR(psock->stats.rx_mem_fail); | ||
363 | kfree_skb(orig_skb); | 392 | kfree_skb(orig_skb); |
364 | desc->error = -ENOMEM; | 393 | desc->error = -ENOMEM; |
365 | return 0; | 394 | return 0; |
@@ -374,6 +403,7 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
374 | */ | 403 | */ |
375 | err = skb_unclone(head, GFP_ATOMIC); | 404 | err = skb_unclone(head, GFP_ATOMIC); |
376 | if (err) { | 405 | if (err) { |
406 | KCM_STATS_INCR(psock->stats.rx_mem_fail); | ||
377 | desc->error = err; | 407 | desc->error = err; |
378 | return 0; | 408 | return 0; |
379 | } | 409 | } |
@@ -392,6 +422,7 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
392 | 422 | ||
393 | skb = alloc_skb(0, GFP_ATOMIC); | 423 | skb = alloc_skb(0, GFP_ATOMIC); |
394 | if (!skb) { | 424 | if (!skb) { |
425 | KCM_STATS_INCR(psock->stats.rx_mem_fail); | ||
395 | desc->error = -ENOMEM; | 426 | desc->error = -ENOMEM; |
396 | return 0; | 427 | return 0; |
397 | } | 428 | } |
@@ -414,6 +445,7 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
414 | /* Always clone since we will consume something */ | 445 | /* Always clone since we will consume something */ |
415 | skb = skb_clone(orig_skb, GFP_ATOMIC); | 446 | skb = skb_clone(orig_skb, GFP_ATOMIC); |
416 | if (!skb) { | 447 | if (!skb) { |
448 | KCM_STATS_INCR(psock->stats.rx_mem_fail); | ||
417 | desc->error = -ENOMEM; | 449 | desc->error = -ENOMEM; |
418 | break; | 450 | break; |
419 | } | 451 | } |
@@ -435,6 +467,7 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
435 | */ | 467 | */ |
436 | err = skb_unclone(skb, GFP_ATOMIC); | 468 | err = skb_unclone(skb, GFP_ATOMIC); |
437 | if (err) { | 469 | if (err) { |
470 | KCM_STATS_INCR(psock->stats.rx_mem_fail); | ||
438 | desc->error = err; | 471 | desc->error = err; |
439 | break; | 472 | break; |
440 | } | 473 | } |
@@ -456,6 +489,7 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
456 | /* Need more header to determine length */ | 489 | /* Need more header to determine length */ |
457 | rxm->accum_len += cand_len; | 490 | rxm->accum_len += cand_len; |
458 | eaten += cand_len; | 491 | eaten += cand_len; |
492 | KCM_STATS_INCR(psock->stats.rx_need_more_hdr); | ||
459 | WARN_ON(eaten != orig_len); | 493 | WARN_ON(eaten != orig_len); |
460 | break; | 494 | break; |
461 | } else if (len <= (ssize_t)head->len - | 495 | } else if (len <= (ssize_t)head->len - |
@@ -463,6 +497,7 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
463 | /* Length must be into new skb (and also | 497 | /* Length must be into new skb (and also |
464 | * greater than zero) | 498 | * greater than zero) |
465 | */ | 499 | */ |
500 | KCM_STATS_INCR(psock->stats.rx_bad_hdr_len); | ||
466 | desc->error = -EPROTO; | 501 | desc->error = -EPROTO; |
467 | psock->rx_skb_head = NULL; | 502 | psock->rx_skb_head = NULL; |
468 | kcm_abort_rx_psock(psock, EPROTO, head); | 503 | kcm_abort_rx_psock(psock, EPROTO, head); |
@@ -492,6 +527,7 @@ static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, | |||
492 | 527 | ||
493 | /* Hurray, we have a new message! */ | 528 | /* Hurray, we have a new message! */ |
494 | psock->rx_skb_head = NULL; | 529 | psock->rx_skb_head = NULL; |
530 | KCM_STATS_INCR(psock->stats.rx_msgs); | ||
495 | 531 | ||
496 | try_queue: | 532 | try_queue: |
497 | kcm = reserve_rx_kcm(psock, head); | 533 | kcm = reserve_rx_kcm(psock, head); |
@@ -510,6 +546,8 @@ try_queue: | |||
510 | if (cloned_orig) | 546 | if (cloned_orig) |
511 | kfree_skb(orig_skb); | 547 | kfree_skb(orig_skb); |
512 | 548 | ||
549 | KCM_STATS_ADD(psock->stats.rx_bytes, eaten); | ||
550 | |||
513 | return eaten; | 551 | return eaten; |
514 | } | 552 | } |
515 | 553 | ||
@@ -671,6 +709,7 @@ static struct kcm_psock *reserve_psock(struct kcm_sock *kcm) | |||
671 | } | 709 | } |
672 | kcm->tx_psock = psock; | 710 | kcm->tx_psock = psock; |
673 | psock->tx_kcm = kcm; | 711 | psock->tx_kcm = kcm; |
712 | KCM_STATS_INCR(psock->stats.reserved); | ||
674 | } else if (!kcm->tx_wait) { | 713 | } else if (!kcm->tx_wait) { |
675 | list_add_tail(&kcm->wait_psock_list, | 714 | list_add_tail(&kcm->wait_psock_list, |
676 | &mux->kcm_tx_waiters); | 715 | &mux->kcm_tx_waiters); |
@@ -705,6 +744,7 @@ static void psock_now_avail(struct kcm_psock *psock) | |||
705 | smp_mb(); | 744 | smp_mb(); |
706 | 745 | ||
707 | kcm->tx_psock = psock; | 746 | kcm->tx_psock = psock; |
747 | KCM_STATS_INCR(psock->stats.reserved); | ||
708 | queue_work(kcm_wq, &kcm->tx_work); | 748 | queue_work(kcm_wq, &kcm->tx_work); |
709 | } | 749 | } |
710 | } | 750 | } |
@@ -726,10 +766,13 @@ static void unreserve_psock(struct kcm_sock *kcm) | |||
726 | 766 | ||
727 | smp_rmb(); /* Read tx_psock before tx_wait */ | 767 | smp_rmb(); /* Read tx_psock before tx_wait */ |
728 | 768 | ||
769 | kcm_update_tx_mux_stats(mux, psock); | ||
770 | |||
729 | WARN_ON(kcm->tx_wait); | 771 | WARN_ON(kcm->tx_wait); |
730 | 772 | ||
731 | kcm->tx_psock = NULL; | 773 | kcm->tx_psock = NULL; |
732 | psock->tx_kcm = NULL; | 774 | psock->tx_kcm = NULL; |
775 | KCM_STATS_INCR(psock->stats.unreserved); | ||
733 | 776 | ||
734 | if (unlikely(psock->tx_stopped)) { | 777 | if (unlikely(psock->tx_stopped)) { |
735 | if (psock->done) { | 778 | if (psock->done) { |
@@ -753,6 +796,15 @@ static void unreserve_psock(struct kcm_sock *kcm) | |||
753 | spin_unlock_bh(&mux->lock); | 796 | spin_unlock_bh(&mux->lock); |
754 | } | 797 | } |
755 | 798 | ||
799 | static void kcm_report_tx_retry(struct kcm_sock *kcm) | ||
800 | { | ||
801 | struct kcm_mux *mux = kcm->mux; | ||
802 | |||
803 | spin_lock_bh(&mux->lock); | ||
804 | KCM_STATS_INCR(mux->stats.tx_retries); | ||
805 | spin_unlock_bh(&mux->lock); | ||
806 | } | ||
807 | |||
756 | /* Write any messages ready on the kcm socket. Called with kcm sock lock | 808 | /* Write any messages ready on the kcm socket. Called with kcm sock lock |
757 | * held. Return bytes actually sent or error. | 809 | * held. Return bytes actually sent or error. |
758 | */ | 810 | */ |
@@ -773,6 +825,7 @@ static int kcm_write_msgs(struct kcm_sock *kcm) | |||
773 | * it and we'll retry the message. | 825 | * it and we'll retry the message. |
774 | */ | 826 | */ |
775 | unreserve_psock(kcm); | 827 | unreserve_psock(kcm); |
828 | kcm_report_tx_retry(kcm); | ||
776 | if (skb_queue_empty(&sk->sk_write_queue)) | 829 | if (skb_queue_empty(&sk->sk_write_queue)) |
777 | return 0; | 830 | return 0; |
778 | 831 | ||
@@ -856,6 +909,7 @@ do_frag: | |||
856 | unreserve_psock(kcm); | 909 | unreserve_psock(kcm); |
857 | 910 | ||
858 | txm->sent = 0; | 911 | txm->sent = 0; |
912 | kcm_report_tx_retry(kcm); | ||
859 | ret = 0; | 913 | ret = 0; |
860 | 914 | ||
861 | goto try_again; | 915 | goto try_again; |
@@ -863,6 +917,7 @@ do_frag: | |||
863 | 917 | ||
864 | sent += ret; | 918 | sent += ret; |
865 | frag_offset += ret; | 919 | frag_offset += ret; |
920 | KCM_STATS_ADD(psock->stats.tx_bytes, ret); | ||
866 | if (frag_offset < frag->size) { | 921 | if (frag_offset < frag->size) { |
867 | /* Not finished with this frag */ | 922 | /* Not finished with this frag */ |
868 | goto do_frag; | 923 | goto do_frag; |
@@ -884,6 +939,7 @@ do_frag: | |||
884 | kfree_skb(head); | 939 | kfree_skb(head); |
885 | sk->sk_wmem_queued -= sent; | 940 | sk->sk_wmem_queued -= sent; |
886 | total_sent += sent; | 941 | total_sent += sent; |
942 | KCM_STATS_INCR(psock->stats.tx_msgs); | ||
887 | } while ((head = skb_peek(&sk->sk_write_queue))); | 943 | } while ((head = skb_peek(&sk->sk_write_queue))); |
888 | out: | 944 | out: |
889 | if (!head) { | 945 | if (!head) { |
@@ -1061,6 +1117,7 @@ wait_for_memory: | |||
1061 | /* Message complete, queue it on send buffer */ | 1117 | /* Message complete, queue it on send buffer */ |
1062 | __skb_queue_tail(&sk->sk_write_queue, head); | 1118 | __skb_queue_tail(&sk->sk_write_queue, head); |
1063 | kcm->seq_skb = NULL; | 1119 | kcm->seq_skb = NULL; |
1120 | KCM_STATS_INCR(kcm->stats.tx_msgs); | ||
1064 | 1121 | ||
1065 | if (msg->msg_flags & MSG_BATCH) { | 1122 | if (msg->msg_flags & MSG_BATCH) { |
1066 | kcm->tx_wait_more = true; | 1123 | kcm->tx_wait_more = true; |
@@ -1083,6 +1140,8 @@ partial_message: | |||
1083 | kcm_tx_msg(head)->last_skb = skb; | 1140 | kcm_tx_msg(head)->last_skb = skb; |
1084 | } | 1141 | } |
1085 | 1142 | ||
1143 | KCM_STATS_ADD(kcm->stats.tx_bytes, copied); | ||
1144 | |||
1086 | release_sock(sk); | 1145 | release_sock(sk); |
1087 | return copied; | 1146 | return copied; |
1088 | 1147 | ||
@@ -1144,6 +1203,7 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg, | |||
1144 | size_t len, int flags) | 1203 | size_t len, int flags) |
1145 | { | 1204 | { |
1146 | struct sock *sk = sock->sk; | 1205 | struct sock *sk = sock->sk; |
1206 | struct kcm_sock *kcm = kcm_sk(sk); | ||
1147 | int err = 0; | 1207 | int err = 0; |
1148 | long timeo; | 1208 | long timeo; |
1149 | struct kcm_rx_msg *rxm; | 1209 | struct kcm_rx_msg *rxm; |
@@ -1171,6 +1231,7 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg, | |||
1171 | 1231 | ||
1172 | copied = len; | 1232 | copied = len; |
1173 | if (likely(!(flags & MSG_PEEK))) { | 1233 | if (likely(!(flags & MSG_PEEK))) { |
1234 | KCM_STATS_ADD(kcm->stats.rx_bytes, copied); | ||
1174 | if (copied < rxm->full_len) { | 1235 | if (copied < rxm->full_len) { |
1175 | if (sock->type == SOCK_DGRAM) { | 1236 | if (sock->type == SOCK_DGRAM) { |
1176 | /* Truncated message */ | 1237 | /* Truncated message */ |
@@ -1183,6 +1244,7 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg, | |||
1183 | msg_finished: | 1244 | msg_finished: |
1184 | /* Finished with message */ | 1245 | /* Finished with message */ |
1185 | msg->msg_flags |= MSG_EOR; | 1246 | msg->msg_flags |= MSG_EOR; |
1247 | KCM_STATS_INCR(kcm->stats.rx_msgs); | ||
1186 | skb_unlink(skb, &sk->sk_receive_queue); | 1248 | skb_unlink(skb, &sk->sk_receive_queue); |
1187 | kfree_skb(skb); | 1249 | kfree_skb(skb); |
1188 | } | 1250 | } |
@@ -1394,6 +1456,7 @@ static int kcm_attach(struct socket *sock, struct socket *csock, | |||
1394 | list_add(&psock->psock_list, head); | 1456 | list_add(&psock->psock_list, head); |
1395 | psock->index = index; | 1457 | psock->index = index; |
1396 | 1458 | ||
1459 | KCM_STATS_INCR(mux->stats.psock_attach); | ||
1397 | mux->psocks_cnt++; | 1460 | mux->psocks_cnt++; |
1398 | psock_now_avail(psock); | 1461 | psock_now_avail(psock); |
1399 | spin_unlock_bh(&mux->lock); | 1462 | spin_unlock_bh(&mux->lock); |
@@ -1469,6 +1532,7 @@ static void kcm_unattach(struct kcm_psock *psock) | |||
1469 | list_del(&psock->psock_ready_list); | 1532 | list_del(&psock->psock_ready_list); |
1470 | kfree_skb(psock->ready_rx_msg); | 1533 | kfree_skb(psock->ready_rx_msg); |
1471 | psock->ready_rx_msg = NULL; | 1534 | psock->ready_rx_msg = NULL; |
1535 | KCM_STATS_INCR(mux->stats.rx_ready_drops); | ||
1472 | } | 1536 | } |
1473 | 1537 | ||
1474 | spin_unlock_bh(&mux->rx_lock); | 1538 | spin_unlock_bh(&mux->rx_lock); |
@@ -1485,11 +1549,16 @@ static void kcm_unattach(struct kcm_psock *psock) | |||
1485 | 1549 | ||
1486 | spin_lock_bh(&mux->lock); | 1550 | spin_lock_bh(&mux->lock); |
1487 | 1551 | ||
1552 | aggregate_psock_stats(&psock->stats, &mux->aggregate_psock_stats); | ||
1553 | |||
1554 | KCM_STATS_INCR(mux->stats.psock_unattach); | ||
1555 | |||
1488 | if (psock->tx_kcm) { | 1556 | if (psock->tx_kcm) { |
1489 | /* psock was reserved. Just mark it finished and we will clean | 1557 | /* psock was reserved. Just mark it finished and we will clean |
1490 | * up in the kcm paths, we need kcm lock which can not be | 1558 | * up in the kcm paths, we need kcm lock which can not be |
1491 | * acquired here. | 1559 | * acquired here. |
1492 | */ | 1560 | */ |
1561 | KCM_STATS_INCR(mux->stats.psock_unattach_rsvd); | ||
1493 | spin_unlock_bh(&mux->lock); | 1562 | spin_unlock_bh(&mux->lock); |
1494 | 1563 | ||
1495 | /* We are unattaching a socket that is reserved. Abort the | 1564 | /* We are unattaching a socket that is reserved. Abort the |
@@ -1717,6 +1786,9 @@ static void release_mux(struct kcm_mux *mux) | |||
1717 | __skb_queue_purge(&mux->rx_hold_queue); | 1786 | __skb_queue_purge(&mux->rx_hold_queue); |
1718 | 1787 | ||
1719 | mutex_lock(&knet->mutex); | 1788 | mutex_lock(&knet->mutex); |
1789 | aggregate_mux_stats(&mux->stats, &knet->aggregate_mux_stats); | ||
1790 | aggregate_psock_stats(&mux->aggregate_psock_stats, | ||
1791 | &knet->aggregate_psock_stats); | ||
1720 | list_del_rcu(&mux->kcm_mux_list); | 1792 | list_del_rcu(&mux->kcm_mux_list); |
1721 | knet->count--; | 1793 | knet->count--; |
1722 | mutex_unlock(&knet->mutex); | 1794 | mutex_unlock(&knet->mutex); |
@@ -1979,8 +2051,15 @@ static int __init kcm_init(void) | |||
1979 | if (err) | 2051 | if (err) |
1980 | goto net_ops_fail; | 2052 | goto net_ops_fail; |
1981 | 2053 | ||
2054 | err = kcm_proc_init(); | ||
2055 | if (err) | ||
2056 | goto proc_init_fail; | ||
2057 | |||
1982 | return 0; | 2058 | return 0; |
1983 | 2059 | ||
2060 | proc_init_fail: | ||
2061 | unregister_pernet_device(&kcm_net_ops); | ||
2062 | |||
1984 | net_ops_fail: | 2063 | net_ops_fail: |
1985 | sock_unregister(PF_KCM); | 2064 | sock_unregister(PF_KCM); |
1986 | 2065 | ||
@@ -1999,6 +2078,7 @@ fail: | |||
1999 | 2078 | ||
2000 | static void __exit kcm_exit(void) | 2079 | static void __exit kcm_exit(void) |
2001 | { | 2080 | { |
2081 | kcm_proc_exit(); | ||
2002 | unregister_pernet_device(&kcm_net_ops); | 2082 | unregister_pernet_device(&kcm_net_ops); |
2003 | sock_unregister(PF_KCM); | 2083 | sock_unregister(PF_KCM); |
2004 | proto_unregister(&kcm_proto); | 2084 | proto_unregister(&kcm_proto); |