summaryrefslogtreecommitdiffstats
path: root/net/sunrpc/sysctl.c
blob: 859d55853aa45f5cedc8c821c1051fa3fff802f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * linux/net/sunrpc/sysctl.c
 *
 * Sysctl interface to sunrpc module. This is for debugging only now.
 *
 * I would prefer to register the sunrpc table below sys/net, but that's
 * impossible at the moment.
 */

#include <linux/version.h>
#include <linux/types.h>
#include <linux/linkage.h>
#include <linux/ctype.h>
#include <linux/fs.h>
#include <linux/sysctl.h>
#if LINUX_VERSION_CODE >= 0x020100
#include <asm/uaccess.h>
#else
# include <linux/mm.h>
# define copy_from_user		memcpy_fromfs
# define copy_to_user		memcpy_tofs
# define access_ok		!verify_area
#endif
#include <linux/sunrpc/types.h>

/*
 * Declare the debug flags here
 */
unsigned int	rpc_debug  = 0;
unsigned int	nfs_debug  = 0;
unsigned int	nfsd_debug = 0;
unsigned int	nlm_debug  = 0;

#ifdef RPC_DEBUG

static struct ctl_table_header *sunrpc_table_header = NULL;
static ctl_table		sunrpc_table[];

void
rpc_register_sysctl(void)
{
	if (sunrpc_table_header)
		return;
	sunrpc_table_header = register_sysctl_table(sunrpc_table, 1);
}

void
rpc_unregister_sysctl(void)
{
	if (!sunrpc_table_header)
		return;
	unregister_sysctl_table(sunrpc_table_header);
}

int
proc_dodebug(ctl_table *table, int write, struct file *file,
				void *buffer, size_t *lenp)
{
	char		tmpbuf[20], *p, c;
	unsigned int	value;
	int		left, len;

	if ((file->f_pos && !write) || !*lenp) {
		*lenp = 0;
		return 0;
	}

	left = *lenp;

	if (write) {
		if (!access_ok(VERIFY_READ, buffer, left))
			return -EFAULT;
		p = (char *) buffer;
#if LINUX_VERSION_CODE >= 0x020100
		while (left && __get_user(c, p) >= 0 && isspace(c))
			left--, p++;
#else
		while (left && (c = get_fs_byte(p)) >= 0 && isspace(c))
			left--, p++;
#endif
		if (!left)
			goto done;

		if (left > sizeof(tmpbuf) - 1)
			return -EINVAL;
		copy_from_user(tmpbuf, p, left);
		tmpbuf[left] = '\0';

		for (p = tmpbuf, value = 0; '0' <= *p && *p <= '9'; p++, left--)
			value = 10 * value + (*p - '0');
		if (*p && !isspace(*p))
			return -EINVAL;
		while (left && isspace(*p))
			left--, p++;
		*(unsigned int *) table->data = value;
	} else {
		if (!access_ok(VERIFY_WRITE, buffer, left))
			return -EFAULT;
		len = sprintf(tmpbuf, "%d", *(unsigned int *) table->data);
		if (len > left)
			len = left;
		copy_to_user(buffer, tmpbuf, len);
		if ((left -= len) > 0) {
			put_user('\n', (char *)buffer + len);
			left--;
		}
	}

done:
	*lenp -= left;
	file->f_pos += *lenp;
	return 0;
}

#define DIRENTRY(nam1, nam2, child)	\
	{CTL_##nam1, #nam2, NULL, 0, 0555, child }
#define DBGENTRY(nam1, nam2)	\
	{CTL_##nam1##DEBUG, #nam2 "_debug", &nam2##_debug, sizeof(int),\
	 0644, NULL, &proc_dodebug}

static ctl_table		debug_table[] = {
	DBGENTRY(RPC,  rpc),
	DBGENTRY(NFS,  nfs),
	DBGENTRY(NFSD, nfsd),
	DBGENTRY(NLM,  nlm),
	{0}
};

static ctl_table		sunrpc_table[] = {
	DIRENTRY(SUNRPC, sunrpc, debug_table),
	{0}
};

#endif