xref: /openbmc/linux/net/sunrpc/stats.c (revision 2e8076df)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * linux/net/sunrpc/stats.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * procfs-based user access to generic RPC statistics. The stats files
61da177e4SLinus Torvalds  * reside in /proc/net/rpc.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * The read routines assume that the buffer passed in is just big enough.
91da177e4SLinus Torvalds  * If you implement an RPC service that has its own stats routine which
101da177e4SLinus Torvalds  * appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE
111da177e4SLinus Torvalds  * limit.
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
141da177e4SLinus Torvalds  */
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds #include <linux/module.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #include <linux/init.h>
201da177e4SLinus Torvalds #include <linux/kernel.h>
211da177e4SLinus Torvalds #include <linux/proc_fs.h>
221da177e4SLinus Torvalds #include <linux/seq_file.h>
231da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
241da177e4SLinus Torvalds #include <linux/sunrpc/svcsock.h>
2511c556b3SChuck Lever #include <linux/sunrpc/metrics.h>
262446ab60STrond Myklebust #include <linux/rcupdate.h>
274f42d0d5SPavel Emelyanov 
2840bf7eb3SChuck Lever #include <trace/events/sunrpc.h>
2940bf7eb3SChuck Lever 
304f42d0d5SPavel Emelyanov #include "netns.h"
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds #define RPCDBG_FACILITY	RPCDBG_MISC
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds /*
351da177e4SLinus Torvalds  * Get RPC client stats
361da177e4SLinus Torvalds  */
rpc_proc_show(struct seq_file * seq,void * v)371da177e4SLinus Torvalds static int rpc_proc_show(struct seq_file *seq, void *v) {
381da177e4SLinus Torvalds 	const struct rpc_stat	*statp = seq->private;
391da177e4SLinus Torvalds 	const struct rpc_program *prog = statp->program;
40ea339d46SChuck Lever 	unsigned int i, j;
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 	seq_printf(seq,
4349e31cbaSMax Kellermann 		"net %u %u %u %u\n",
441da177e4SLinus Torvalds 			statp->netcnt,
451da177e4SLinus Torvalds 			statp->netudpcnt,
461da177e4SLinus Torvalds 			statp->nettcpcnt,
471da177e4SLinus Torvalds 			statp->nettcpconn);
481da177e4SLinus Torvalds 	seq_printf(seq,
4949e31cbaSMax Kellermann 		"rpc %u %u %u\n",
501da177e4SLinus Torvalds 			statp->rpccnt,
511da177e4SLinus Torvalds 			statp->rpcretrans,
521da177e4SLinus Torvalds 			statp->rpcauthrefresh);
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds 	for (i = 0; i < prog->nrvers; i++) {
551da177e4SLinus Torvalds 		const struct rpc_version *vers = prog->version[i];
561da177e4SLinus Torvalds 		if (!vers)
571da177e4SLinus Torvalds 			continue;
5849e31cbaSMax Kellermann 		seq_printf(seq, "proc%u %u",
591da177e4SLinus Torvalds 					vers->number, vers->nrprocs);
601da177e4SLinus Torvalds 		for (j = 0; j < vers->nrprocs; j++)
611c5876ddSChristoph Hellwig 			seq_printf(seq, " %u", vers->counts[j]);
621da177e4SLinus Torvalds 		seq_putc(seq, '\n');
631da177e4SLinus Torvalds 	}
641da177e4SLinus Torvalds 	return 0;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
rpc_proc_open(struct inode * inode,struct file * file)671da177e4SLinus Torvalds static int rpc_proc_open(struct inode *inode, struct file *file)
681da177e4SLinus Torvalds {
69359745d7SMuchun Song 	return single_open(file, rpc_proc_show, pde_data(inode));
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
7297a32539SAlexey Dobriyan static const struct proc_ops rpc_proc_ops = {
7397a32539SAlexey Dobriyan 	.proc_open	= rpc_proc_open,
7497a32539SAlexey Dobriyan 	.proc_read	= seq_read,
7597a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
7697a32539SAlexey Dobriyan 	.proc_release	= single_release,
771da177e4SLinus Torvalds };
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds /*
801da177e4SLinus Torvalds  * Get RPC server stats
811da177e4SLinus Torvalds  */
svc_seq_show(struct seq_file * seq,const struct svc_stat * statp)827fd38af9SChristoph Hellwig void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp)
837fd38af9SChristoph Hellwig {
841da177e4SLinus Torvalds 	const struct svc_program *prog = statp->program;
851da177e4SLinus Torvalds 	const struct svc_version *vers;
8665ba3d24SChuck Lever 	unsigned int i, j, k;
8765ba3d24SChuck Lever 	unsigned long count;
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds 	seq_printf(seq,
9049e31cbaSMax Kellermann 		"net %u %u %u %u\n",
911da177e4SLinus Torvalds 			statp->netcnt,
921da177e4SLinus Torvalds 			statp->netudpcnt,
931da177e4SLinus Torvalds 			statp->nettcpcnt,
941da177e4SLinus Torvalds 			statp->nettcpconn);
951da177e4SLinus Torvalds 	seq_printf(seq,
9649e31cbaSMax Kellermann 		"rpc %u %u %u %u %u\n",
971da177e4SLinus Torvalds 			statp->rpccnt,
981da177e4SLinus Torvalds 			statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
991da177e4SLinus Torvalds 			statp->rpcbadfmt,
1001da177e4SLinus Torvalds 			statp->rpcbadauth,
1011da177e4SLinus Torvalds 			statp->rpcbadclnt);
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 	for (i = 0; i < prog->pg_nvers; i++) {
1047fd38af9SChristoph Hellwig 		vers = prog->pg_vers[i];
1057fd38af9SChristoph Hellwig 		if (!vers)
1061da177e4SLinus Torvalds 			continue;
10749e31cbaSMax Kellermann 		seq_printf(seq, "proc%d %u", i, vers->vs_nproc);
10865ba3d24SChuck Lever 		for (j = 0; j < vers->vs_nproc; j++) {
10965ba3d24SChuck Lever 			count = 0;
11065ba3d24SChuck Lever 			for_each_possible_cpu(k)
11165ba3d24SChuck Lever 				count += per_cpu(vers->vs_count[j], k);
11265ba3d24SChuck Lever 			seq_printf(seq, " %lu", count);
11365ba3d24SChuck Lever 		}
1141da177e4SLinus Torvalds 		seq_putc(seq, '\n');
1151da177e4SLinus Torvalds 	}
1161da177e4SLinus Torvalds }
11724c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_seq_show);
1181da177e4SLinus Torvalds 
11911c556b3SChuck Lever /**
12011c556b3SChuck Lever  * rpc_alloc_iostats - allocate an rpc_iostats structure
12111c556b3SChuck Lever  * @clnt: RPC program, version, and xprt
12211c556b3SChuck Lever  *
12311c556b3SChuck Lever  */
rpc_alloc_iostats(struct rpc_clnt * clnt)12411c556b3SChuck Lever struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
12511c556b3SChuck Lever {
126edef1297SChuck Lever 	struct rpc_iostats *stats;
127edef1297SChuck Lever 	int i;
128edef1297SChuck Lever 
129edef1297SChuck Lever 	stats = kcalloc(clnt->cl_maxproc, sizeof(*stats), GFP_KERNEL);
130edef1297SChuck Lever 	if (stats) {
131edef1297SChuck Lever 		for (i = 0; i < clnt->cl_maxproc; i++)
132edef1297SChuck Lever 			spin_lock_init(&stats[i].om_lock);
133edef1297SChuck Lever 	}
134edef1297SChuck Lever 	return stats;
13511c556b3SChuck Lever }
136e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_alloc_iostats);
13711c556b3SChuck Lever 
13811c556b3SChuck Lever /**
13911c556b3SChuck Lever  * rpc_free_iostats - release an rpc_iostats structure
14011c556b3SChuck Lever  * @stats: doomed rpc_iostats structure
14111c556b3SChuck Lever  *
14211c556b3SChuck Lever  */
rpc_free_iostats(struct rpc_iostats * stats)14311c556b3SChuck Lever void rpc_free_iostats(struct rpc_iostats *stats)
14411c556b3SChuck Lever {
14511c556b3SChuck Lever 	kfree(stats);
14611c556b3SChuck Lever }
147e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_free_iostats);
14811c556b3SChuck Lever 
14911c556b3SChuck Lever /**
150840210fcSWeston Andros Adamson  * rpc_count_iostats_metrics - tally up per-task stats
15111c556b3SChuck Lever  * @task: completed rpc_task
152840210fcSWeston Andros Adamson  * @op_metrics: stat structure for OP that will accumulate stats from @task
15311c556b3SChuck Lever  */
rpc_count_iostats_metrics(const struct rpc_task * task,struct rpc_iostats * op_metrics)154840210fcSWeston Andros Adamson void rpc_count_iostats_metrics(const struct rpc_task *task,
155840210fcSWeston Andros Adamson 			       struct rpc_iostats *op_metrics)
15611c556b3SChuck Lever {
15711c556b3SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
15840bf7eb3SChuck Lever 	ktime_t backlog, execute, now;
15911c556b3SChuck Lever 
160840210fcSWeston Andros Adamson 	if (!op_metrics || !req)
16111c556b3SChuck Lever 		return;
16255ae1aabSRicardo Labiaga 
163edef1297SChuck Lever 	now = ktime_get();
164edef1297SChuck Lever 	spin_lock(&op_metrics->om_lock);
165edef1297SChuck Lever 
16611c556b3SChuck Lever 	op_metrics->om_ops++;
167ae09531dSChuck Lever 	/* kernel API: om_ops must never become larger than om_ntrans */
168ae09531dSChuck Lever 	op_metrics->om_ntrans += max(req->rq_ntrans, 1);
16911c556b3SChuck Lever 	op_metrics->om_timeouts += task->tk_timeouts;
17011c556b3SChuck Lever 
171d60dbb20STrond Myklebust 	op_metrics->om_bytes_sent += req->rq_xmit_bytes_sent;
172dd2b63d0SRicardo Labiaga 	op_metrics->om_bytes_recv += req->rq_reply_bytes_recvd;
17311c556b3SChuck Lever 
17440bf7eb3SChuck Lever 	backlog = 0;
175ae09531dSChuck Lever 	if (ktime_to_ns(req->rq_xtime)) {
17640bf7eb3SChuck Lever 		backlog = ktime_sub(req->rq_xtime, task->tk_start);
17740bf7eb3SChuck Lever 		op_metrics->om_queue = ktime_add(op_metrics->om_queue, backlog);
178ae09531dSChuck Lever 	}
17940bf7eb3SChuck Lever 
180d60dbb20STrond Myklebust 	op_metrics->om_rtt = ktime_add(op_metrics->om_rtt, req->rq_rtt);
18111c556b3SChuck Lever 
18240bf7eb3SChuck Lever 	execute = ktime_sub(now, task->tk_start);
18340bf7eb3SChuck Lever 	op_metrics->om_execute = ktime_add(op_metrics->om_execute, execute);
184a332518fSDave Wysochanski 	if (task->tk_status < 0)
185a332518fSDave Wysochanski 		op_metrics->om_error_status++;
186edef1297SChuck Lever 
187edef1297SChuck Lever 	spin_unlock(&op_metrics->om_lock);
18840bf7eb3SChuck Lever 
18940bf7eb3SChuck Lever 	trace_rpc_stats_latency(req->rq_task, backlog, req->rq_rtt, execute);
19011c556b3SChuck Lever }
191840210fcSWeston Andros Adamson EXPORT_SYMBOL_GPL(rpc_count_iostats_metrics);
192840210fcSWeston Andros Adamson 
193840210fcSWeston Andros Adamson /**
194840210fcSWeston Andros Adamson  * rpc_count_iostats - tally up per-task stats
195840210fcSWeston Andros Adamson  * @task: completed rpc_task
196840210fcSWeston Andros Adamson  * @stats: array of stat structures
197840210fcSWeston Andros Adamson  *
198840210fcSWeston Andros Adamson  * Uses the statidx from @task
199840210fcSWeston Andros Adamson  */
rpc_count_iostats(const struct rpc_task * task,struct rpc_iostats * stats)200840210fcSWeston Andros Adamson void rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats)
201840210fcSWeston Andros Adamson {
202840210fcSWeston Andros Adamson 	rpc_count_iostats_metrics(task,
203840210fcSWeston Andros Adamson 				  &stats[task->tk_msg.rpc_proc->p_statidx]);
204840210fcSWeston Andros Adamson }
2050a702195SWeston Andros Adamson EXPORT_SYMBOL_GPL(rpc_count_iostats);
20611c556b3SChuck Lever 
_print_name(struct seq_file * seq,unsigned int op,const struct rpc_procinfo * procs)207ec535ce1SAdrian Bunk static void _print_name(struct seq_file *seq, unsigned int op,
208499b4988SChristoph Hellwig 			const struct rpc_procinfo *procs)
209cc0175c1SChuck Lever {
210cc0175c1SChuck Lever 	if (procs[op].p_name)
211cc0175c1SChuck Lever 		seq_printf(seq, "\t%12s: ", procs[op].p_name);
212cc0175c1SChuck Lever 	else if (op == 0)
213cc0175c1SChuck Lever 		seq_printf(seq, "\t        NULL: ");
214cc0175c1SChuck Lever 	else
215cc0175c1SChuck Lever 		seq_printf(seq, "\t%12u: ", op);
216cc0175c1SChuck Lever }
217cc0175c1SChuck Lever 
_add_rpc_iostats(struct rpc_iostats * a,struct rpc_iostats * b)218189e1955SDave Wysochanski static void _add_rpc_iostats(struct rpc_iostats *a, struct rpc_iostats *b)
219189e1955SDave Wysochanski {
220189e1955SDave Wysochanski 	a->om_ops += b->om_ops;
221189e1955SDave Wysochanski 	a->om_ntrans += b->om_ntrans;
222189e1955SDave Wysochanski 	a->om_timeouts += b->om_timeouts;
223189e1955SDave Wysochanski 	a->om_bytes_sent += b->om_bytes_sent;
224189e1955SDave Wysochanski 	a->om_bytes_recv += b->om_bytes_recv;
225189e1955SDave Wysochanski 	a->om_queue = ktime_add(a->om_queue, b->om_queue);
226189e1955SDave Wysochanski 	a->om_rtt = ktime_add(a->om_rtt, b->om_rtt);
227189e1955SDave Wysochanski 	a->om_execute = ktime_add(a->om_execute, b->om_execute);
228a332518fSDave Wysochanski 	a->om_error_status += b->om_error_status;
229189e1955SDave Wysochanski }
230189e1955SDave Wysochanski 
_print_rpc_iostats(struct seq_file * seq,struct rpc_iostats * stats,int op,const struct rpc_procinfo * procs)231acdce5fbSDave Wysochanski static void _print_rpc_iostats(struct seq_file *seq, struct rpc_iostats *stats,
232acdce5fbSDave Wysochanski 			       int op, const struct rpc_procinfo *procs)
233acdce5fbSDave Wysochanski {
234acdce5fbSDave Wysochanski 	_print_name(seq, op, procs);
235a332518fSDave Wysochanski 	seq_printf(seq, "%lu %lu %lu %llu %llu %llu %llu %llu %lu\n",
236acdce5fbSDave Wysochanski 		   stats->om_ops,
237acdce5fbSDave Wysochanski 		   stats->om_ntrans,
238acdce5fbSDave Wysochanski 		   stats->om_timeouts,
239acdce5fbSDave Wysochanski 		   stats->om_bytes_sent,
240acdce5fbSDave Wysochanski 		   stats->om_bytes_recv,
241acdce5fbSDave Wysochanski 		   ktime_to_ms(stats->om_queue),
242acdce5fbSDave Wysochanski 		   ktime_to_ms(stats->om_rtt),
243a332518fSDave Wysochanski 		   ktime_to_ms(stats->om_execute),
244a332518fSDave Wysochanski 		   stats->om_error_status);
245acdce5fbSDave Wysochanski }
246acdce5fbSDave Wysochanski 
do_print_stats(struct rpc_clnt * clnt,struct rpc_xprt * xprt,void * seqv)24710db5691SNeilBrown static int do_print_stats(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *seqv)
24810db5691SNeilBrown {
24910db5691SNeilBrown 	struct seq_file *seq = seqv;
25010db5691SNeilBrown 
25110db5691SNeilBrown 	xprt->ops->print_stats(xprt, seq);
25210db5691SNeilBrown 	return 0;
25310db5691SNeilBrown }
25410db5691SNeilBrown 
rpc_clnt_show_stats(struct seq_file * seq,struct rpc_clnt * clnt)255016583d7SDave Wysochanski void rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt)
25611c556b3SChuck Lever {
25711c556b3SChuck Lever 	unsigned int op, maxproc = clnt->cl_maxproc;
25811c556b3SChuck Lever 
259016583d7SDave Wysochanski 	if (!clnt->cl_metrics)
26011c556b3SChuck Lever 		return;
26111c556b3SChuck Lever 
26211c556b3SChuck Lever 	seq_printf(seq, "\tRPC iostats version: %s  ", RPC_IOSTATS_VERS);
26311c556b3SChuck Lever 	seq_printf(seq, "p/v: %u/%u (%s)\n",
26455909f21STrond Myklebust 			clnt->cl_prog, clnt->cl_vers, clnt->cl_program->name);
26511c556b3SChuck Lever 
26610db5691SNeilBrown 	rpc_clnt_iterate_for_each_xprt(clnt, do_print_stats, seq);
26711c556b3SChuck Lever 
26811c556b3SChuck Lever 	seq_printf(seq, "\tper-op statistics\n");
26911c556b3SChuck Lever 	for (op = 0; op < maxproc; op++) {
270016583d7SDave Wysochanski 		struct rpc_iostats stats = {};
271016583d7SDave Wysochanski 		struct rpc_clnt *next = clnt;
272016583d7SDave Wysochanski 		do {
273016583d7SDave Wysochanski 			_add_rpc_iostats(&stats, &next->cl_metrics[op]);
274016583d7SDave Wysochanski 			if (next == next->cl_parent)
275016583d7SDave Wysochanski 				break;
276016583d7SDave Wysochanski 			next = next->cl_parent;
277016583d7SDave Wysochanski 		} while (next);
278016583d7SDave Wysochanski 		_print_rpc_iostats(seq, &stats, op, clnt->cl_procinfo);
27911c556b3SChuck Lever 	}
28011c556b3SChuck Lever }
281016583d7SDave Wysochanski EXPORT_SYMBOL_GPL(rpc_clnt_show_stats);
28211c556b3SChuck Lever 
2831da177e4SLinus Torvalds /*
2841da177e4SLinus Torvalds  * Register/unregister RPC proc files
2851da177e4SLinus Torvalds  */
2861da177e4SLinus Torvalds static inline struct proc_dir_entry *
do_register(struct net * net,const char * name,void * data,const struct proc_ops * proc_ops)287ec7652aaSStanislav Kinsbursky do_register(struct net *net, const char *name, void *data,
28897a32539SAlexey Dobriyan 	    const struct proc_ops *proc_ops)
2891da177e4SLinus Torvalds {
2904f42d0d5SPavel Emelyanov 	struct sunrpc_net *sn;
2911da177e4SLinus Torvalds 
2924f42d0d5SPavel Emelyanov 	dprintk("RPC:       registering /proc/net/rpc/%s\n", name);
293ec7652aaSStanislav Kinsbursky 	sn = net_generic(net, sunrpc_net_id);
29497a32539SAlexey Dobriyan 	return proc_create_data(name, 0, sn->proc_net_rpc, proc_ops, data);
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds struct proc_dir_entry *
rpc_proc_register(struct net * net,struct rpc_stat * statp)298ec7652aaSStanislav Kinsbursky rpc_proc_register(struct net *net, struct rpc_stat *statp)
2991da177e4SLinus Torvalds {
30097a32539SAlexey Dobriyan 	return do_register(net, statp->program->name, statp, &rpc_proc_ops);
3011da177e4SLinus Torvalds }
302e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_proc_register);
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds void
rpc_proc_unregister(struct net * net,const char * name)305ec7652aaSStanislav Kinsbursky rpc_proc_unregister(struct net *net, const char *name)
3061da177e4SLinus Torvalds {
3074f42d0d5SPavel Emelyanov 	struct sunrpc_net *sn;
3084f42d0d5SPavel Emelyanov 
309ec7652aaSStanislav Kinsbursky 	sn = net_generic(net, sunrpc_net_id);
3104f42d0d5SPavel Emelyanov 	remove_proc_entry(name, sn->proc_net_rpc);
3111da177e4SLinus Torvalds }
312e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_proc_unregister);
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds struct proc_dir_entry *
svc_proc_register(struct net * net,struct svc_stat * statp,const struct proc_ops * proc_ops)31597a32539SAlexey Dobriyan svc_proc_register(struct net *net, struct svc_stat *statp, const struct proc_ops *proc_ops)
3161da177e4SLinus Torvalds {
317*2e8076dfSJosef Bacik 	return do_register(net, statp->program->pg_name, net, proc_ops);
3181da177e4SLinus Torvalds }
31924c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_proc_register);
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds void
svc_proc_unregister(struct net * net,const char * name)322246590f5SStanislav Kinsbursky svc_proc_unregister(struct net *net, const char *name)
3231da177e4SLinus Torvalds {
3244f42d0d5SPavel Emelyanov 	struct sunrpc_net *sn;
3254f42d0d5SPavel Emelyanov 
326246590f5SStanislav Kinsbursky 	sn = net_generic(net, sunrpc_net_id);
3274f42d0d5SPavel Emelyanov 	remove_proc_entry(name, sn->proc_net_rpc);
3281da177e4SLinus Torvalds }
32924c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_proc_unregister);
3301da177e4SLinus Torvalds 
rpc_proc_init(struct net * net)3314f42d0d5SPavel Emelyanov int rpc_proc_init(struct net *net)
3321da177e4SLinus Torvalds {
3334f42d0d5SPavel Emelyanov 	struct sunrpc_net *sn;
3344f42d0d5SPavel Emelyanov 
3351da177e4SLinus Torvalds 	dprintk("RPC:       registering /proc/net/rpc\n");
3364f42d0d5SPavel Emelyanov 	sn = net_generic(net, sunrpc_net_id);
3374f42d0d5SPavel Emelyanov 	sn->proc_net_rpc = proc_mkdir("rpc", net->proc_net);
3384f42d0d5SPavel Emelyanov 	if (sn->proc_net_rpc == NULL)
3394f42d0d5SPavel Emelyanov 		return -ENOMEM;
3404f42d0d5SPavel Emelyanov 
3414f42d0d5SPavel Emelyanov 	return 0;
3421da177e4SLinus Torvalds }
3431da177e4SLinus Torvalds 
rpc_proc_exit(struct net * net)3444f42d0d5SPavel Emelyanov void rpc_proc_exit(struct net *net)
3451da177e4SLinus Torvalds {
3461da177e4SLinus Torvalds 	dprintk("RPC:       unregistering /proc/net/rpc\n");
3474f42d0d5SPavel Emelyanov 	remove_proc_entry("rpc", net->proc_net);
3481da177e4SLinus Torvalds }
349