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 struct ctl_table_header *sunrpc_table_header; 44 static struct ctl_table sunrpc_table[]; 45 46 void 47 rpc_register_sysctl(void) 48 { 49 if (!sunrpc_table_header) 50 sunrpc_table_header = register_sysctl_table(sunrpc_table); 51 } 52 53 void 54 rpc_unregister_sysctl(void) 55 { 56 if (sunrpc_table_header) { 57 unregister_sysctl_table(sunrpc_table_header); 58 sunrpc_table_header = NULL; 59 } 60 } 61 62 static int proc_do_xprt(struct ctl_table *table, int write, 63 void __user *buffer, size_t *lenp, loff_t *ppos) 64 { 65 char tmpbuf[256]; 66 size_t len; 67 68 if ((*ppos && !write) || !*lenp) { 69 *lenp = 0; 70 return 0; 71 } 72 len = svc_print_xprts(tmpbuf, sizeof(tmpbuf)); 73 return simple_read_from_buffer(buffer, *lenp, ppos, tmpbuf, len); 74 } 75 76 static int 77 proc_dodebug(struct ctl_table *table, int write, 78 void __user *buffer, size_t *lenp, loff_t *ppos) 79 { 80 char tmpbuf[20], c, *s = NULL; 81 char __user *p; 82 unsigned int value; 83 size_t left, len; 84 85 if ((*ppos && !write) || !*lenp) { 86 *lenp = 0; 87 return 0; 88 } 89 90 left = *lenp; 91 92 if (write) { 93 if (!access_ok(buffer, left)) 94 return -EFAULT; 95 p = buffer; 96 while (left && __get_user(c, p) >= 0 && isspace(c)) 97 left--, p++; 98 if (!left) 99 goto done; 100 101 if (left > sizeof(tmpbuf) - 1) 102 return -EINVAL; 103 if (copy_from_user(tmpbuf, p, left)) 104 return -EFAULT; 105 tmpbuf[left] = '\0'; 106 107 value = simple_strtol(tmpbuf, &s, 0); 108 if (s) { 109 left -= (s - tmpbuf); 110 if (left && !isspace(*s)) 111 return -EINVAL; 112 while (left && isspace(*s)) 113 left--, s++; 114 } else 115 left = 0; 116 *(unsigned int *) table->data = value; 117 /* Display the RPC tasks on writing to rpc_debug */ 118 if (strcmp(table->procname, "rpc_debug") == 0) 119 rpc_show_tasks(&init_net); 120 } else { 121 len = sprintf(tmpbuf, "0x%04x", *(unsigned int *) table->data); 122 if (len > left) 123 len = left; 124 if (copy_to_user(buffer, tmpbuf, len)) 125 return -EFAULT; 126 if ((left -= len) > 0) { 127 if (put_user('\n', (char __user *)buffer + len)) 128 return -EFAULT; 129 left--; 130 } 131 } 132 133 done: 134 *lenp -= left; 135 *ppos += *lenp; 136 return 0; 137 } 138 139 140 static struct ctl_table debug_table[] = { 141 { 142 .procname = "rpc_debug", 143 .data = &rpc_debug, 144 .maxlen = sizeof(int), 145 .mode = 0644, 146 .proc_handler = proc_dodebug 147 }, 148 { 149 .procname = "nfs_debug", 150 .data = &nfs_debug, 151 .maxlen = sizeof(int), 152 .mode = 0644, 153 .proc_handler = proc_dodebug 154 }, 155 { 156 .procname = "nfsd_debug", 157 .data = &nfsd_debug, 158 .maxlen = sizeof(int), 159 .mode = 0644, 160 .proc_handler = proc_dodebug 161 }, 162 { 163 .procname = "nlm_debug", 164 .data = &nlm_debug, 165 .maxlen = sizeof(int), 166 .mode = 0644, 167 .proc_handler = proc_dodebug 168 }, 169 { 170 .procname = "transports", 171 .maxlen = 256, 172 .mode = 0444, 173 .proc_handler = proc_do_xprt, 174 }, 175 { } 176 }; 177 178 static struct ctl_table sunrpc_table[] = { 179 { 180 .procname = "sunrpc", 181 .mode = 0555, 182 .child = debug_table 183 }, 184 { } 185 }; 186 187 #endif 188