18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/net/sunrpc/stats.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * procfs-based user access to generic RPC statistics. The stats files
68c2ecf20Sopenharmony_ci * reside in /proc/net/rpc.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * The read routines assume that the buffer passed in is just big enough.
98c2ecf20Sopenharmony_ci * If you implement an RPC service that has its own stats routine which
108c2ecf20Sopenharmony_ci * appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE
118c2ecf20Sopenharmony_ci * limit.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/init.h>
208c2ecf20Sopenharmony_ci#include <linux/kernel.h>
218c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
228c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
238c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h>
248c2ecf20Sopenharmony_ci#include <linux/sunrpc/svcsock.h>
258c2ecf20Sopenharmony_ci#include <linux/sunrpc/metrics.h>
268c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <trace/events/sunrpc.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "netns.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define RPCDBG_FACILITY	RPCDBG_MISC
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/*
358c2ecf20Sopenharmony_ci * Get RPC client stats
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_cistatic int rpc_proc_show(struct seq_file *seq, void *v) {
388c2ecf20Sopenharmony_ci	const struct rpc_stat	*statp = seq->private;
398c2ecf20Sopenharmony_ci	const struct rpc_program *prog = statp->program;
408c2ecf20Sopenharmony_ci	unsigned int i, j;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	seq_printf(seq,
438c2ecf20Sopenharmony_ci		"net %u %u %u %u\n",
448c2ecf20Sopenharmony_ci			statp->netcnt,
458c2ecf20Sopenharmony_ci			statp->netudpcnt,
468c2ecf20Sopenharmony_ci			statp->nettcpcnt,
478c2ecf20Sopenharmony_ci			statp->nettcpconn);
488c2ecf20Sopenharmony_ci	seq_printf(seq,
498c2ecf20Sopenharmony_ci		"rpc %u %u %u\n",
508c2ecf20Sopenharmony_ci			statp->rpccnt,
518c2ecf20Sopenharmony_ci			statp->rpcretrans,
528c2ecf20Sopenharmony_ci			statp->rpcauthrefresh);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	for (i = 0; i < prog->nrvers; i++) {
558c2ecf20Sopenharmony_ci		const struct rpc_version *vers = prog->version[i];
568c2ecf20Sopenharmony_ci		if (!vers)
578c2ecf20Sopenharmony_ci			continue;
588c2ecf20Sopenharmony_ci		seq_printf(seq, "proc%u %u",
598c2ecf20Sopenharmony_ci					vers->number, vers->nrprocs);
608c2ecf20Sopenharmony_ci		for (j = 0; j < vers->nrprocs; j++)
618c2ecf20Sopenharmony_ci			seq_printf(seq, " %u", vers->counts[j]);
628c2ecf20Sopenharmony_ci		seq_putc(seq, '\n');
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int rpc_proc_open(struct inode *inode, struct file *file)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	return single_open(file, rpc_proc_show, PDE_DATA(inode));
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic const struct proc_ops rpc_proc_ops = {
738c2ecf20Sopenharmony_ci	.proc_open	= rpc_proc_open,
748c2ecf20Sopenharmony_ci	.proc_read	= seq_read,
758c2ecf20Sopenharmony_ci	.proc_lseek	= seq_lseek,
768c2ecf20Sopenharmony_ci	.proc_release	= single_release,
778c2ecf20Sopenharmony_ci};
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * Get RPC server stats
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_civoid svc_seq_show(struct seq_file *seq, const struct svc_stat *statp)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	const struct svc_program *prog = statp->program;
858c2ecf20Sopenharmony_ci	const struct svc_version *vers;
868c2ecf20Sopenharmony_ci	unsigned int i, j;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	seq_printf(seq,
898c2ecf20Sopenharmony_ci		"net %u %u %u %u\n",
908c2ecf20Sopenharmony_ci			statp->netcnt,
918c2ecf20Sopenharmony_ci			statp->netudpcnt,
928c2ecf20Sopenharmony_ci			statp->nettcpcnt,
938c2ecf20Sopenharmony_ci			statp->nettcpconn);
948c2ecf20Sopenharmony_ci	seq_printf(seq,
958c2ecf20Sopenharmony_ci		"rpc %u %u %u %u %u\n",
968c2ecf20Sopenharmony_ci			statp->rpccnt,
978c2ecf20Sopenharmony_ci			statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
988c2ecf20Sopenharmony_ci			statp->rpcbadfmt,
998c2ecf20Sopenharmony_ci			statp->rpcbadauth,
1008c2ecf20Sopenharmony_ci			statp->rpcbadclnt);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	for (i = 0; i < prog->pg_nvers; i++) {
1038c2ecf20Sopenharmony_ci		vers = prog->pg_vers[i];
1048c2ecf20Sopenharmony_ci		if (!vers)
1058c2ecf20Sopenharmony_ci			continue;
1068c2ecf20Sopenharmony_ci		seq_printf(seq, "proc%d %u", i, vers->vs_nproc);
1078c2ecf20Sopenharmony_ci		for (j = 0; j < vers->vs_nproc; j++)
1088c2ecf20Sopenharmony_ci			seq_printf(seq, " %u", vers->vs_count[j]);
1098c2ecf20Sopenharmony_ci		seq_putc(seq, '\n');
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_seq_show);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/**
1158c2ecf20Sopenharmony_ci * rpc_alloc_iostats - allocate an rpc_iostats structure
1168c2ecf20Sopenharmony_ci * @clnt: RPC program, version, and xprt
1178c2ecf20Sopenharmony_ci *
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_cistruct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct rpc_iostats *stats;
1228c2ecf20Sopenharmony_ci	int i;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	stats = kcalloc(clnt->cl_maxproc, sizeof(*stats), GFP_KERNEL);
1258c2ecf20Sopenharmony_ci	if (stats) {
1268c2ecf20Sopenharmony_ci		for (i = 0; i < clnt->cl_maxproc; i++)
1278c2ecf20Sopenharmony_ci			spin_lock_init(&stats[i].om_lock);
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci	return stats;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_alloc_iostats);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/**
1348c2ecf20Sopenharmony_ci * rpc_free_iostats - release an rpc_iostats structure
1358c2ecf20Sopenharmony_ci * @stats: doomed rpc_iostats structure
1368c2ecf20Sopenharmony_ci *
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_civoid rpc_free_iostats(struct rpc_iostats *stats)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	kfree(stats);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_free_iostats);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/**
1458c2ecf20Sopenharmony_ci * rpc_count_iostats_metrics - tally up per-task stats
1468c2ecf20Sopenharmony_ci * @task: completed rpc_task
1478c2ecf20Sopenharmony_ci * @op_metrics: stat structure for OP that will accumulate stats from @task
1488c2ecf20Sopenharmony_ci */
1498c2ecf20Sopenharmony_civoid rpc_count_iostats_metrics(const struct rpc_task *task,
1508c2ecf20Sopenharmony_ci			       struct rpc_iostats *op_metrics)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct rpc_rqst *req = task->tk_rqstp;
1538c2ecf20Sopenharmony_ci	ktime_t backlog, execute, now;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (!op_metrics || !req)
1568c2ecf20Sopenharmony_ci		return;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	now = ktime_get();
1598c2ecf20Sopenharmony_ci	spin_lock(&op_metrics->om_lock);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	op_metrics->om_ops++;
1628c2ecf20Sopenharmony_ci	/* kernel API: om_ops must never become larger than om_ntrans */
1638c2ecf20Sopenharmony_ci	op_metrics->om_ntrans += max(req->rq_ntrans, 1);
1648c2ecf20Sopenharmony_ci	op_metrics->om_timeouts += task->tk_timeouts;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	op_metrics->om_bytes_sent += req->rq_xmit_bytes_sent;
1678c2ecf20Sopenharmony_ci	op_metrics->om_bytes_recv += req->rq_reply_bytes_recvd;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	backlog = 0;
1708c2ecf20Sopenharmony_ci	if (ktime_to_ns(req->rq_xtime)) {
1718c2ecf20Sopenharmony_ci		backlog = ktime_sub(req->rq_xtime, task->tk_start);
1728c2ecf20Sopenharmony_ci		op_metrics->om_queue = ktime_add(op_metrics->om_queue, backlog);
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	op_metrics->om_rtt = ktime_add(op_metrics->om_rtt, req->rq_rtt);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	execute = ktime_sub(now, task->tk_start);
1788c2ecf20Sopenharmony_ci	op_metrics->om_execute = ktime_add(op_metrics->om_execute, execute);
1798c2ecf20Sopenharmony_ci	if (task->tk_status < 0)
1808c2ecf20Sopenharmony_ci		op_metrics->om_error_status++;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	spin_unlock(&op_metrics->om_lock);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	trace_rpc_stats_latency(req->rq_task, backlog, req->rq_rtt, execute);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_count_iostats_metrics);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/**
1898c2ecf20Sopenharmony_ci * rpc_count_iostats - tally up per-task stats
1908c2ecf20Sopenharmony_ci * @task: completed rpc_task
1918c2ecf20Sopenharmony_ci * @stats: array of stat structures
1928c2ecf20Sopenharmony_ci *
1938c2ecf20Sopenharmony_ci * Uses the statidx from @task
1948c2ecf20Sopenharmony_ci */
1958c2ecf20Sopenharmony_civoid rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	rpc_count_iostats_metrics(task,
1988c2ecf20Sopenharmony_ci				  &stats[task->tk_msg.rpc_proc->p_statidx]);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_count_iostats);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic void _print_name(struct seq_file *seq, unsigned int op,
2038c2ecf20Sopenharmony_ci			const struct rpc_procinfo *procs)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	if (procs[op].p_name)
2068c2ecf20Sopenharmony_ci		seq_printf(seq, "\t%12s: ", procs[op].p_name);
2078c2ecf20Sopenharmony_ci	else if (op == 0)
2088c2ecf20Sopenharmony_ci		seq_printf(seq, "\t        NULL: ");
2098c2ecf20Sopenharmony_ci	else
2108c2ecf20Sopenharmony_ci		seq_printf(seq, "\t%12u: ", op);
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic void _add_rpc_iostats(struct rpc_iostats *a, struct rpc_iostats *b)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	a->om_ops += b->om_ops;
2168c2ecf20Sopenharmony_ci	a->om_ntrans += b->om_ntrans;
2178c2ecf20Sopenharmony_ci	a->om_timeouts += b->om_timeouts;
2188c2ecf20Sopenharmony_ci	a->om_bytes_sent += b->om_bytes_sent;
2198c2ecf20Sopenharmony_ci	a->om_bytes_recv += b->om_bytes_recv;
2208c2ecf20Sopenharmony_ci	a->om_queue = ktime_add(a->om_queue, b->om_queue);
2218c2ecf20Sopenharmony_ci	a->om_rtt = ktime_add(a->om_rtt, b->om_rtt);
2228c2ecf20Sopenharmony_ci	a->om_execute = ktime_add(a->om_execute, b->om_execute);
2238c2ecf20Sopenharmony_ci	a->om_error_status += b->om_error_status;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic void _print_rpc_iostats(struct seq_file *seq, struct rpc_iostats *stats,
2278c2ecf20Sopenharmony_ci			       int op, const struct rpc_procinfo *procs)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	_print_name(seq, op, procs);
2308c2ecf20Sopenharmony_ci	seq_printf(seq, "%lu %lu %lu %llu %llu %llu %llu %llu %lu\n",
2318c2ecf20Sopenharmony_ci		   stats->om_ops,
2328c2ecf20Sopenharmony_ci		   stats->om_ntrans,
2338c2ecf20Sopenharmony_ci		   stats->om_timeouts,
2348c2ecf20Sopenharmony_ci		   stats->om_bytes_sent,
2358c2ecf20Sopenharmony_ci		   stats->om_bytes_recv,
2368c2ecf20Sopenharmony_ci		   ktime_to_ms(stats->om_queue),
2378c2ecf20Sopenharmony_ci		   ktime_to_ms(stats->om_rtt),
2388c2ecf20Sopenharmony_ci		   ktime_to_ms(stats->om_execute),
2398c2ecf20Sopenharmony_ci		   stats->om_error_status);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int do_print_stats(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *seqv)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct seq_file *seq = seqv;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	xprt->ops->print_stats(xprt, seq);
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_civoid rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	unsigned int op, maxproc = clnt->cl_maxproc;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (!clnt->cl_metrics)
2558c2ecf20Sopenharmony_ci		return;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	seq_printf(seq, "\tRPC iostats version: %s  ", RPC_IOSTATS_VERS);
2588c2ecf20Sopenharmony_ci	seq_printf(seq, "p/v: %u/%u (%s)\n",
2598c2ecf20Sopenharmony_ci			clnt->cl_prog, clnt->cl_vers, clnt->cl_program->name);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	rpc_clnt_iterate_for_each_xprt(clnt, do_print_stats, seq);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	seq_printf(seq, "\tper-op statistics\n");
2648c2ecf20Sopenharmony_ci	for (op = 0; op < maxproc; op++) {
2658c2ecf20Sopenharmony_ci		struct rpc_iostats stats = {};
2668c2ecf20Sopenharmony_ci		struct rpc_clnt *next = clnt;
2678c2ecf20Sopenharmony_ci		do {
2688c2ecf20Sopenharmony_ci			_add_rpc_iostats(&stats, &next->cl_metrics[op]);
2698c2ecf20Sopenharmony_ci			if (next == next->cl_parent)
2708c2ecf20Sopenharmony_ci				break;
2718c2ecf20Sopenharmony_ci			next = next->cl_parent;
2728c2ecf20Sopenharmony_ci		} while (next);
2738c2ecf20Sopenharmony_ci		_print_rpc_iostats(seq, &stats, op, clnt->cl_procinfo);
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_clnt_show_stats);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/*
2798c2ecf20Sopenharmony_ci * Register/unregister RPC proc files
2808c2ecf20Sopenharmony_ci */
2818c2ecf20Sopenharmony_cistatic inline struct proc_dir_entry *
2828c2ecf20Sopenharmony_cido_register(struct net *net, const char *name, void *data,
2838c2ecf20Sopenharmony_ci	    const struct proc_ops *proc_ops)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct sunrpc_net *sn;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	dprintk("RPC:       registering /proc/net/rpc/%s\n", name);
2888c2ecf20Sopenharmony_ci	sn = net_generic(net, sunrpc_net_id);
2898c2ecf20Sopenharmony_ci	return proc_create_data(name, 0, sn->proc_net_rpc, proc_ops, data);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistruct proc_dir_entry *
2938c2ecf20Sopenharmony_cirpc_proc_register(struct net *net, struct rpc_stat *statp)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	return do_register(net, statp->program->name, statp, &rpc_proc_ops);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_proc_register);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_civoid
3008c2ecf20Sopenharmony_cirpc_proc_unregister(struct net *net, const char *name)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct sunrpc_net *sn;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	sn = net_generic(net, sunrpc_net_id);
3058c2ecf20Sopenharmony_ci	remove_proc_entry(name, sn->proc_net_rpc);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_proc_unregister);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistruct proc_dir_entry *
3108c2ecf20Sopenharmony_cisvc_proc_register(struct net *net, struct svc_stat *statp, const struct proc_ops *proc_ops)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	return do_register(net, statp->program->pg_name, statp, proc_ops);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_proc_register);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_civoid
3178c2ecf20Sopenharmony_cisvc_proc_unregister(struct net *net, const char *name)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct sunrpc_net *sn;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	sn = net_generic(net, sunrpc_net_id);
3228c2ecf20Sopenharmony_ci	remove_proc_entry(name, sn->proc_net_rpc);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(svc_proc_unregister);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciint rpc_proc_init(struct net *net)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct sunrpc_net *sn;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	dprintk("RPC:       registering /proc/net/rpc\n");
3318c2ecf20Sopenharmony_ci	sn = net_generic(net, sunrpc_net_id);
3328c2ecf20Sopenharmony_ci	sn->proc_net_rpc = proc_mkdir("rpc", net->proc_net);
3338c2ecf20Sopenharmony_ci	if (sn->proc_net_rpc == NULL)
3348c2ecf20Sopenharmony_ci		return -ENOMEM;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return 0;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_civoid rpc_proc_exit(struct net *net)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	dprintk("RPC:       unregistering /proc/net/rpc\n");
3428c2ecf20Sopenharmony_ci	remove_proc_entry("rpc", net->proc_net);
3438c2ecf20Sopenharmony_ci}
344