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