xref: /openbmc/linux/net/kcm/kcmproc.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2cd6e111bSTom Herbert #include <linux/in.h>
3cd6e111bSTom Herbert #include <linux/inet.h>
4cd6e111bSTom Herbert #include <linux/list.h>
5cd6e111bSTom Herbert #include <linux/module.h>
6cd6e111bSTom Herbert #include <linux/net.h>
7cd6e111bSTom Herbert #include <linux/proc_fs.h>
8cd6e111bSTom Herbert #include <linux/rculist.h>
9cd6e111bSTom Herbert #include <linux/seq_file.h>
10cd6e111bSTom Herbert #include <linux/socket.h>
11cd6e111bSTom Herbert #include <net/inet_sock.h>
12cd6e111bSTom Herbert #include <net/kcm.h>
13cd6e111bSTom Herbert #include <net/net_namespace.h>
14cd6e111bSTom Herbert #include <net/netns/generic.h>
15cd6e111bSTom Herbert #include <net/tcp.h>
16cd6e111bSTom Herbert 
17cd6e111bSTom Herbert #ifdef CONFIG_PROC_FS
kcm_get_first(struct seq_file * seq)18cd6e111bSTom Herbert static struct kcm_mux *kcm_get_first(struct seq_file *seq)
19cd6e111bSTom Herbert {
20cd6e111bSTom Herbert 	struct net *net = seq_file_net(seq);
21cd6e111bSTom Herbert 	struct kcm_net *knet = net_generic(net, kcm_net_id);
22cd6e111bSTom Herbert 
23cd6e111bSTom Herbert 	return list_first_or_null_rcu(&knet->mux_list,
24cd6e111bSTom Herbert 				      struct kcm_mux, kcm_mux_list);
25cd6e111bSTom Herbert }
26cd6e111bSTom Herbert 
kcm_get_next(struct kcm_mux * mux)27cd6e111bSTom Herbert static struct kcm_mux *kcm_get_next(struct kcm_mux *mux)
28cd6e111bSTom Herbert {
29cd6e111bSTom Herbert 	struct kcm_net *knet = mux->knet;
30cd6e111bSTom Herbert 
31cd6e111bSTom Herbert 	return list_next_or_null_rcu(&knet->mux_list, &mux->kcm_mux_list,
32cd6e111bSTom Herbert 				     struct kcm_mux, kcm_mux_list);
33cd6e111bSTom Herbert }
34cd6e111bSTom Herbert 
kcm_get_idx(struct seq_file * seq,loff_t pos)35cd6e111bSTom Herbert static struct kcm_mux *kcm_get_idx(struct seq_file *seq, loff_t pos)
36cd6e111bSTom Herbert {
37cd6e111bSTom Herbert 	struct net *net = seq_file_net(seq);
38cd6e111bSTom Herbert 	struct kcm_net *knet = net_generic(net, kcm_net_id);
39cd6e111bSTom Herbert 	struct kcm_mux *m;
40cd6e111bSTom Herbert 
41cd6e111bSTom Herbert 	list_for_each_entry_rcu(m, &knet->mux_list, kcm_mux_list) {
42cd6e111bSTom Herbert 		if (!pos)
43cd6e111bSTom Herbert 			return m;
44cd6e111bSTom Herbert 		--pos;
45cd6e111bSTom Herbert 	}
46cd6e111bSTom Herbert 	return NULL;
47cd6e111bSTom Herbert }
48cd6e111bSTom Herbert 
kcm_seq_next(struct seq_file * seq,void * v,loff_t * pos)49cd6e111bSTom Herbert static void *kcm_seq_next(struct seq_file *seq, void *v, loff_t *pos)
50cd6e111bSTom Herbert {
51cd6e111bSTom Herbert 	void *p;
52cd6e111bSTom Herbert 
53cd6e111bSTom Herbert 	if (v == SEQ_START_TOKEN)
54cd6e111bSTom Herbert 		p = kcm_get_first(seq);
55cd6e111bSTom Herbert 	else
56cd6e111bSTom Herbert 		p = kcm_get_next(v);
57cd6e111bSTom Herbert 	++*pos;
58cd6e111bSTom Herbert 	return p;
59cd6e111bSTom Herbert }
60cd6e111bSTom Herbert 
kcm_seq_start(struct seq_file * seq,loff_t * pos)61cd6e111bSTom Herbert static void *kcm_seq_start(struct seq_file *seq, loff_t *pos)
62cd6e111bSTom Herbert 	__acquires(rcu)
63cd6e111bSTom Herbert {
64cd6e111bSTom Herbert 	rcu_read_lock();
65cd6e111bSTom Herbert 
66cd6e111bSTom Herbert 	if (!*pos)
67cd6e111bSTom Herbert 		return SEQ_START_TOKEN;
68cd6e111bSTom Herbert 	else
69cd6e111bSTom Herbert 		return kcm_get_idx(seq, *pos - 1);
70cd6e111bSTom Herbert }
71cd6e111bSTom Herbert 
kcm_seq_stop(struct seq_file * seq,void * v)72cd6e111bSTom Herbert static void kcm_seq_stop(struct seq_file *seq, void *v)
73cd6e111bSTom Herbert 	__releases(rcu)
74cd6e111bSTom Herbert {
75cd6e111bSTom Herbert 	rcu_read_unlock();
76cd6e111bSTom Herbert }
77cd6e111bSTom Herbert 
78cd6e111bSTom Herbert struct kcm_proc_mux_state {
79cd6e111bSTom Herbert 	struct seq_net_private p;
80cd6e111bSTom Herbert 	int idx;
81cd6e111bSTom Herbert };
82cd6e111bSTom Herbert 
kcm_format_mux_header(struct seq_file * seq)83cd6e111bSTom Herbert static void kcm_format_mux_header(struct seq_file *seq)
84cd6e111bSTom Herbert {
85cd6e111bSTom Herbert 	struct net *net = seq_file_net(seq);
86cd6e111bSTom Herbert 	struct kcm_net *knet = net_generic(net, kcm_net_id);
87cd6e111bSTom Herbert 
88cd6e111bSTom Herbert 	seq_printf(seq,
89cd6e111bSTom Herbert 		   "*** KCM statistics (%d MUX) ****\n",
90cd6e111bSTom Herbert 		   knet->count);
91cd6e111bSTom Herbert 
92cd6e111bSTom Herbert 	seq_printf(seq,
93cd6e111bSTom Herbert 		   "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s",
94cd6e111bSTom Herbert 		   "Object",
95cd6e111bSTom Herbert 		   "RX-Msgs",
96cd6e111bSTom Herbert 		   "RX-Bytes",
97cd6e111bSTom Herbert 		   "TX-Msgs",
98cd6e111bSTom Herbert 		   "TX-Bytes",
99cd6e111bSTom Herbert 		   "Recv-Q",
100cd6e111bSTom Herbert 		   "Rmem",
101cd6e111bSTom Herbert 		   "Send-Q",
102cd6e111bSTom Herbert 		   "Smem",
103cd6e111bSTom Herbert 		   "Status");
104cd6e111bSTom Herbert 
105cd6e111bSTom Herbert 	/* XXX: pdsts header stuff here */
106cd6e111bSTom Herbert 	seq_puts(seq, "\n");
107cd6e111bSTom Herbert }
108cd6e111bSTom Herbert 
kcm_format_sock(struct kcm_sock * kcm,struct seq_file * seq,int i,int * len)109cd6e111bSTom Herbert static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq,
110cd6e111bSTom Herbert 			    int i, int *len)
111cd6e111bSTom Herbert {
112cd6e111bSTom Herbert 	seq_printf(seq,
113cd6e111bSTom Herbert 		   "   kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ",
114cd6e111bSTom Herbert 		   kcm->index,
115cd6e111bSTom Herbert 		   kcm->stats.rx_msgs,
116cd6e111bSTom Herbert 		   kcm->stats.rx_bytes,
117cd6e111bSTom Herbert 		   kcm->stats.tx_msgs,
118cd6e111bSTom Herbert 		   kcm->stats.tx_bytes,
119cd6e111bSTom Herbert 		   kcm->sk.sk_receive_queue.qlen,
120cd6e111bSTom Herbert 		   sk_rmem_alloc_get(&kcm->sk),
121cd6e111bSTom Herbert 		   kcm->sk.sk_write_queue.qlen,
122cd6e111bSTom Herbert 		   "-");
123cd6e111bSTom Herbert 
124cd6e111bSTom Herbert 	if (kcm->tx_psock)
125cd6e111bSTom Herbert 		seq_printf(seq, "Psck-%u ", kcm->tx_psock->index);
126cd6e111bSTom Herbert 
127cd6e111bSTom Herbert 	if (kcm->tx_wait)
128cd6e111bSTom Herbert 		seq_puts(seq, "TxWait ");
129cd6e111bSTom Herbert 
130cd6e111bSTom Herbert 	if (kcm->tx_wait_more)
131cd6e111bSTom Herbert 		seq_puts(seq, "WMore ");
132cd6e111bSTom Herbert 
133cd6e111bSTom Herbert 	if (kcm->rx_wait)
134cd6e111bSTom Herbert 		seq_puts(seq, "RxWait ");
135cd6e111bSTom Herbert 
136cd6e111bSTom Herbert 	seq_puts(seq, "\n");
137cd6e111bSTom Herbert }
138cd6e111bSTom Herbert 
kcm_format_psock(struct kcm_psock * psock,struct seq_file * seq,int i,int * len)139cd6e111bSTom Herbert static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
140cd6e111bSTom Herbert 			     int i, int *len)
141cd6e111bSTom Herbert {
142cd6e111bSTom Herbert 	seq_printf(seq,
143cd6e111bSTom Herbert 		   "   psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ",
144cd6e111bSTom Herbert 		   psock->index,
145bbb03029STom Herbert 		   psock->strp.stats.msgs,
146bbb03029STom Herbert 		   psock->strp.stats.bytes,
147cd6e111bSTom Herbert 		   psock->stats.tx_msgs,
148cd6e111bSTom Herbert 		   psock->stats.tx_bytes,
149cd6e111bSTom Herbert 		   psock->sk->sk_receive_queue.qlen,
150cd6e111bSTom Herbert 		   atomic_read(&psock->sk->sk_rmem_alloc),
151cd6e111bSTom Herbert 		   psock->sk->sk_write_queue.qlen,
15214afee4bSReshetova, Elena 		   refcount_read(&psock->sk->sk_wmem_alloc));
153cd6e111bSTom Herbert 
154cd6e111bSTom Herbert 	if (psock->done)
155cd6e111bSTom Herbert 		seq_puts(seq, "Done ");
156cd6e111bSTom Herbert 
157cd6e111bSTom Herbert 	if (psock->tx_stopped)
158cd6e111bSTom Herbert 		seq_puts(seq, "TxStop ");
159cd6e111bSTom Herbert 
160bbb03029STom Herbert 	if (psock->strp.stopped)
161cd6e111bSTom Herbert 		seq_puts(seq, "RxStop ");
162cd6e111bSTom Herbert 
163cd6e111bSTom Herbert 	if (psock->tx_kcm)
164cd6e111bSTom Herbert 		seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index);
165cd6e111bSTom Herbert 
166bbb03029STom Herbert 	if (!psock->strp.paused && !psock->ready_rx_msg) {
1671616b38fSTom Herbert 		if (psock->sk->sk_receive_queue.qlen) {
168bbb03029STom Herbert 			if (psock->strp.need_bytes)
1691616b38fSTom Herbert 				seq_printf(seq, "RxWait=%u ",
170bbb03029STom Herbert 					   psock->strp.need_bytes);
1711616b38fSTom Herbert 			else
1721616b38fSTom Herbert 				seq_printf(seq, "RxWait ");
1731616b38fSTom Herbert 		}
1741616b38fSTom Herbert 	} else  {
175bbb03029STom Herbert 		if (psock->strp.paused)
1761616b38fSTom Herbert 			seq_puts(seq, "RxPause ");
1771616b38fSTom Herbert 
178cd6e111bSTom Herbert 		if (psock->ready_rx_msg)
179cd6e111bSTom Herbert 			seq_puts(seq, "RdyRx ");
1801616b38fSTom Herbert 	}
181cd6e111bSTom Herbert 
182cd6e111bSTom Herbert 	seq_puts(seq, "\n");
183cd6e111bSTom Herbert }
184cd6e111bSTom Herbert 
185cd6e111bSTom Herbert static void
kcm_format_mux(struct kcm_mux * mux,loff_t idx,struct seq_file * seq)186cd6e111bSTom Herbert kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq)
187cd6e111bSTom Herbert {
188cd6e111bSTom Herbert 	int i, len;
189cd6e111bSTom Herbert 	struct kcm_sock *kcm;
190cd6e111bSTom Herbert 	struct kcm_psock *psock;
191cd6e111bSTom Herbert 
192cd6e111bSTom Herbert 	/* mux information */
193cd6e111bSTom Herbert 	seq_printf(seq,
194cd6e111bSTom Herbert 		   "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ",
195cd6e111bSTom Herbert 		   "mux", "",
196cd6e111bSTom Herbert 		   mux->stats.rx_msgs,
197cd6e111bSTom Herbert 		   mux->stats.rx_bytes,
198cd6e111bSTom Herbert 		   mux->stats.tx_msgs,
199cd6e111bSTom Herbert 		   mux->stats.tx_bytes,
200cd6e111bSTom Herbert 		   "-", "-", "-", "-");
201cd6e111bSTom Herbert 
202cd6e111bSTom Herbert 	seq_printf(seq, "KCMs: %d, Psocks %d\n",
203cd6e111bSTom Herbert 		   mux->kcm_socks_cnt, mux->psocks_cnt);
204cd6e111bSTom Herbert 
205cd6e111bSTom Herbert 	/* kcm sock information */
206cd6e111bSTom Herbert 	i = 0;
207cd6e111bSTom Herbert 	spin_lock_bh(&mux->lock);
208cd6e111bSTom Herbert 	list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) {
209cd6e111bSTom Herbert 		kcm_format_sock(kcm, seq, i, &len);
210cd6e111bSTom Herbert 		i++;
211cd6e111bSTom Herbert 	}
212cd6e111bSTom Herbert 	i = 0;
213cd6e111bSTom Herbert 	list_for_each_entry(psock, &mux->psocks, psock_list) {
214cd6e111bSTom Herbert 		kcm_format_psock(psock, seq, i, &len);
215cd6e111bSTom Herbert 		i++;
216cd6e111bSTom Herbert 	}
217cd6e111bSTom Herbert 	spin_unlock_bh(&mux->lock);
218cd6e111bSTom Herbert }
219cd6e111bSTom Herbert 
kcm_seq_show(struct seq_file * seq,void * v)220cd6e111bSTom Herbert static int kcm_seq_show(struct seq_file *seq, void *v)
221cd6e111bSTom Herbert {
222cd6e111bSTom Herbert 	struct kcm_proc_mux_state *mux_state;
223cd6e111bSTom Herbert 
224cd6e111bSTom Herbert 	mux_state = seq->private;
225cd6e111bSTom Herbert 	if (v == SEQ_START_TOKEN) {
226cd6e111bSTom Herbert 		mux_state->idx = 0;
227cd6e111bSTom Herbert 		kcm_format_mux_header(seq);
228cd6e111bSTom Herbert 	} else {
229cd6e111bSTom Herbert 		kcm_format_mux(v, mux_state->idx, seq);
230cd6e111bSTom Herbert 		mux_state->idx++;
231cd6e111bSTom Herbert 	}
232cd6e111bSTom Herbert 	return 0;
233cd6e111bSTom Herbert }
234cd6e111bSTom Herbert 
2352ad17b19SChristoph Hellwig static const struct seq_operations kcm_seq_ops = {
2362ad17b19SChristoph Hellwig 	.show	= kcm_seq_show,
2372ad17b19SChristoph Hellwig 	.start	= kcm_seq_start,
2382ad17b19SChristoph Hellwig 	.next	= kcm_seq_next,
2392ad17b19SChristoph Hellwig 	.stop	= kcm_seq_stop,
2402ad17b19SChristoph Hellwig };
2412ad17b19SChristoph Hellwig 
kcm_stats_seq_show(struct seq_file * seq,void * v)242cd6e111bSTom Herbert static int kcm_stats_seq_show(struct seq_file *seq, void *v)
243cd6e111bSTom Herbert {
244cd6e111bSTom Herbert 	struct kcm_psock_stats psock_stats;
245cd6e111bSTom Herbert 	struct kcm_mux_stats mux_stats;
2469b73896aSTom Herbert 	struct strp_aggr_stats strp_stats;
247cd6e111bSTom Herbert 	struct kcm_mux *mux;
248cd6e111bSTom Herbert 	struct kcm_psock *psock;
249cd6e111bSTom Herbert 	struct net *net = seq->private;
250cd6e111bSTom Herbert 	struct kcm_net *knet = net_generic(net, kcm_net_id);
251cd6e111bSTom Herbert 
252cd6e111bSTom Herbert 	memset(&mux_stats, 0, sizeof(mux_stats));
253cd6e111bSTom Herbert 	memset(&psock_stats, 0, sizeof(psock_stats));
2549b73896aSTom Herbert 	memset(&strp_stats, 0, sizeof(strp_stats));
255cd6e111bSTom Herbert 
256cd6e111bSTom Herbert 	mutex_lock(&knet->mutex);
257cd6e111bSTom Herbert 
258cd6e111bSTom Herbert 	aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats);
259cd6e111bSTom Herbert 	aggregate_psock_stats(&knet->aggregate_psock_stats,
260cd6e111bSTom Herbert 			      &psock_stats);
2619b73896aSTom Herbert 	aggregate_strp_stats(&knet->aggregate_strp_stats,
2629b73896aSTom Herbert 			     &strp_stats);
263cd6e111bSTom Herbert 
264*1963507eSMadhuparna Bhowmik 	list_for_each_entry(mux, &knet->mux_list, kcm_mux_list) {
265cd6e111bSTom Herbert 		spin_lock_bh(&mux->lock);
266cd6e111bSTom Herbert 		aggregate_mux_stats(&mux->stats, &mux_stats);
267cd6e111bSTom Herbert 		aggregate_psock_stats(&mux->aggregate_psock_stats,
268cd6e111bSTom Herbert 				      &psock_stats);
2699b73896aSTom Herbert 		aggregate_strp_stats(&mux->aggregate_strp_stats,
2709b73896aSTom Herbert 				     &strp_stats);
2719b73896aSTom Herbert 		list_for_each_entry(psock, &mux->psocks, psock_list) {
272cd6e111bSTom Herbert 			aggregate_psock_stats(&psock->stats, &psock_stats);
2739b73896aSTom Herbert 			save_strp_stats(&psock->strp, &strp_stats);
2749b73896aSTom Herbert 		}
2759b73896aSTom Herbert 
276cd6e111bSTom Herbert 		spin_unlock_bh(&mux->lock);
277cd6e111bSTom Herbert 	}
278cd6e111bSTom Herbert 
279cd6e111bSTom Herbert 	mutex_unlock(&knet->mutex);
280cd6e111bSTom Herbert 
281cd6e111bSTom Herbert 	seq_printf(seq,
282cd6e111bSTom Herbert 		   "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n",
283cd6e111bSTom Herbert 		   "MUX",
284cd6e111bSTom Herbert 		   "RX-Msgs",
285cd6e111bSTom Herbert 		   "RX-Bytes",
286cd6e111bSTom Herbert 		   "TX-Msgs",
287cd6e111bSTom Herbert 		   "TX-Bytes",
288cd6e111bSTom Herbert 		   "TX-Retries",
289cd6e111bSTom Herbert 		   "Attach",
290cd6e111bSTom Herbert 		   "Unattach",
291cd6e111bSTom Herbert 		   "UnattchRsvd",
292cd6e111bSTom Herbert 		   "RX-RdyDrops");
293cd6e111bSTom Herbert 
294cd6e111bSTom Herbert 	seq_printf(seq,
295cd6e111bSTom Herbert 		   "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n",
296cd6e111bSTom Herbert 		   "",
297cd6e111bSTom Herbert 		   mux_stats.rx_msgs,
298cd6e111bSTom Herbert 		   mux_stats.rx_bytes,
299cd6e111bSTom Herbert 		   mux_stats.tx_msgs,
300cd6e111bSTom Herbert 		   mux_stats.tx_bytes,
301cd6e111bSTom Herbert 		   mux_stats.tx_retries,
302cd6e111bSTom Herbert 		   mux_stats.psock_attach,
303cd6e111bSTom Herbert 		   mux_stats.psock_unattach_rsvd,
304cd6e111bSTom Herbert 		   mux_stats.psock_unattach,
305cd6e111bSTom Herbert 		   mux_stats.rx_ready_drops);
306cd6e111bSTom Herbert 
307cd6e111bSTom Herbert 	seq_printf(seq,
3089b73896aSTom Herbert 		   "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
309cd6e111bSTom Herbert 		   "Psock",
310cd6e111bSTom Herbert 		   "RX-Msgs",
311cd6e111bSTom Herbert 		   "RX-Bytes",
312cd6e111bSTom Herbert 		   "TX-Msgs",
313cd6e111bSTom Herbert 		   "TX-Bytes",
314cd6e111bSTom Herbert 		   "Reserved",
315cd6e111bSTom Herbert 		   "Unreserved",
316cd6e111bSTom Herbert 		   "RX-Aborts",
3179b73896aSTom Herbert 		   "RX-Intr",
3189b73896aSTom Herbert 		   "RX-Unrecov",
319cd6e111bSTom Herbert 		   "RX-MemFail",
320cd6e111bSTom Herbert 		   "RX-NeedMor",
321cd6e111bSTom Herbert 		   "RX-BadLen",
3227ced95efSTom Herbert 		   "RX-TooBig",
32329152a34STom Herbert 		   "RX-Timeout",
324cd6e111bSTom Herbert 		   "TX-Aborts");
325cd6e111bSTom Herbert 
326cd6e111bSTom Herbert 	seq_printf(seq,
3279b73896aSTom Herbert 		   "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
328cd6e111bSTom Herbert 		   "",
329bbb03029STom Herbert 		   strp_stats.msgs,
330bbb03029STom Herbert 		   strp_stats.bytes,
331cd6e111bSTom Herbert 		   psock_stats.tx_msgs,
332cd6e111bSTom Herbert 		   psock_stats.tx_bytes,
333cd6e111bSTom Herbert 		   psock_stats.reserved,
334cd6e111bSTom Herbert 		   psock_stats.unreserved,
335bbb03029STom Herbert 		   strp_stats.aborts,
336bbb03029STom Herbert 		   strp_stats.interrupted,
337bbb03029STom Herbert 		   strp_stats.unrecov_intr,
338bbb03029STom Herbert 		   strp_stats.mem_fail,
339bbb03029STom Herbert 		   strp_stats.need_more_hdr,
340bbb03029STom Herbert 		   strp_stats.bad_hdr_len,
341bbb03029STom Herbert 		   strp_stats.msg_too_big,
342bbb03029STom Herbert 		   strp_stats.msg_timeouts,
343cd6e111bSTom Herbert 		   psock_stats.tx_aborts);
344cd6e111bSTom Herbert 
345cd6e111bSTom Herbert 	return 0;
346cd6e111bSTom Herbert }
347cd6e111bSTom Herbert 
kcm_proc_init_net(struct net * net)348cd6e111bSTom Herbert static int kcm_proc_init_net(struct net *net)
349cd6e111bSTom Herbert {
3503617d949SChristoph Hellwig 	if (!proc_create_net_single("kcm_stats", 0444, net->proc_net,
3513617d949SChristoph Hellwig 			 kcm_stats_seq_show, NULL))
352cd6e111bSTom Herbert 		goto out_kcm_stats;
353cd6e111bSTom Herbert 
354c3506372SChristoph Hellwig 	if (!proc_create_net("kcm", 0444, net->proc_net, &kcm_seq_ops,
355c3506372SChristoph Hellwig 			sizeof(struct kcm_proc_mux_state)))
356cd6e111bSTom Herbert 		goto out_kcm;
357cd6e111bSTom Herbert 
358cd6e111bSTom Herbert 	return 0;
359cd6e111bSTom Herbert 
360cd6e111bSTom Herbert out_kcm:
361cd6e111bSTom Herbert 	remove_proc_entry("kcm_stats", net->proc_net);
362cd6e111bSTom Herbert out_kcm_stats:
3632ad17b19SChristoph Hellwig 	return -ENOMEM;
364cd6e111bSTom Herbert }
365cd6e111bSTom Herbert 
kcm_proc_exit_net(struct net * net)366cd6e111bSTom Herbert static void kcm_proc_exit_net(struct net *net)
367cd6e111bSTom Herbert {
3682ad17b19SChristoph Hellwig 	remove_proc_entry("kcm", net->proc_net);
369cd6e111bSTom Herbert 	remove_proc_entry("kcm_stats", net->proc_net);
370cd6e111bSTom Herbert }
371cd6e111bSTom Herbert 
372cd6e111bSTom Herbert static struct pernet_operations kcm_net_ops = {
373cd6e111bSTom Herbert 	.init = kcm_proc_init_net,
374cd6e111bSTom Herbert 	.exit = kcm_proc_exit_net,
375cd6e111bSTom Herbert };
376cd6e111bSTom Herbert 
kcm_proc_init(void)377cd6e111bSTom Herbert int __init kcm_proc_init(void)
378cd6e111bSTom Herbert {
379cd6e111bSTom Herbert 	return register_pernet_subsys(&kcm_net_ops);
380cd6e111bSTom Herbert }
381cd6e111bSTom Herbert 
kcm_proc_exit(void)382cd6e111bSTom Herbert void __exit kcm_proc_exit(void)
383cd6e111bSTom Herbert {
384cd6e111bSTom Herbert 	unregister_pernet_subsys(&kcm_net_ops);
385cd6e111bSTom Herbert }
386cd6e111bSTom Herbert 
387cd6e111bSTom Herbert #endif /* CONFIG_PROC_FS */
388