1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/net/sunrpc/sysctl.c |
4 | * |
5 | * Sysctl interface to sunrpc module. |
6 | * |
7 | * I would prefer to register the sunrpc table below sys/net, but that's |
8 | * impossible at the moment. |
9 | */ |
10 | |
11 | #include <linux/types.h> |
12 | #include <linux/linkage.h> |
13 | #include <linux/ctype.h> |
14 | #include <linux/fs.h> |
15 | #include <linux/sysctl.h> |
16 | #include <linux/module.h> |
17 | |
18 | #include <linux/uaccess.h> |
19 | #include <linux/sunrpc/types.h> |
20 | #include <linux/sunrpc/sched.h> |
21 | #include <linux/sunrpc/stats.h> |
22 | #include <linux/sunrpc/svc_xprt.h> |
23 | |
24 | #include "netns.h" |
25 | |
26 | /* |
27 | * Declare the debug flags here |
28 | */ |
29 | unsigned int rpc_debug; |
30 | EXPORT_SYMBOL_GPL(rpc_debug); |
31 | |
32 | unsigned int nfs_debug; |
33 | EXPORT_SYMBOL_GPL(nfs_debug); |
34 | |
35 | unsigned int nfsd_debug; |
36 | EXPORT_SYMBOL_GPL(nfsd_debug); |
37 | |
38 | unsigned int nlm_debug; |
39 | EXPORT_SYMBOL_GPL(nlm_debug); |
40 | |
41 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
42 | |
43 | static int proc_do_xprt(struct ctl_table *table, int write, |
44 | void *buffer, size_t *lenp, loff_t *ppos) |
45 | { |
46 | char tmpbuf[256]; |
47 | ssize_t len; |
48 | |
49 | if (write || *ppos) { |
50 | *lenp = 0; |
51 | return 0; |
52 | } |
53 | len = svc_print_xprts(buf: tmpbuf, maxlen: sizeof(tmpbuf)); |
54 | len = memory_read_from_buffer(to: buffer, count: *lenp, ppos, from: tmpbuf, available: len); |
55 | |
56 | if (len < 0) { |
57 | *lenp = 0; |
58 | return -EINVAL; |
59 | } |
60 | *lenp = len; |
61 | return 0; |
62 | } |
63 | |
64 | static int |
65 | proc_dodebug(struct ctl_table *table, int write, void *buffer, size_t *lenp, |
66 | loff_t *ppos) |
67 | { |
68 | char tmpbuf[20], *s = NULL; |
69 | char *p; |
70 | unsigned int value; |
71 | size_t left, len; |
72 | |
73 | if ((*ppos && !write) || !*lenp) { |
74 | *lenp = 0; |
75 | return 0; |
76 | } |
77 | |
78 | left = *lenp; |
79 | |
80 | if (write) { |
81 | p = buffer; |
82 | while (left && isspace(*p)) { |
83 | left--; |
84 | p++; |
85 | } |
86 | if (!left) |
87 | goto done; |
88 | |
89 | if (left > sizeof(tmpbuf) - 1) |
90 | return -EINVAL; |
91 | memcpy(tmpbuf, p, left); |
92 | tmpbuf[left] = '\0'; |
93 | |
94 | value = simple_strtol(tmpbuf, &s, 0); |
95 | if (s) { |
96 | left -= (s - tmpbuf); |
97 | if (left && !isspace(*s)) |
98 | return -EINVAL; |
99 | while (left && isspace(*s)) { |
100 | left--; |
101 | s++; |
102 | } |
103 | } else |
104 | left = 0; |
105 | *(unsigned int *) table->data = value; |
106 | /* Display the RPC tasks on writing to rpc_debug */ |
107 | if (strcmp(table->procname, "rpc_debug" ) == 0) |
108 | rpc_show_tasks(&init_net); |
109 | } else { |
110 | len = sprintf(buf: tmpbuf, fmt: "0x%04x" , *(unsigned int *) table->data); |
111 | if (len > left) |
112 | len = left; |
113 | memcpy(buffer, tmpbuf, len); |
114 | if ((left -= len) > 0) { |
115 | *((char *)buffer + len) = '\n'; |
116 | left--; |
117 | } |
118 | } |
119 | |
120 | done: |
121 | *lenp -= left; |
122 | *ppos += *lenp; |
123 | return 0; |
124 | } |
125 | |
126 | static struct ctl_table_header *; |
127 | |
128 | static struct ctl_table debug_table[] = { |
129 | { |
130 | .procname = "rpc_debug" , |
131 | .data = &rpc_debug, |
132 | .maxlen = sizeof(int), |
133 | .mode = 0644, |
134 | .proc_handler = proc_dodebug |
135 | }, |
136 | { |
137 | .procname = "nfs_debug" , |
138 | .data = &nfs_debug, |
139 | .maxlen = sizeof(int), |
140 | .mode = 0644, |
141 | .proc_handler = proc_dodebug |
142 | }, |
143 | { |
144 | .procname = "nfsd_debug" , |
145 | .data = &nfsd_debug, |
146 | .maxlen = sizeof(int), |
147 | .mode = 0644, |
148 | .proc_handler = proc_dodebug |
149 | }, |
150 | { |
151 | .procname = "nlm_debug" , |
152 | .data = &nlm_debug, |
153 | .maxlen = sizeof(int), |
154 | .mode = 0644, |
155 | .proc_handler = proc_dodebug |
156 | }, |
157 | { |
158 | .procname = "transports" , |
159 | .maxlen = 256, |
160 | .mode = 0444, |
161 | .proc_handler = proc_do_xprt, |
162 | }, |
163 | { } |
164 | }; |
165 | |
166 | void |
167 | rpc_register_sysctl(void) |
168 | { |
169 | if (!sunrpc_table_header) |
170 | sunrpc_table_header = register_sysctl("sunrpc" , debug_table); |
171 | } |
172 | |
173 | void |
174 | rpc_unregister_sysctl(void) |
175 | { |
176 | if (sunrpc_table_header) { |
177 | unregister_sysctl_table(table: sunrpc_table_header); |
178 | sunrpc_table_header = NULL; |
179 | } |
180 | } |
181 | #endif |
182 | |