OSDN Git Service

tcp: Clear probes_out more aggressively in tcp_ack().
[linux-kernel-docs/linux-2.4.36.git] / kernel / sysctl.c
1 /*
2  * sysctl.c: General linux system control interface
3  *
4  * Begun 24 March 1995, Stephen Tweedie
5  * Added /proc support, Dec 1995
6  * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
7  * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
8  * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
9  * Dynamic registration fixes, Stephen Tweedie.
10  * Added kswapd-interval, ctrl-alt-del, printk stuff, 1/8/97, Chris Horn.
11  * Made sysctl support optional via CONFIG_SYSCTL, 1/10/97, Chris
12  *  Horn.
13  * Added proc_doulongvec_ms_jiffies_minmax, 09/08/99, Carlos H. Bauer.
14  * Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer.
15  * Changed linked lists to use list.h instead of lists.h, 02/24/00, Bill
16  *  Wendling.
17  * The list_for_each() macro wasn't appropriate for the sysctl loop.
18  *  Removed it and replaced it with older style, 03/23/00, Bill Wendling
19  */
20
21 #include <linux/config.h>
22 #include <linux/slab.h>
23 #include <linux/sysctl.h>
24 #include <linux/swapctl.h>
25 #include <linux/proc_fs.h>
26 #include <linux/ctype.h>
27 #include <linux/utsname.h>
28 #include <linux/capability.h>
29 #include <linux/smp_lock.h>
30 #include <linux/init.h>
31 #include <linux/sysrq.h>
32 #include <linux/highuid.h>
33 #include <linux/swap.h>
34
35 #include <asm/uaccess.h>
36
37 #ifdef CONFIG_ROOT_NFS
38 #include <linux/nfs_fs.h>
39 #endif
40
41 #if defined(CONFIG_SYSCTL)
42
43 /* External variables not in a header file. */
44 extern int panic_timeout;
45 extern int C_A_D;
46 extern int bdf_prm[], bdflush_min[], bdflush_max[];
47 extern int sysctl_overcommit_memory;
48 extern int max_threads;
49 extern atomic_t nr_queued_signals;
50 extern int max_queued_signals;
51 extern int sysrq_enabled;
52 extern int core_uses_pid;
53 extern int core_setuid_ok;
54 extern char core_pattern[];
55 extern int cad_pid;
56 extern int laptop_mode;
57 extern int block_dump;
58
59 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
60 static int maxolduid = 65535;
61 static int minolduid;
62
63 #ifdef CONFIG_KMOD
64 extern char modprobe_path[];
65 #endif
66 #ifdef CONFIG_HOTPLUG
67 extern char hotplug_path[];
68 #endif
69 #ifdef CONFIG_CHR_DEV_SG
70 extern int sg_big_buff;
71 #endif
72 #ifdef CONFIG_SYSVIPC
73 extern size_t shm_ctlmax;
74 extern size_t shm_ctlall;
75 extern int shm_ctlmni;
76 extern int msg_ctlmax;
77 extern int msg_ctlmnb;
78 extern int msg_ctlmni;
79 extern int sem_ctls[];
80 #endif
81
82 extern int exception_trace;
83
84 #ifdef __sparc__
85 extern char reboot_command [];
86 extern int stop_a_enabled;
87 extern int scons_pwroff;
88 #endif
89
90 #ifdef CONFIG_ARCH_S390
91 #ifdef CONFIG_MATHEMU
92 extern int sysctl_ieee_emulation_warnings;
93 #endif
94 extern int sysctl_userprocess_debug;
95 #endif
96
97 #ifdef CONFIG_PPC32
98 extern unsigned long zero_paged_on, powersave_nap;
99 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
100                 void *buffer, size_t *lenp);
101 int proc_dol3crvec(ctl_table *table, int write, struct file *filp,
102                 void *buffer, size_t *lenp);
103 #endif
104
105 #ifdef CONFIG_BSD_PROCESS_ACCT
106 extern int acct_parm[];
107 #endif
108
109 extern int pgt_cache_water[];
110
111 static int parse_table(int *, int, void *, size_t *, void *, size_t,
112                        ctl_table *, void **);
113 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
114                   void *buffer, size_t *lenp);
115
116 static ctl_table root_table[];
117 static struct ctl_table_header root_table_header =
118         { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
119
120 static ctl_table kern_table[];
121 static ctl_table vm_table[];
122 #ifdef CONFIG_NET
123 extern ctl_table net_table[];
124 #endif
125 static ctl_table proc_table[];
126 static ctl_table fs_table[];
127 static ctl_table debug_table[];
128 static ctl_table dev_table[];
129 extern ctl_table random_table[];
130
131 /* /proc declarations: */
132
133 #ifdef CONFIG_PROC_FS
134
135 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
136 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
137 static int proc_sys_permission(struct inode *, int);
138
139 struct file_operations proc_sys_file_operations = {
140         read:           proc_readsys,
141         write:          proc_writesys,
142 };
143
144 static struct inode_operations proc_sys_inode_operations = {
145         permission:     proc_sys_permission,
146 };
147
148 extern struct proc_dir_entry *proc_sys_root;
149
150 static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *);
151 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
152 #endif
153
154 /* The default sysctl tables: */
155
156 static ctl_table root_table[] = {
157         {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
158         {CTL_VM, "vm", NULL, 0, 0555, vm_table},
159 #ifdef CONFIG_NET
160         {CTL_NET, "net", NULL, 0, 0555, net_table},
161 #endif
162         {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
163         {CTL_FS, "fs", NULL, 0, 0555, fs_table},
164         {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
165         {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
166         {0}
167 };
168
169 static ctl_table kern_table[] = {
170         {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
171          0444, NULL, &proc_doutsstring, &sysctl_string},
172         {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
173          0444, NULL, &proc_doutsstring, &sysctl_string},
174         {KERN_VERSION, "version", system_utsname.version, 64,
175          0444, NULL, &proc_doutsstring, &sysctl_string},
176         {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
177          0644, NULL, &proc_doutsstring, &sysctl_string},
178         {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
179          0644, NULL, &proc_doutsstring, &sysctl_string},
180         {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
181          0644, NULL, &proc_dointvec},
182         {KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
183          0644, NULL, &proc_dointvec},
184         {KERN_CORE_SETUID, "core_setuid_ok", &core_setuid_ok, sizeof(int),
185         0644, NULL, &proc_dointvec},
186         {KERN_CORE_PATTERN, "core_pattern", core_pattern, 64,
187          0644, NULL, &proc_dostring, &sysctl_string},
188         {KERN_TAINTED, "tainted", &tainted, sizeof(int),
189          0644, NULL, &proc_dointvec},
190         {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
191          0600, NULL, &proc_dointvec_bset},
192 #ifdef CONFIG_BLK_DEV_INITRD
193         {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
194          0644, NULL, &proc_dointvec},
195 #endif
196 #ifdef __sparc__
197         {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
198          256, 0644, NULL, &proc_dostring, &sysctl_string },
199         {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
200          0644, NULL, &proc_dointvec},
201         {KERN_SPARC_SCONS_PWROFF, "scons-poweroff", &scons_pwroff, sizeof (int),
202          0644, NULL, &proc_dointvec},
203 #endif
204 #ifdef CONFIG_PPC32
205         {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
206          0644, NULL, &proc_dointvec},
207         {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
208          0644, NULL, &proc_dointvec},
209         {KERN_PPC_L2CR, "l2cr", NULL, 0,
210          0644, NULL, &proc_dol2crvec},
211         {KERN_PPC_L3CR, "l3cr", NULL, 0,
212          0644, NULL, &proc_dol3crvec},
213 #endif
214         {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
215          0644, NULL, &proc_dointvec},
216         {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
217          0644, NULL, &proc_dointvec},
218 #ifdef CONFIG_KMOD
219         {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
220          0644, NULL, &proc_dostring, &sysctl_string },
221 #endif
222 #ifdef CONFIG_HOTPLUG
223         {KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
224          0644, NULL, &proc_dostring, &sysctl_string },
225 #endif
226 #ifdef CONFIG_CHR_DEV_SG
227         {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
228          0444, NULL, &proc_dointvec},
229 #endif
230 #ifdef CONFIG_BSD_PROCESS_ACCT
231         {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
232         0644, NULL, &proc_dointvec},
233 #endif
234         {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
235          0444, NULL, &proc_dointvec},
236         {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
237          0644, NULL, &proc_dointvec},
238 #ifdef CONFIG_SYSVIPC
239         {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
240          0644, NULL, &proc_doulongvec_minmax},
241         {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (size_t),
242          0644, NULL, &proc_doulongvec_minmax},
243         {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
244          0644, NULL, &proc_dointvec},
245         {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
246          0644, NULL, &proc_dointvec},
247         {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
248          0644, NULL, &proc_dointvec},
249         {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int),
250          0644, NULL, &proc_dointvec},
251         {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int),
252          0644, NULL, &proc_dointvec},
253 #endif
254 #ifdef CONFIG_MAGIC_SYSRQ
255         {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
256          0644, NULL, &proc_dointvec},
257 #endif   
258         {KERN_CADPID, "cad_pid", &cad_pid, sizeof (int),
259          0600, NULL, &proc_dointvec},
260         {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
261          0644, NULL, &proc_dointvec},
262         {KERN_RANDOM, "random", NULL, 0, 0555, random_table},
263         {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
264          &proc_dointvec_minmax, &sysctl_intvec, NULL,
265          &minolduid, &maxolduid},
266         {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
267          &proc_dointvec_minmax, &sysctl_intvec, NULL,
268          &minolduid, &maxolduid},
269 #ifdef CONFIG_ARCH_S390
270 #ifdef CONFIG_MATHEMU
271         {KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings",
272          &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec},
273 #endif
274         {KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug",
275          &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec},
276 #endif
277 #ifdef __x86_64__
278         {KERN_EXCEPTION_TRACE,"exception-trace",
279          &exception_trace,sizeof(int),0644,NULL,&proc_dointvec},
280 #endif  
281         {0}
282 };
283
284 static ctl_table vm_table[] = {
285         {VM_GFP_DEBUG, "vm_gfp_debug", 
286          &vm_gfp_debug, sizeof(int), 0644, NULL, &proc_dointvec},
287         {VM_VFS_SCAN_RATIO, "vm_vfs_scan_ratio", 
288          &vm_vfs_scan_ratio, sizeof(int), 0644, NULL, &proc_dointvec},
289         {VM_CACHE_SCAN_RATIO, "vm_cache_scan_ratio", 
290          &vm_cache_scan_ratio, sizeof(int), 0644, NULL, &proc_dointvec},
291         {VM_MAPPED_RATIO, "vm_mapped_ratio", 
292          &vm_mapped_ratio, sizeof(int), 0644, NULL, &proc_dointvec},
293         {VM_ANON_LRU, "vm_anon_lru", 
294          &vm_anon_lru, sizeof(int), 0644, NULL, &proc_dointvec},
295         {VM_LRU_BALANCE_RATIO, "vm_lru_balance_ratio", 
296          &vm_lru_balance_ratio, sizeof(int), 0644, NULL, &proc_dointvec},
297         {VM_PASSES, "vm_passes", 
298          &vm_passes, sizeof(int), 0644, NULL, &proc_dointvec},
299         {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL,
300          &proc_dointvec_minmax, &sysctl_intvec, NULL,
301          &bdflush_min, &bdflush_max},
302         {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
303          sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
304         {VM_PAGERDAEMON, "kswapd",
305          &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
306         {VM_PGT_CACHE, "pagetable_cache", 
307          &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
308         {VM_PAGE_CLUSTER, "page-cluster", 
309          &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
310         {VM_MIN_READAHEAD, "min-readahead",
311         &vm_min_readahead,sizeof(int), 0644, NULL, &proc_dointvec},
312         {VM_MAX_READAHEAD, "max-readahead",
313         &vm_max_readahead,sizeof(int), 0644, NULL, &proc_dointvec},
314         {VM_MAX_MAP_COUNT, "max_map_count",
315          &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec},
316         {VM_LAPTOP_MODE, "laptop_mode",
317          &laptop_mode, sizeof(int), 0644, NULL, &proc_dointvec},
318         {VM_BLOCK_DUMP, "block_dump",
319          &block_dump, sizeof(int), 0644, NULL, &proc_dointvec},
320         {VM_MMAP_MIN_ADDR, "mmap_min_addr",
321          &mmap_min_addr, sizeof(unsigned long), 0644, NULL, &proc_doulongvec_minmax},
322         {0}
323 };
324
325 static ctl_table proc_table[] = {
326         {0}
327 };
328
329 static ctl_table fs_table[] = {
330         {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
331          0444, NULL, &proc_dointvec},
332         {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
333          0444, NULL, &proc_dointvec},
334         {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
335          0444, NULL, &proc_dointvec},
336         {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
337          0644, NULL, &proc_dointvec},
338         {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
339          0444, NULL, &proc_dointvec},
340         {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
341          &proc_dointvec_minmax, &sysctl_intvec, NULL,
342          &minolduid, &maxolduid},
343         {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
344          &proc_dointvec_minmax, &sysctl_intvec, NULL,
345          &minolduid, &maxolduid},
346         {FS_LEASES, "leases-enable", &leases_enable, sizeof(int),
347          0644, NULL, &proc_dointvec},
348         {FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable,
349          sizeof(int), 0644, NULL, &proc_dointvec},
350         {FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int),
351          0644, NULL, &proc_dointvec},
352         {0}
353 };
354
355 static ctl_table debug_table[] = {
356         {0}
357 };
358
359 static ctl_table dev_table[] = {
360         {0}
361 };  
362
363 extern void init_irq_proc (void);
364
365 static spinlock_t sysctl_lock = SPIN_LOCK_UNLOCKED;
366
367 /* called under sysctl_lock */
368 static int use_table(struct ctl_table_header *p)
369 {
370         if (unlikely(p->unregistering != NULL))
371                 return 0;
372         p->used++;
373         return 1;
374 }
375
376 /* called under sysctl_lock */
377 static void unuse_table(struct ctl_table_header *p)
378 {
379         if (!--p->used)
380                 if (unlikely(p->unregistering != NULL))
381                         complete(p->unregistering);
382 }
383
384 /* called under sysctl_lock, will reacquire if has to wait */
385 static void start_unregistering(struct ctl_table_header *p)
386 {
387         /*
388          * if p->used is 0, nobody will ever touch that entry again;
389          * we'll eliminate all paths to it before dropping sysctl_lock
390          */
391         if (unlikely(p->used)) {
392                 struct completion wait;
393                 init_completion(&wait);
394                 p->unregistering = &wait;
395                 spin_unlock(&sysctl_lock);
396                 wait_for_completion(&wait);
397                 spin_lock(&sysctl_lock);
398         }
399         /*
400          * do not remove from the list until nobody holds it; walking the
401          * list in do_sysctl() relies on that.
402          */
403         list_del_init(&p->ctl_entry);
404 }
405
406 void __init sysctl_init(void)
407 {
408 #ifdef CONFIG_PROC_FS
409         register_proc_table(root_table, proc_sys_root, &root_table_header);
410         init_irq_proc();
411 #endif
412 }
413
414 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
415                void *newval, size_t newlen)
416 {
417         struct list_head *tmp;
418         int error = -ENOTDIR;
419
420         if (nlen <= 0 || nlen >= CTL_MAXNAME)
421                 return -ENOTDIR;
422         if (oldval) {
423                 int old_len;
424                 if (!oldlenp || get_user(old_len, oldlenp))
425                         return -EFAULT;
426                 /* XXX: insufficient for SMP, but should be redundant anyway */
427                 if ((ssize_t)old_len < 0)
428                         return -EINVAL;
429         }
430         spin_lock(&sysctl_lock);
431         tmp = &root_table_header.ctl_entry;
432         do {
433                 struct ctl_table_header *head =
434                         list_entry(tmp, struct ctl_table_header, ctl_entry);
435                 void *context = NULL;
436
437                 if (!use_table(head))
438                         continue;
439
440                 spin_unlock(&sysctl_lock);
441
442                 error = parse_table(name, nlen, oldval, oldlenp, 
443                                         newval, newlen, head->ctl_table,
444                                         &context);
445                 if (context)
446                         kfree(context);
447
448                 spin_lock(&sysctl_lock);
449                 unuse_table(head);
450                 if (error != -ENOTDIR)
451                         break;
452         } while ((tmp = tmp->next) != &root_table_header.ctl_entry);
453         spin_unlock(&sysctl_lock);
454         return error;
455 }
456
457 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
458 {
459         struct __sysctl_args tmp;
460         int error;
461
462         if (copy_from_user(&tmp, args, sizeof(tmp)))
463                 return -EFAULT;
464                 
465         lock_kernel();
466         error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
467                           tmp.newval, tmp.newlen);
468         unlock_kernel();
469         return error;
470 }
471
472 /*
473  * ctl_perm does NOT grant the superuser all rights automatically, because
474  * some sysctl variables are readonly even to root.
475  */
476
477 static int test_perm(int mode, int op)
478 {
479         if (!current->euid)
480                 mode >>= 6;
481         else if (in_egroup_p(0))
482                 mode >>= 3;
483         if ((mode & op & 0007) == op)
484                 return 0;
485         return -EACCES;
486 }
487
488 static inline int ctl_perm(ctl_table *table, int op)
489 {
490         return test_perm(table->mode, op);
491 }
492
493 static int parse_table(int *name, int nlen,
494                        void *oldval, size_t *oldlenp,
495                        void *newval, size_t newlen,
496                        ctl_table *table, void **context)
497 {
498         int n;
499 repeat:
500         if (!nlen)
501                 return -ENOTDIR;
502         if (get_user(n, name))
503                 return -EFAULT;
504         for ( ; table->ctl_name; table++) {
505                 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
506                         int error;
507                         if (table->child) {
508                                 if (ctl_perm(table, 001))
509                                         return -EPERM;
510                                 if (table->strategy) {
511                                         error = table->strategy(
512                                                 table, name, nlen,
513                                                 oldval, oldlenp,
514                                                 newval, newlen, context);
515                                         if (error)
516                                                 return error;
517                                 }
518                                 name++;
519                                 nlen--;
520                                 table = table->child;
521                                 goto repeat;
522                         }
523                         error = do_sysctl_strategy(table, name, nlen,
524                                                    oldval, oldlenp,
525                                                    newval, newlen, context);
526                         return error;
527                 }
528         }
529         return -ENOTDIR;
530 }
531
532 /* Perform the actual read/write of a sysctl table entry. */
533 int do_sysctl_strategy (ctl_table *table, 
534                         int *name, int nlen,
535                         void *oldval, size_t *oldlenp,
536                         void *newval, size_t newlen, void **context)
537 {
538         int op = 0, rc;
539         size_t len;
540
541         if (oldval)
542                 op |= 004;
543         if (newval) 
544                 op |= 002;
545         if (ctl_perm(table, op))
546                 return -EPERM;
547
548         if (table->strategy) {
549                 rc = table->strategy(table, name, nlen, oldval, oldlenp,
550                                      newval, newlen, context);
551                 if (rc < 0)
552                         return rc;
553                 if (rc > 0)
554                         return 0;
555         }
556
557         /* If there is no strategy routine, or if the strategy returns
558          * zero, proceed with automatic r/w */
559         if (table->data && table->maxlen) {
560                 if (oldval && oldlenp) {
561                         if (get_user(len, oldlenp))
562                                 return -EFAULT;
563                         if (len) {
564                                 if (len > table->maxlen)
565                                         len = table->maxlen;
566                                 if(copy_to_user(oldval, table->data, len))
567                                         return -EFAULT;
568                                 if(put_user(len, oldlenp))
569                                         return -EFAULT;
570                         }
571                 }
572                 if (newval && newlen) {
573                         len = newlen;
574                         if (len > table->maxlen)
575                                 len = table->maxlen;
576                         if(copy_from_user(table->data, newval, len))
577                                 return -EFAULT;
578                 }
579         }
580         return 0;
581 }
582
583 /**
584  * register_sysctl_table - register a sysctl hierarchy
585  * @table: the top-level table structure
586  * @insert_at_head: whether the entry should be inserted in front or at the end
587  *
588  * Register a sysctl table hierarchy. @table should be a filled in ctl_table
589  * array. An entry with a ctl_name of 0 terminates the table. 
590  *
591  * The members of the &ctl_table structure are used as follows:
592  *
593  * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
594  *            must be unique within that level of sysctl
595  *
596  * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
597  *            enter a sysctl file
598  *
599  * data - a pointer to data for use by proc_handler
600  *
601  * maxlen - the maximum size in bytes of the data
602  *
603  * mode - the file permissions for the /proc/sys file, and for sysctl(2)
604  *
605  * child - a pointer to the child sysctl table if this entry is a directory, or
606  *         %NULL.
607  *
608  * proc_handler - the text handler routine (described below)
609  *
610  * strategy - the strategy routine (described below)
611  *
612  * de - for internal use by the sysctl routines
613  *
614  * extra1, extra2 - extra pointers usable by the proc handler routines
615  *
616  * Leaf nodes in the sysctl tree will be represented by a single file
617  * under /proc; non-leaf nodes will be represented by directories.
618  *
619  * sysctl(2) can automatically manage read and write requests through
620  * the sysctl table.  The data and maxlen fields of the ctl_table
621  * struct enable minimal validation of the values being written to be
622  * performed, and the mode field allows minimal authentication.
623  *
624  * More sophisticated management can be enabled by the provision of a
625  * strategy routine with the table entry.  This will be called before
626  * any automatic read or write of the data is performed.
627  *
628  * The strategy routine may return
629  *
630  * < 0 - Error occurred (error is passed to user process)
631  *
632  * 0   - OK - proceed with automatic read or write.
633  *
634  * > 0 - OK - read or write has been done by the strategy routine, so
635  *       return immediately.
636  *
637  * There must be a proc_handler routine for any terminal nodes
638  * mirrored under /proc/sys (non-terminals are handled by a built-in
639  * directory handler).  Several default handlers are available to
640  * cover common cases -
641  *
642  * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
643  * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
644  * proc_doulongvec_minmax()
645  *
646  * It is the handler's job to read the input buffer from user memory
647  * and process it. The handler should return 0 on success.
648  *
649  * This routine returns %NULL on a failure to register, and a pointer
650  * to the table header on success.
651  */
652 struct ctl_table_header *register_sysctl_table(ctl_table * table, 
653                                                int insert_at_head)
654 {
655         struct ctl_table_header *tmp;
656         tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
657         if (!tmp)
658                 return NULL;
659         tmp->ctl_table = table;
660         INIT_LIST_HEAD(&tmp->ctl_entry);
661         tmp->used = 0;
662         tmp->unregistering = NULL;
663         spin_lock(&sysctl_lock);
664         if (insert_at_head)
665                 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
666         else
667                 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
668         spin_unlock(&sysctl_lock);
669 #ifdef CONFIG_PROC_FS
670         register_proc_table(table, proc_sys_root, tmp);
671 #endif
672         return tmp;
673 }
674
675 /**
676  * unregister_sysctl_table - unregister a sysctl table hierarchy
677  * @header: the header returned from register_sysctl_table
678  *
679  * Unregisters the sysctl table and all children. proc entries may not
680  * actually be removed until they are no longer used by anyone.
681  */
682 void unregister_sysctl_table(struct ctl_table_header * header)
683 {
684         spin_lock(&sysctl_lock);
685         start_unregistering(header);
686 #ifdef CONFIG_PROC_FS
687         unregister_proc_table(header->ctl_table, proc_sys_root);
688 #endif
689         spin_unlock(&sysctl_lock);
690         kfree(header);
691 }
692
693 /*
694  * /proc/sys support
695  */
696
697 #ifdef CONFIG_PROC_FS
698
699 /* Scan the sysctl entries in table and add them all into /proc */
700 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set)
701 {
702         struct proc_dir_entry *de;
703         int len;
704         mode_t mode;
705         
706         for (; table->ctl_name; table++) {
707                 /* Can't do anything without a proc name. */
708                 if (!table->procname)
709                         continue;
710                 /* Maybe we can't do anything with it... */
711                 if (!table->proc_handler && !table->child) {
712                         printk(KERN_WARNING "SYSCTL: Can't register %s\n",
713                                 table->procname);
714                         continue;
715                 }
716
717                 len = strlen(table->procname);
718                 mode = table->mode;
719
720                 de = NULL;
721                 if (table->proc_handler)
722                         mode |= S_IFREG;
723                 else {
724                         mode |= S_IFDIR;
725                         for (de = root->subdir; de; de = de->next) {
726                                 if (proc_match(len, table->procname, de))
727                                         break;
728                         }
729                         /* If the subdir exists already, de is non-NULL */
730                 }
731
732                 if (!de) {
733                         de = create_proc_entry(table->procname, mode, root);
734                         if (!de)
735                                 continue;
736                         de->set = set;
737                         de->data = (void *) table;
738                         if (table->proc_handler) {
739                                 de->proc_fops = &proc_sys_file_operations;
740                                 de->proc_iops = &proc_sys_inode_operations;
741                         }
742                 }
743                 table->de = de;
744                 if (de->mode & S_IFDIR)
745                         register_proc_table(table->child, de, set);
746         }
747 }
748
749 /*
750  * Unregister a /proc sysctl table and any subdirectories.
751  */
752 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
753 {
754         struct proc_dir_entry *de;
755         for (; table->ctl_name; table++) {
756                 if (!(de = table->de))
757                         continue;
758                 if (de->mode & S_IFDIR) {
759                         if (!table->child) {
760                                 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
761                                 continue;
762                         }
763                         unregister_proc_table(table->child, de);
764
765                         /* Don't unregister directories which still have entries.. */
766                         if (de->subdir)
767                                 continue;
768                 }
769
770                 /*
771                  * In any case, mark the entry as goner; we'll keep it
772                  * around if it's busy, but we'll know to do nothing with
773                  * its fields.  We are under sysctl_lock here.
774                  */
775                 de->data = NULL;
776
777                 /* Don't unregister proc entries that are still being used.. */
778                 if (atomic_read(&de->count))
779                         continue;
780
781                 table->de = NULL;
782                 remove_proc_entry(table->procname, root);
783         }
784 }
785
786 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
787                           size_t count, loff_t *ppos)
788 {
789         int op;
790         struct proc_dir_entry *de =
791           (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
792         struct ctl_table *table;
793         size_t res;
794         ssize_t error = -ENOTDIR;
795
796         spin_lock(&sysctl_lock);
797         if (de && de->data && use_table(de->set)) {
798                 /*
799                  * at that point we know that sysctl was not unregistered
800                  * and won't be until we finish
801                  */
802                 spin_unlock(&sysctl_lock);
803                 table = (struct ctl_table *) de->data;
804                 if (!table || !table->proc_handler)
805                         goto out;
806                 error = -EPERM;
807                 op = (write ? 002 : 004);
808                 if (ctl_perm(table, op))
809                         goto out;
810                 
811                 /* careful: calling conventions are nasty here */
812                 res = count;
813
814                 /*
815                  * FIXME: we need to pass on ppos to the handler.
816                  */
817
818                 error = (*table->proc_handler)(table, write, file,
819                                                 buf, &res);
820                 if (!error)
821                         error = res;
822         out:
823                 spin_lock(&sysctl_lock);
824                 unuse_table(de->set);
825         }
826         spin_unlock(&sysctl_lock);
827         return error;
828 }
829
830 static ssize_t proc_readsys(struct file * file, char * buf,
831                             size_t count, loff_t *ppos)
832 {
833         return do_rw_proc(0, file, buf, count, ppos);
834 }
835
836 static ssize_t proc_writesys(struct file * file, const char * buf,
837                              size_t count, loff_t *ppos)
838 {
839         return do_rw_proc(1, file, (char *) buf, count, ppos);
840 }
841
842 static int proc_sys_permission(struct inode *inode, int op)
843 {
844         return test_perm(inode->i_mode, op);
845 }
846
847 /**
848  * proc_dostring - read a string sysctl
849  * @table: the sysctl table
850  * @write: %TRUE if this is a write to the sysctl file
851  * @filp: the file structure
852  * @buffer: the user buffer
853  * @lenp: the size of the user buffer
854  *
855  * Reads/writes a string from/to the user buffer. If the kernel
856  * buffer provided is not large enough to hold the string, the
857  * string is truncated. The copied string is %NULL-terminated.
858  * If the string is being read by the user process, it is copied
859  * and a newline '\n' is added. It is truncated if the buffer is
860  * not large enough.
861  *
862  * Returns 0 on success.
863  */
864 int proc_dostring(ctl_table *table, int write, struct file *filp,
865                   void *buffer, size_t *lenp)
866 {
867         size_t len;
868         char *p, c;
869         
870         if (!table->data || !table->maxlen || !*lenp ||
871             (filp->f_pos && !write)) {
872                 *lenp = 0;
873                 return 0;
874         }
875         
876         if (write) {
877                 len = 0;
878                 p = buffer;
879                 while (len < *lenp) {
880                         if (get_user(c, p++))
881                                 return -EFAULT;
882                         if (c == 0 || c == '\n')
883                                 break;
884                         len++;
885                 }
886                 if (len >= table->maxlen)
887                         len = table->maxlen-1;
888                 if(copy_from_user(table->data, buffer, len))
889                         return -EFAULT;
890                 ((char *) table->data)[len] = 0;
891                 filp->f_pos += *lenp;
892         } else {
893                 len = strlen(table->data);
894                 if (len > table->maxlen)
895                         len = table->maxlen;
896                 if (len > *lenp)
897                         len = *lenp;
898                 if (len)
899                         if(copy_to_user(buffer, table->data, len))
900                                 return -EFAULT;
901                 if (len < *lenp) {
902                         if(put_user('\n', ((char *) buffer) + len))
903                                 return -EFAULT;
904                         len++;
905                 }
906                 *lenp = len;
907                 filp->f_pos += len;
908         }
909         return 0;
910 }
911
912 /*
913  *      Special case of dostring for the UTS structure. This has locks
914  *      to observe. Should this be in kernel/sys.c ????
915  */
916  
917 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
918                   void *buffer, size_t *lenp)
919 {
920         int r;
921
922         if (!write) {
923                 down_read(&uts_sem);
924                 r=proc_dostring(table,0,filp,buffer,lenp);
925                 up_read(&uts_sem);
926         } else {
927                 down_write(&uts_sem);
928                 r=proc_dostring(table,1,filp,buffer,lenp);
929                 up_write(&uts_sem);
930         }
931         return r;
932 }
933
934 #define OP_SET  0
935 #define OP_AND  1
936 #define OP_OR   2
937 #define OP_MAX  3
938 #define OP_MIN  4
939
940 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
941                   void *buffer, size_t *lenp, int conv, int op)
942 {
943         int *i, vleft, first=1, neg, val;
944         size_t left, len;
945         
946         #define TMPBUFLEN 20
947         char buf[TMPBUFLEN], *p;
948         
949         if (!table->data || !table->maxlen || !*lenp ||
950             (filp->f_pos && !write)) {
951                 *lenp = 0;
952                 return 0;
953         }
954         
955         i = (int *) table->data;
956         vleft = table->maxlen / sizeof(int);
957         left = *lenp;
958         
959         for (; left && vleft--; i++, first=0) {
960                 if (write) {
961                         while (left) {
962                                 char c;
963                                 if (get_user(c, (char *) buffer))
964                                         return -EFAULT;
965                                 if (!isspace(c))
966                                         break;
967                                 left--;
968                                 buffer++;
969                         }
970                         if (!left)
971                                 break;
972                         neg = 0;
973                         len = left;
974                         if (len > TMPBUFLEN-1)
975                                 len = TMPBUFLEN-1;
976                         if(copy_from_user(buf, buffer, len))
977                                 return -EFAULT;
978                         buf[len] = 0;
979                         p = buf;
980                         if (*p == '-' && left > 1) {
981                                 neg = 1;
982                                 left--, p++;
983                         }
984                         if (*p < '0' || *p > '9')
985                                 break;
986                         val = simple_strtoul(p, &p, 0) * conv;
987                         len = p-buf;
988                         if ((len < left) && *p && !isspace(*p))
989                                 break;
990                         if (neg)
991                                 val = -val;
992                         buffer += len;
993                         left -= len;
994                         switch(op) {
995                         case OP_SET:    *i = val; break;
996                         case OP_AND:    *i &= val; break;
997                         case OP_OR:     *i |= val; break;
998                         case OP_MAX:    if(*i < val)
999                                                 *i = val;
1000                                         break;
1001                         case OP_MIN:    if(*i > val)
1002                                                 *i = val;
1003                                         break;
1004                         }
1005                 } else {
1006                         p = buf;
1007                         if (!first)
1008                                 *p++ = '\t';
1009                         sprintf(p, "%d", (*i) / conv);
1010                         len = strlen(buf);
1011                         if (len > left)
1012                                 len = left;
1013                         if(copy_to_user(buffer, buf, len))
1014                                 return -EFAULT;
1015                         left -= len;
1016                         buffer += len;
1017                 }
1018         }
1019
1020         if (!write && !first && left) {
1021                 if(put_user('\n', (char *) buffer))
1022                         return -EFAULT;
1023                 left--, buffer++;
1024         }
1025         if (write) {
1026                 p = (char *) buffer;
1027                 while (left) {
1028                         char c;
1029                         if (get_user(c, p++))
1030                                 return -EFAULT;
1031                         if (!isspace(c))
1032                                 break;
1033                         left--;
1034                 }
1035         }
1036         if (write && first)
1037                 return -EINVAL;
1038         *lenp -= left;
1039         filp->f_pos += *lenp;
1040         return 0;
1041 }
1042
1043 /**
1044  * proc_dointvec - read a vector of integers
1045  * @table: the sysctl table
1046  * @write: %TRUE if this is a write to the sysctl file
1047  * @filp: the file structure
1048  * @buffer: the user buffer
1049  * @lenp: the size of the user buffer
1050  *
1051  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1052  * values from/to the user buffer, treated as an ASCII string. 
1053  *
1054  * Returns 0 on success.
1055  */
1056 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1057                      void *buffer, size_t *lenp)
1058 {
1059     return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
1060 }
1061
1062 /*
1063  *      init may raise the set.
1064  */
1065  
1066 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1067                         void *buffer, size_t *lenp)
1068 {
1069         if (!capable(CAP_SYS_MODULE)) {
1070                 return -EPERM;
1071         }
1072         return do_proc_dointvec(table,write,filp,buffer,lenp,1,
1073                                 (current->pid == 1) ? OP_SET : OP_AND);
1074 }
1075
1076 /**
1077  * proc_dointvec_minmax - read a vector of integers with min/max values
1078  * @table: the sysctl table
1079  * @write: %TRUE if this is a write to the sysctl file
1080  * @filp: the file structure
1081  * @buffer: the user buffer
1082  * @lenp: the size of the user buffer
1083  *
1084  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1085  * values from/to the user buffer, treated as an ASCII string.
1086  *
1087  * This routine will ensure the values are within the range specified by
1088  * table->extra1 (min) and table->extra2 (max).
1089  *
1090  * Returns 0 on success.
1091  */
1092 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1093                   void *buffer, size_t *lenp)
1094 {
1095         int *i, *min, *max, vleft, first=1, neg, val;
1096         size_t len, left;
1097         #define TMPBUFLEN 20
1098         char buf[TMPBUFLEN], *p;
1099         
1100         if (!table->data || !table->maxlen || !*lenp ||
1101             (filp->f_pos && !write)) {
1102                 *lenp = 0;
1103                 return 0;
1104         }
1105         
1106         i = (int *) table->data;
1107         min = (int *) table->extra1;
1108         max = (int *) table->extra2;
1109         vleft = table->maxlen / sizeof(int);
1110         left = *lenp;
1111         
1112         for (; left && vleft--; i++, min++, max++, first=0) {
1113                 if (write) {
1114                         while (left) {
1115                                 char c;
1116                                 if (get_user(c, (char *) buffer))
1117                                         return -EFAULT;
1118                                 if (!isspace(c))
1119                                         break;
1120                                 left--;
1121                                 buffer++;
1122                         }
1123                         if (!left)
1124                                 break;
1125                         neg = 0;
1126                         len = left;
1127                         if (len > TMPBUFLEN-1)
1128                                 len = TMPBUFLEN-1;
1129                         if(copy_from_user(buf, buffer, len))
1130                                 return -EFAULT;
1131                         buf[len] = 0;
1132                         p = buf;
1133                         if (*p == '-' && left > 1) {
1134                                 neg = 1;
1135                                 left--, p++;
1136                         }
1137                         if (*p < '0' || *p > '9')
1138                                 break;
1139                         val = simple_strtoul(p, &p, 0);
1140                         len = p-buf;
1141                         if ((len < left) && *p && !isspace(*p))
1142                                 break;
1143                         if (neg)
1144                                 val = -val;
1145                         buffer += len;
1146                         left -= len;
1147
1148                         if ((min && val < *min) || (max && val > *max))
1149                                 continue;
1150                         *i = val;
1151                 } else {
1152                         p = buf;
1153                         if (!first)
1154                                 *p++ = '\t';
1155                         sprintf(p, "%d", *i);
1156                         len = strlen(buf);
1157                         if (len > left)
1158                                 len = left;
1159                         if(copy_to_user(buffer, buf, len))
1160                                 return -EFAULT;
1161                         left -= len;
1162                         buffer += len;
1163                 }
1164         }
1165
1166         if (!write && !first && left) {
1167                 if(put_user('\n', (char *) buffer))
1168                         return -EFAULT;
1169                 left--, buffer++;
1170         }
1171         if (write) {
1172                 p = (char *) buffer;
1173                 while (left) {
1174                         char c;
1175                         if (get_user(c, p++))
1176                                 return -EFAULT;
1177                         if (!isspace(c))
1178                                 break;
1179                         left--;
1180                 }
1181         }
1182         if (write && first)
1183                 return -EINVAL;
1184         *lenp -= left;
1185         filp->f_pos += *lenp;
1186         return 0;
1187 }
1188
1189 static int do_proc_doulongvec_minmax(ctl_table *table, int write,
1190                                      struct file *filp,
1191                                      void *buffer, size_t *lenp,
1192                                      unsigned long convmul,
1193                                      unsigned long convdiv)
1194 {
1195 #define TMPBUFLEN 20
1196         unsigned long *i, *min, *max, val;
1197         int vleft, first=1, neg;
1198         size_t len, left;
1199         char buf[TMPBUFLEN], *p;
1200         
1201         if (!table->data || !table->maxlen || !*lenp ||
1202             (filp->f_pos && !write)) {
1203                 *lenp = 0;
1204                 return 0;
1205         }
1206         
1207         i = (unsigned long *) table->data;
1208         min = (unsigned long *) table->extra1;
1209         max = (unsigned long *) table->extra2;
1210         vleft = table->maxlen / sizeof(unsigned long);
1211         left = *lenp;
1212         
1213         for (; left && vleft--; i++, first=0) {
1214                 if (write) {
1215                         while (left) {
1216                                 char c;
1217                                 if (get_user(c, (char *) buffer))
1218                                         return -EFAULT;
1219                                 if (!isspace(c))
1220                                         break;
1221                                 left--;
1222                                 buffer++;
1223                         }
1224                         if (!left)
1225                                 break;
1226                         neg = 0;
1227                         len = left;
1228                         if (len > TMPBUFLEN-1)
1229                                 len = TMPBUFLEN-1;
1230                         if(copy_from_user(buf, buffer, len))
1231                                 return -EFAULT;
1232                         buf[len] = 0;
1233                         p = buf;
1234                         if (*p == '-' && left > 1) {
1235                                 neg = 1;
1236                                 left--, p++;
1237                         }
1238                         if (*p < '0' || *p > '9')
1239                                 break;
1240                         val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
1241                         len = p-buf;
1242                         if ((len < left) && *p && !isspace(*p))
1243                                 break;
1244                         if (neg)
1245                                 val = -val;
1246                         buffer += len;
1247                         left -= len;
1248
1249                         if(neg)
1250                                 continue;
1251                         if (min && val < *min++)
1252                                 continue;
1253                         if (max && val > *max++)
1254                                 continue;
1255                         *i = val;
1256                 } else {
1257                         p = buf;
1258                         if (!first)
1259                                 *p++ = '\t';
1260                         sprintf(p, "%lu", convdiv * (*i) / convmul);
1261                         len = strlen(buf);
1262                         if (len > left)
1263                                 len = left;
1264                         if(copy_to_user(buffer, buf, len))
1265                                 return -EFAULT;
1266                         left -= len;
1267                         buffer += len;
1268                 }
1269         }
1270
1271         if (!write && !first && left) {
1272                 if(put_user('\n', (char *) buffer))
1273                         return -EFAULT;
1274                 left--, buffer++;
1275         }
1276         if (write) {
1277                 p = (char *) buffer;
1278                 while (left) {
1279                         char c;
1280                         if (get_user(c, p++))
1281                                 return -EFAULT;
1282                         if (!isspace(c))
1283                                 break;
1284                         left--;
1285                 }
1286         }
1287         if (write && first)
1288                 return -EINVAL;
1289         *lenp -= left;
1290         filp->f_pos += *lenp;
1291         return 0;
1292 #undef TMPBUFLEN
1293 }
1294
1295 /**
1296  * proc_doulongvec_minmax - read a vector of long integers with min/max values
1297  * @table: the sysctl table
1298  * @write: %TRUE if this is a write to the sysctl file
1299  * @filp: the file structure
1300  * @buffer: the user buffer
1301  * @lenp: the size of the user buffer
1302  *
1303  * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
1304  * values from/to the user buffer, treated as an ASCII string.
1305  *
1306  * This routine will ensure the values are within the range specified by
1307  * table->extra1 (min) and table->extra2 (max).
1308  *
1309  * Returns 0 on success.
1310  */
1311 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1312                            void *buffer, size_t *lenp)
1313 {
1314     return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l);
1315 }
1316
1317 /**
1318  * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values
1319  * @table: the sysctl table
1320  * @write: %TRUE if this is a write to the sysctl file
1321  * @filp: the file structure
1322  * @buffer: the user buffer
1323  * @lenp: the size of the user buffer
1324  *
1325  * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
1326  * values from/to the user buffer, treated as an ASCII string. The values
1327  * are treated as milliseconds, and converted to jiffies when they are stored.
1328  *
1329  * This routine will ensure the values are within the range specified by
1330  * table->extra1 (min) and table->extra2 (max).
1331  *
1332  * Returns 0 on success.
1333  */
1334 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1335                                       struct file *filp,
1336                                       void *buffer, size_t *lenp)
1337 {
1338     return do_proc_doulongvec_minmax(table, write, filp, buffer,
1339                                      lenp, HZ, 1000l);
1340 }
1341
1342
1343 /**
1344  * proc_dointvec_jiffies - read a vector of integers as seconds
1345  * @table: the sysctl table
1346  * @write: %TRUE if this is a write to the sysctl file
1347  * @filp: the file structure
1348  * @buffer: the user buffer
1349  * @lenp: the size of the user buffer
1350  *
1351  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1352  * values from/to the user buffer, treated as an ASCII string. 
1353  * The values read are assumed to be in seconds, and are converted into
1354  * jiffies.
1355  *
1356  * Returns 0 on success.
1357  */
1358 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1359                           void *buffer, size_t *lenp)
1360 {
1361     return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET);
1362 }
1363
1364 #else /* CONFIG_PROC_FS */
1365
1366 int proc_dostring(ctl_table *table, int write, struct file *filp,
1367                   void *buffer, size_t *lenp)
1368 {
1369         return -ENOSYS;
1370 }
1371
1372 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
1373                             void *buffer, size_t *lenp)
1374 {
1375         return -ENOSYS;
1376 }
1377
1378 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1379                   void *buffer, size_t *lenp)
1380 {
1381         return -ENOSYS;
1382 }
1383
1384 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1385                         void *buffer, size_t *lenp)
1386 {
1387         return -ENOSYS;
1388 }
1389
1390 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1391                     void *buffer, size_t *lenp)
1392 {
1393         return -ENOSYS;
1394 }
1395
1396 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1397                     void *buffer, size_t *lenp)
1398 {
1399         return -ENOSYS;
1400 }
1401
1402 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1403                     void *buffer, size_t *lenp)
1404 {
1405         return -ENOSYS;
1406 }
1407
1408 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1409                                       struct file *filp,
1410                                       void *buffer, size_t *lenp)
1411 {
1412     return -ENOSYS;
1413 }
1414
1415
1416 #endif /* CONFIG_PROC_FS */
1417
1418
1419 /*
1420  * General sysctl support routines 
1421  */
1422
1423 /* The generic string strategy routine: */
1424 int sysctl_string(ctl_table *table, int *name, int nlen,
1425                   void *oldval, size_t *oldlenp,
1426                   void *newval, size_t newlen, void **context)
1427 {
1428         size_t l, len;
1429         
1430         if (!table->data || !table->maxlen) 
1431                 return -ENOTDIR;
1432         
1433         if (oldval && oldlenp) {
1434                 if (get_user(len, oldlenp))
1435                         return -EFAULT;
1436                 if (len) {
1437                         l = strlen(table->data);
1438                         if (len > l) len = l;
1439                         if (len >= table->maxlen)
1440                                 len = table->maxlen;
1441                         if(copy_to_user(oldval, table->data, len))
1442                                 return -EFAULT;
1443                         if(put_user(0, ((char *) oldval) + len))
1444                                 return -EFAULT;
1445                         if(put_user(len, oldlenp))
1446                                 return -EFAULT;
1447                 }
1448         }
1449         if (newval && newlen) {
1450                 len = newlen;
1451                 if (len > table->maxlen)
1452                         len = table->maxlen;
1453                 if(copy_from_user(table->data, newval, len))
1454                         return -EFAULT;
1455                 if (len == table->maxlen)
1456                         len--;
1457                 ((char *) table->data)[len] = 0;
1458         }
1459         return 0;
1460 }
1461
1462 /*
1463  * This function makes sure that all of the integers in the vector
1464  * are between the minimum and maximum values given in the arrays
1465  * table->extra1 and table->extra2, respectively.
1466  */
1467 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1468                 void *oldval, size_t *oldlenp,
1469                 void *newval, size_t newlen, void **context)
1470 {
1471         int i, *vec, *min, *max;
1472         size_t length;
1473
1474         if (newval && newlen) {
1475                 if (newlen % sizeof(int) != 0)
1476                         return -EINVAL;
1477
1478                 if (!table->extra1 && !table->extra2)
1479                         return 0;
1480
1481                 if (newlen > table->maxlen)
1482                         newlen = table->maxlen;
1483                 length = newlen / sizeof(int);
1484
1485                 vec = (int *) newval;
1486                 min = (int *) table->extra1;
1487                 max = (int *) table->extra2;
1488
1489                 for (i = 0; i < length; i++) {
1490                         int value;
1491                         if (get_user(value, vec + i))
1492                                 return -EFAULT;
1493                         if (min && value < min[i])
1494                                 return -EINVAL;
1495                         if (max && value > max[i])
1496                                 return -EINVAL;
1497                 }
1498         }
1499         return 0;
1500 }
1501
1502 /* Strategy function to convert jiffies to seconds */ 
1503 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1504                 void *oldval, size_t *oldlenp,
1505                 void *newval, size_t newlen, void **context)
1506 {
1507         if (oldval) {
1508                 size_t olen;
1509                 if (oldlenp) { 
1510                         if (get_user(olen, oldlenp))
1511                                 return -EFAULT;
1512                         if (olen!=sizeof(int))
1513                                 return -EINVAL; 
1514                 }
1515                 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) || 
1516                     (oldlenp && put_user(sizeof(int),oldlenp)))
1517                         return -EFAULT;
1518         }
1519         if (newval && newlen) { 
1520                 int new;
1521                 if (newlen != sizeof(int))
1522                         return -EINVAL; 
1523                 if (get_user(new, (int *)newval))
1524                         return -EFAULT;
1525                 *(int *)(table->data) = new*HZ; 
1526         }
1527         return 1;
1528 }
1529
1530
1531 #else /* CONFIG_SYSCTL */
1532
1533
1534 extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
1535 {
1536         return -ENOSYS;
1537 }
1538
1539 int sysctl_string(ctl_table *table, int *name, int nlen,
1540                   void *oldval, size_t *oldlenp,
1541                   void *newval, size_t newlen, void **context)
1542 {
1543         return -ENOSYS;
1544 }
1545
1546 int sysctl_intvec(ctl_table *table, int *name, int nlen,
1547                 void *oldval, size_t *oldlenp,
1548                 void *newval, size_t newlen, void **context)
1549 {
1550         return -ENOSYS;
1551 }
1552
1553 int sysctl_jiffies(ctl_table *table, int *name, int nlen,
1554                 void *oldval, size_t *oldlenp,
1555                 void *newval, size_t newlen, void **context)
1556 {
1557         return -ENOSYS;
1558 }
1559
1560 int proc_dostring(ctl_table *table, int write, struct file *filp,
1561                   void *buffer, size_t *lenp)
1562 {
1563         return -ENOSYS;
1564 }
1565
1566 int proc_dointvec(ctl_table *table, int write, struct file *filp,
1567                   void *buffer, size_t *lenp)
1568 {
1569         return -ENOSYS;
1570 }
1571
1572 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
1573                         void *buffer, size_t *lenp)
1574 {
1575         return -ENOSYS;
1576 }
1577
1578 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
1579                     void *buffer, size_t *lenp)
1580 {
1581         return -ENOSYS;
1582 }
1583
1584 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
1585                           void *buffer, size_t *lenp)
1586 {
1587         return -ENOSYS;
1588 }
1589
1590 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
1591                     void *buffer, size_t *lenp)
1592 {
1593         return -ENOSYS;
1594 }
1595
1596 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
1597                                       struct file *filp,
1598                                       void *buffer, size_t *lenp)
1599 {
1600     return -ENOSYS;
1601 }
1602
1603 struct ctl_table_header * register_sysctl_table(ctl_table * table, 
1604                                                 int insert_at_head)
1605 {
1606         return 0;
1607 }
1608
1609 void unregister_sysctl_table(struct ctl_table_header * table)
1610 {
1611 }
1612
1613 #endif /* CONFIG_SYSCTL */