1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36 
37 #include <linux/module.h>
38 #include <linux/sysctl.h>
39 #include <linux/sched.h>
40 #include <linux/mm.h>
41 #include <linux/proc_fs.h>
42 #include <linux/slab.h>
43 #include <linux/stat.h>
44 #include <linux/ctype.h>
45 #include <linux/bitops.h>
46 #include <linux/uaccess.h>
47 #include <linux/utsname.h>
48 
49 #define DEBUG_SUBSYSTEM S_CLASS
50 
51 #include "../../include/obd_support.h"
52 #include "../../include/lprocfs_status.h"
53 
54 #ifdef CONFIG_SYSCTL
55 static struct ctl_table_header *obd_table_header;
56 #endif
57 
58 
59 #define OBD_SYSCTL 300
60 
61 enum {
62 	OBD_TIMEOUT = 3,	/* RPC timeout before recovery/intr */
63 	OBD_DUMP_ON_TIMEOUT,    /* dump kernel debug log upon eviction */
64 	OBD_MEMUSED,	    /* bytes currently OBD_ALLOCated */
65 	OBD_PAGESUSED,	  /* pages currently OBD_PAGE_ALLOCated */
66 	OBD_MAXMEMUSED,	 /* maximum bytes OBD_ALLOCated concurrently */
67 	OBD_MAXPAGESUSED,       /* maximum pages OBD_PAGE_ALLOCated concurrently */
68 	OBD_SYNCFILTER,	 /* XXX temporary, as we play with sync osts.. */
69 	OBD_LDLM_TIMEOUT,       /* LDLM timeout for ASTs before client eviction */
70 	OBD_DUMP_ON_EVICTION,   /* dump kernel debug log upon eviction */
71 	OBD_DEBUG_PEER_ON_TIMEOUT, /* dump peer debug when RPC times out */
72 	OBD_ALLOC_FAIL_RATE,    /* memory allocation random failure rate */
73 	OBD_MAX_DIRTY_PAGES,    /* maximum dirty pages */
74 	OBD_AT_MIN,	     /* Adaptive timeouts params */
75 	OBD_AT_MAX,
76 	OBD_AT_EXTRA,
77 	OBD_AT_EARLY_MARGIN,
78 	OBD_AT_HISTORY,
79 };
80 
81 
82 #ifdef CONFIG_SYSCTL
proc_set_timeout(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)83 static int proc_set_timeout(struct ctl_table *table, int write,
84 			void __user *buffer, size_t *lenp, loff_t *ppos)
85 {
86 	int rc;
87 
88 	rc = proc_dointvec(table, write, buffer, lenp, ppos);
89 	if (ldlm_timeout >= obd_timeout)
90 		ldlm_timeout = max(obd_timeout / 3, 1U);
91 	return rc;
92 }
93 
proc_memory_alloc(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)94 static int proc_memory_alloc(struct ctl_table *table, int write,
95 			void __user *buffer, size_t *lenp, loff_t *ppos)
96 {
97 	char buf[22];
98 	int len;
99 
100 	if (!*lenp || (*ppos && !write)) {
101 		*lenp = 0;
102 		return 0;
103 	}
104 	if (write)
105 		return -EINVAL;
106 
107 	len = snprintf(buf, sizeof(buf), "%llu\n", obd_memory_sum());
108 	if (len > *lenp)
109 		len = *lenp;
110 	buf[len] = '\0';
111 	if (copy_to_user(buffer, buf, len))
112 		return -EFAULT;
113 	*lenp = len;
114 	*ppos += *lenp;
115 	return 0;
116 }
117 
proc_pages_alloc(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)118 static int proc_pages_alloc(struct ctl_table *table, int write,
119 			void __user *buffer, size_t *lenp, loff_t *ppos)
120 {
121 	char buf[22];
122 	int len;
123 
124 	if (!*lenp || (*ppos && !write)) {
125 		*lenp = 0;
126 		return 0;
127 	}
128 	if (write)
129 		return -EINVAL;
130 
131 	len = snprintf(buf, sizeof(buf), "%llu\n", obd_pages_sum());
132 	if (len > *lenp)
133 		len = *lenp;
134 	buf[len] = '\0';
135 	if (copy_to_user(buffer, buf, len))
136 		return -EFAULT;
137 	*lenp = len;
138 	*ppos += *lenp;
139 	return 0;
140 }
141 
proc_mem_max(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)142 static int proc_mem_max(struct ctl_table *table, int write, void __user *buffer,
143 		 size_t *lenp, loff_t *ppos)
144 {
145 	char buf[22];
146 	int len;
147 
148 	if (!*lenp || (*ppos && !write)) {
149 		*lenp = 0;
150 		return 0;
151 	}
152 	if (write)
153 		return -EINVAL;
154 
155 	len = snprintf(buf, sizeof(buf), "%llu\n", obd_memory_max());
156 	if (len > *lenp)
157 		len = *lenp;
158 	buf[len] = '\0';
159 	if (copy_to_user(buffer, buf, len))
160 		return -EFAULT;
161 	*lenp = len;
162 	*ppos += *lenp;
163 	return 0;
164 }
165 
proc_pages_max(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)166 static int proc_pages_max(struct ctl_table *table, int write,
167 			void __user *buffer, size_t *lenp, loff_t *ppos)
168 {
169 	char buf[22];
170 	int len;
171 
172 	if (!*lenp || (*ppos && !write)) {
173 		*lenp = 0;
174 		return 0;
175 	}
176 	if (write)
177 		return -EINVAL;
178 
179 	len = snprintf(buf, sizeof(buf), "%llu\n", obd_pages_max());
180 	if (len > *lenp)
181 		len = *lenp;
182 	buf[len] = '\0';
183 	if (copy_to_user(buffer, buf, len))
184 		return -EFAULT;
185 	*lenp = len;
186 	*ppos += *lenp;
187 	return 0;
188 }
189 
proc_max_dirty_pages_in_mb(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)190 static int proc_max_dirty_pages_in_mb(struct ctl_table *table, int write,
191 			       void __user *buffer, size_t *lenp, loff_t *ppos)
192 {
193 	int rc = 0;
194 
195 	if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) {
196 		*lenp = 0;
197 		return 0;
198 	}
199 	if (write) {
200 		rc = lprocfs_write_frac_helper(buffer, *lenp,
201 					       (unsigned int *)table->data,
202 					       1 << (20 - PAGE_CACHE_SHIFT));
203 		/* Don't allow them to let dirty pages exceed 90% of system
204 		 * memory and set a hard minimum of 4MB. */
205 		if (obd_max_dirty_pages > ((totalram_pages / 10) * 9)) {
206 			CERROR("Refusing to set max dirty pages to %u, which is more than 90%% of available RAM; setting to %lu\n",
207 			       obd_max_dirty_pages,
208 			       ((totalram_pages / 10) * 9));
209 			obd_max_dirty_pages = (totalram_pages / 10) * 9;
210 		} else if (obd_max_dirty_pages < 4 << (20 - PAGE_CACHE_SHIFT)) {
211 			obd_max_dirty_pages = 4 << (20 - PAGE_CACHE_SHIFT);
212 		}
213 	} else {
214 		char buf[21];
215 		int len;
216 
217 		len = lprocfs_read_frac_helper(buf, sizeof(buf),
218 					       *(unsigned int *)table->data,
219 					       1 << (20 - PAGE_CACHE_SHIFT));
220 		if (len > *lenp)
221 			len = *lenp;
222 		buf[len] = '\0';
223 		if (copy_to_user(buffer, buf, len))
224 			return -EFAULT;
225 		*lenp = len;
226 	}
227 	*ppos += *lenp;
228 	return rc;
229 }
230 
proc_alloc_fail_rate(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)231 static int proc_alloc_fail_rate(struct ctl_table *table, int write,
232 			 void __user *buffer, size_t *lenp, loff_t *ppos)
233 {
234 	int rc	  = 0;
235 
236 	if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) {
237 		*lenp = 0;
238 		return 0;
239 	}
240 	if (write) {
241 		rc = lprocfs_write_frac_helper(buffer, *lenp,
242 					       (unsigned int *)table->data,
243 					       OBD_ALLOC_FAIL_MULT);
244 	} else {
245 		char buf[21];
246 		int  len;
247 
248 		len = lprocfs_read_frac_helper(buf, 21,
249 					       *(unsigned int *)table->data,
250 					       OBD_ALLOC_FAIL_MULT);
251 		if (len > *lenp)
252 			len = *lenp;
253 		buf[len] = '\0';
254 		if (copy_to_user(buffer, buf, len))
255 			return -EFAULT;
256 		*lenp = len;
257 	}
258 	*ppos += *lenp;
259 	return rc;
260 }
261 
262 static struct ctl_table obd_table[] = {
263 	{
264 		.procname = "timeout",
265 		.data     = &obd_timeout,
266 		.maxlen   = sizeof(int),
267 		.mode     = 0644,
268 		.proc_handler = &proc_set_timeout
269 	},
270 	{
271 		.procname = "debug_peer_on_timeout",
272 		.data     = &obd_debug_peer_on_timeout,
273 		.maxlen   = sizeof(int),
274 		.mode     = 0644,
275 		.proc_handler = &proc_dointvec
276 	},
277 	{
278 		.procname = "dump_on_timeout",
279 		.data     = &obd_dump_on_timeout,
280 		.maxlen   = sizeof(int),
281 		.mode     = 0644,
282 		.proc_handler = &proc_dointvec
283 	},
284 	{
285 		.procname = "dump_on_eviction",
286 		.data     = &obd_dump_on_eviction,
287 		.maxlen   = sizeof(int),
288 		.mode     = 0644,
289 		.proc_handler = &proc_dointvec
290 	},
291 	{
292 		.procname = "memused",
293 		.data     = NULL,
294 		.maxlen   = 0,
295 		.mode     = 0444,
296 		.proc_handler = &proc_memory_alloc
297 	},
298 	{
299 		.procname = "pagesused",
300 		.data     = NULL,
301 		.maxlen   = 0,
302 		.mode     = 0444,
303 		.proc_handler = &proc_pages_alloc
304 	},
305 	{
306 		.procname = "memused_max",
307 		.data     = NULL,
308 		.maxlen   = 0,
309 		.mode     = 0444,
310 		.proc_handler = &proc_mem_max
311 	},
312 	{
313 		.procname = "pagesused_max",
314 		.data     = NULL,
315 		.maxlen   = 0,
316 		.mode     = 0444,
317 		.proc_handler = &proc_pages_max
318 	},
319 	{
320 		.procname = "ldlm_timeout",
321 		.data     = &ldlm_timeout,
322 		.maxlen   = sizeof(int),
323 		.mode     = 0644,
324 		.proc_handler = &proc_set_timeout
325 	},
326 	{
327 		.procname = "alloc_fail_rate",
328 		.data     = &obd_alloc_fail_rate,
329 		.maxlen   = sizeof(int),
330 		.mode     = 0644,
331 		.proc_handler = &proc_alloc_fail_rate
332 	},
333 	{
334 		.procname = "max_dirty_mb",
335 		.data     = &obd_max_dirty_pages,
336 		.maxlen   = sizeof(int),
337 		.mode     = 0644,
338 		.proc_handler = &proc_max_dirty_pages_in_mb
339 	},
340 	{
341 		.procname = "at_min",
342 		.data     = &at_min,
343 		.maxlen   = sizeof(int),
344 		.mode     = 0644,
345 		.proc_handler = &proc_dointvec,
346 	},
347 	{
348 		.procname = "at_max",
349 		.data     = &at_max,
350 		.maxlen   = sizeof(int),
351 		.mode     = 0644,
352 		.proc_handler = &proc_dointvec,
353 	},
354 	{
355 		.procname = "at_extra",
356 		.data     = &at_extra,
357 		.maxlen   = sizeof(int),
358 		.mode     = 0644,
359 		.proc_handler = &proc_dointvec,
360 	},
361 	{
362 		.procname = "at_early_margin",
363 		.data     = &at_early_margin,
364 		.maxlen   = sizeof(int),
365 		.mode     = 0644,
366 		.proc_handler = &proc_dointvec,
367 	},
368 	{
369 		.procname = "at_history",
370 		.data     = &at_history,
371 		.maxlen   = sizeof(int),
372 		.mode     = 0644,
373 		.proc_handler = &proc_dointvec,
374 	},
375 	{}
376 };
377 
378 static struct ctl_table parent_table[] = {
379 	{
380 		.procname = "lustre",
381 		.data     = NULL,
382 		.maxlen   = 0,
383 		.mode     = 0555,
384 		.child    = obd_table
385 	},
386 	{}
387 };
388 #endif
389 
obd_sysctl_init(void)390 void obd_sysctl_init(void)
391 {
392 #ifdef CONFIG_SYSCTL
393 	if (!obd_table_header)
394 		obd_table_header = register_sysctl_table(parent_table);
395 #endif
396 }
397 
obd_sysctl_clean(void)398 void obd_sysctl_clean(void)
399 {
400 #ifdef CONFIG_SYSCTL
401 	if (obd_table_header)
402 		unregister_sysctl_table(obd_table_header);
403 	obd_table_header = NULL;
404 #endif
405 }
406