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(tmpbuf, sizeof(tmpbuf)); 54 len = memory_read_from_buffer(buffer, *lenp, ppos, tmpbuf, 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(tmpbuf, "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 *sunrpc_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(sunrpc_table_header); 178 sunrpc_table_header = NULL; 179 } 180 } 181 #endif 182