diff options
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 689 |
1 files changed, 489 insertions, 200 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8686b0f5fc12..ca38e8e3e907 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -37,21 +37,24 @@ | |||
37 | #include <linux/highuid.h> | 37 | #include <linux/highuid.h> |
38 | #include <linux/writeback.h> | 38 | #include <linux/writeback.h> |
39 | #include <linux/ratelimit.h> | 39 | #include <linux/ratelimit.h> |
40 | #include <linux/compaction.h> | ||
40 | #include <linux/hugetlb.h> | 41 | #include <linux/hugetlb.h> |
41 | #include <linux/initrd.h> | 42 | #include <linux/initrd.h> |
42 | #include <linux/key.h> | 43 | #include <linux/key.h> |
43 | #include <linux/times.h> | 44 | #include <linux/times.h> |
44 | #include <linux/limits.h> | 45 | #include <linux/limits.h> |
45 | #include <linux/dcache.h> | 46 | #include <linux/dcache.h> |
47 | #include <linux/dnotify.h> | ||
46 | #include <linux/syscalls.h> | 48 | #include <linux/syscalls.h> |
47 | #include <linux/vmstat.h> | 49 | #include <linux/vmstat.h> |
48 | #include <linux/nfs_fs.h> | 50 | #include <linux/nfs_fs.h> |
49 | #include <linux/acpi.h> | 51 | #include <linux/acpi.h> |
50 | #include <linux/reboot.h> | 52 | #include <linux/reboot.h> |
51 | #include <linux/ftrace.h> | 53 | #include <linux/ftrace.h> |
52 | #include <linux/slow-work.h> | ||
53 | #include <linux/perf_event.h> | 54 | #include <linux/perf_event.h> |
54 | #include <linux/kprobes.h> | 55 | #include <linux/kprobes.h> |
56 | #include <linux/pipe_fs_i.h> | ||
57 | #include <linux/oom.h> | ||
55 | 58 | ||
56 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
57 | #include <asm/processor.h> | 60 | #include <asm/processor.h> |
@@ -74,15 +77,16 @@ | |||
74 | #include <scsi/sg.h> | 77 | #include <scsi/sg.h> |
75 | #endif | 78 | #endif |
76 | 79 | ||
80 | #ifdef CONFIG_LOCKUP_DETECTOR | ||
81 | #include <linux/nmi.h> | ||
82 | #endif | ||
83 | |||
77 | 84 | ||
78 | #if defined(CONFIG_SYSCTL) | 85 | #if defined(CONFIG_SYSCTL) |
79 | 86 | ||
80 | /* External variables not in a header file. */ | 87 | /* External variables not in a header file. */ |
81 | extern int sysctl_overcommit_memory; | 88 | extern int sysctl_overcommit_memory; |
82 | extern int sysctl_overcommit_ratio; | 89 | extern int sysctl_overcommit_ratio; |
83 | extern int sysctl_panic_on_oom; | ||
84 | extern int sysctl_oom_kill_allocating_task; | ||
85 | extern int sysctl_oom_dump_tasks; | ||
86 | extern int max_threads; | 90 | extern int max_threads; |
87 | extern int core_uses_pid; | 91 | extern int core_uses_pid; |
88 | extern int suid_dumpable; | 92 | extern int suid_dumpable; |
@@ -104,7 +108,7 @@ extern int blk_iopoll_enabled; | |||
104 | #endif | 108 | #endif |
105 | 109 | ||
106 | /* Constants used for minimum and maximum */ | 110 | /* Constants used for minimum and maximum */ |
107 | #ifdef CONFIG_DETECT_SOFTLOCKUP | 111 | #ifdef CONFIG_LOCKUP_DETECTOR |
108 | static int sixty = 60; | 112 | static int sixty = 60; |
109 | static int neg_one = -1; | 113 | static int neg_one = -1; |
110 | #endif | 114 | #endif |
@@ -128,6 +132,9 @@ static int min_percpu_pagelist_fract = 8; | |||
128 | 132 | ||
129 | static int ngroups_max = NGROUPS_MAX; | 133 | static int ngroups_max = NGROUPS_MAX; |
130 | 134 | ||
135 | #ifdef CONFIG_INOTIFY_USER | ||
136 | #include <linux/inotify.h> | ||
137 | #endif | ||
131 | #ifdef CONFIG_SPARC | 138 | #ifdef CONFIG_SPARC |
132 | #include <asm/system.h> | 139 | #include <asm/system.h> |
133 | #endif | 140 | #endif |
@@ -163,6 +170,27 @@ static int proc_taint(struct ctl_table *table, int write, | |||
163 | void __user *buffer, size_t *lenp, loff_t *ppos); | 170 | void __user *buffer, size_t *lenp, loff_t *ppos); |
164 | #endif | 171 | #endif |
165 | 172 | ||
173 | #ifdef CONFIG_MAGIC_SYSRQ | ||
174 | static int __sysrq_enabled; /* Note: sysrq code ises it's own private copy */ | ||
175 | |||
176 | static int sysrq_sysctl_handler(ctl_table *table, int write, | ||
177 | void __user *buffer, size_t *lenp, | ||
178 | loff_t *ppos) | ||
179 | { | ||
180 | int error; | ||
181 | |||
182 | error = proc_dointvec(table, write, buffer, lenp, ppos); | ||
183 | if (error) | ||
184 | return error; | ||
185 | |||
186 | if (write) | ||
187 | sysrq_toggle_support(__sysrq_enabled); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | #endif | ||
193 | |||
166 | static struct ctl_table root_table[]; | 194 | static struct ctl_table root_table[]; |
167 | static struct ctl_table_root sysctl_table_root; | 195 | static struct ctl_table_root sysctl_table_root; |
168 | static struct ctl_table_header root_table_header = { | 196 | static struct ctl_table_header root_table_header = { |
@@ -183,9 +211,6 @@ static struct ctl_table fs_table[]; | |||
183 | static struct ctl_table debug_table[]; | 211 | static struct ctl_table debug_table[]; |
184 | static struct ctl_table dev_table[]; | 212 | static struct ctl_table dev_table[]; |
185 | extern struct ctl_table random_table[]; | 213 | extern struct ctl_table random_table[]; |
186 | #ifdef CONFIG_INOTIFY_USER | ||
187 | extern struct ctl_table inotify_table[]; | ||
188 | #endif | ||
189 | #ifdef CONFIG_EPOLL | 214 | #ifdef CONFIG_EPOLL |
190 | extern struct ctl_table epoll_table[]; | 215 | extern struct ctl_table epoll_table[]; |
191 | #endif | 216 | #endif |
@@ -240,6 +265,11 @@ static int min_sched_shares_ratelimit = 100000; /* 100 usec */ | |||
240 | static int max_sched_shares_ratelimit = NSEC_PER_SEC; /* 1 second */ | 265 | static int max_sched_shares_ratelimit = NSEC_PER_SEC; /* 1 second */ |
241 | #endif | 266 | #endif |
242 | 267 | ||
268 | #ifdef CONFIG_COMPACTION | ||
269 | static int min_extfrag_threshold; | ||
270 | static int max_extfrag_threshold = 1000; | ||
271 | #endif | ||
272 | |||
243 | static struct ctl_table kern_table[] = { | 273 | static struct ctl_table kern_table[] = { |
244 | { | 274 | { |
245 | .procname = "sched_child_runs_first", | 275 | .procname = "sched_child_runs_first", |
@@ -534,7 +564,7 @@ static struct ctl_table kern_table[] = { | |||
534 | .extra2 = &one, | 564 | .extra2 = &one, |
535 | }, | 565 | }, |
536 | #endif | 566 | #endif |
537 | #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) | 567 | #ifdef CONFIG_HOTPLUG |
538 | { | 568 | { |
539 | .procname = "hotplug", | 569 | .procname = "hotplug", |
540 | .data = &uevent_helper, | 570 | .data = &uevent_helper, |
@@ -567,7 +597,7 @@ static struct ctl_table kern_table[] = { | |||
567 | .data = &__sysrq_enabled, | 597 | .data = &__sysrq_enabled, |
568 | .maxlen = sizeof (int), | 598 | .maxlen = sizeof (int), |
569 | .mode = 0644, | 599 | .mode = 0644, |
570 | .proc_handler = proc_dointvec, | 600 | .proc_handler = sysrq_sysctl_handler, |
571 | }, | 601 | }, |
572 | #endif | 602 | #endif |
573 | #ifdef CONFIG_PROC_SYSCTL | 603 | #ifdef CONFIG_PROC_SYSCTL |
@@ -621,7 +651,7 @@ static struct ctl_table kern_table[] = { | |||
621 | #endif | 651 | #endif |
622 | { | 652 | { |
623 | .procname = "userprocess_debug", | 653 | .procname = "userprocess_debug", |
624 | .data = &sysctl_userprocess_debug, | 654 | .data = &show_unhandled_signals, |
625 | .maxlen = sizeof(int), | 655 | .maxlen = sizeof(int), |
626 | .mode = 0644, | 656 | .mode = 0644, |
627 | .proc_handler = proc_dointvec, | 657 | .proc_handler = proc_dointvec, |
@@ -682,7 +712,34 @@ static struct ctl_table kern_table[] = { | |||
682 | .mode = 0444, | 712 | .mode = 0444, |
683 | .proc_handler = proc_dointvec, | 713 | .proc_handler = proc_dointvec, |
684 | }, | 714 | }, |
685 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) | 715 | #if defined(CONFIG_LOCKUP_DETECTOR) |
716 | { | ||
717 | .procname = "watchdog", | ||
718 | .data = &watchdog_enabled, | ||
719 | .maxlen = sizeof (int), | ||
720 | .mode = 0644, | ||
721 | .proc_handler = proc_dowatchdog_enabled, | ||
722 | }, | ||
723 | { | ||
724 | .procname = "watchdog_thresh", | ||
725 | .data = &softlockup_thresh, | ||
726 | .maxlen = sizeof(int), | ||
727 | .mode = 0644, | ||
728 | .proc_handler = proc_dowatchdog_thresh, | ||
729 | .extra1 = &neg_one, | ||
730 | .extra2 = &sixty, | ||
731 | }, | ||
732 | { | ||
733 | .procname = "softlockup_panic", | ||
734 | .data = &softlockup_panic, | ||
735 | .maxlen = sizeof(int), | ||
736 | .mode = 0644, | ||
737 | .proc_handler = proc_dointvec_minmax, | ||
738 | .extra1 = &zero, | ||
739 | .extra2 = &one, | ||
740 | }, | ||
741 | #endif | ||
742 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) && !defined(CONFIG_LOCKUP_DETECTOR) | ||
686 | { | 743 | { |
687 | .procname = "unknown_nmi_panic", | 744 | .procname = "unknown_nmi_panic", |
688 | .data = &unknown_nmi_panic, | 745 | .data = &unknown_nmi_panic, |
@@ -785,26 +842,6 @@ static struct ctl_table kern_table[] = { | |||
785 | .proc_handler = proc_dointvec, | 842 | .proc_handler = proc_dointvec, |
786 | }, | 843 | }, |
787 | #endif | 844 | #endif |
788 | #ifdef CONFIG_DETECT_SOFTLOCKUP | ||
789 | { | ||
790 | .procname = "softlockup_panic", | ||
791 | .data = &softlockup_panic, | ||
792 | .maxlen = sizeof(int), | ||
793 | .mode = 0644, | ||
794 | .proc_handler = proc_dointvec_minmax, | ||
795 | .extra1 = &zero, | ||
796 | .extra2 = &one, | ||
797 | }, | ||
798 | { | ||
799 | .procname = "softlockup_thresh", | ||
800 | .data = &softlockup_thresh, | ||
801 | .maxlen = sizeof(int), | ||
802 | .mode = 0644, | ||
803 | .proc_handler = proc_dosoftlockup_thresh, | ||
804 | .extra1 = &neg_one, | ||
805 | .extra2 = &sixty, | ||
806 | }, | ||
807 | #endif | ||
808 | #ifdef CONFIG_DETECT_HUNG_TASK | 845 | #ifdef CONFIG_DETECT_HUNG_TASK |
809 | { | 846 | { |
810 | .procname = "hung_task_panic", | 847 | .procname = "hung_task_panic", |
@@ -878,13 +915,6 @@ static struct ctl_table kern_table[] = { | |||
878 | .proc_handler = proc_dointvec, | 915 | .proc_handler = proc_dointvec, |
879 | }, | 916 | }, |
880 | #endif | 917 | #endif |
881 | #ifdef CONFIG_SLOW_WORK | ||
882 | { | ||
883 | .procname = "slow-work", | ||
884 | .mode = 0555, | ||
885 | .child = slow_work_sysctls, | ||
886 | }, | ||
887 | #endif | ||
888 | #ifdef CONFIG_PERF_EVENTS | 918 | #ifdef CONFIG_PERF_EVENTS |
889 | { | 919 | { |
890 | .procname = "perf_event_paranoid", | 920 | .procname = "perf_event_paranoid", |
@@ -1099,6 +1129,25 @@ static struct ctl_table vm_table[] = { | |||
1099 | .mode = 0644, | 1129 | .mode = 0644, |
1100 | .proc_handler = drop_caches_sysctl_handler, | 1130 | .proc_handler = drop_caches_sysctl_handler, |
1101 | }, | 1131 | }, |
1132 | #ifdef CONFIG_COMPACTION | ||
1133 | { | ||
1134 | .procname = "compact_memory", | ||
1135 | .data = &sysctl_compact_memory, | ||
1136 | .maxlen = sizeof(int), | ||
1137 | .mode = 0200, | ||
1138 | .proc_handler = sysctl_compaction_handler, | ||
1139 | }, | ||
1140 | { | ||
1141 | .procname = "extfrag_threshold", | ||
1142 | .data = &sysctl_extfrag_threshold, | ||
1143 | .maxlen = sizeof(int), | ||
1144 | .mode = 0644, | ||
1145 | .proc_handler = sysctl_extfrag_handler, | ||
1146 | .extra1 = &min_extfrag_threshold, | ||
1147 | .extra2 = &max_extfrag_threshold, | ||
1148 | }, | ||
1149 | |||
1150 | #endif /* CONFIG_COMPACTION */ | ||
1102 | { | 1151 | { |
1103 | .procname = "min_free_kbytes", | 1152 | .procname = "min_free_kbytes", |
1104 | .data = &min_free_kbytes, | 1153 | .data = &min_free_kbytes, |
@@ -1423,6 +1472,14 @@ static struct ctl_table fs_table[] = { | |||
1423 | .child = binfmt_misc_table, | 1472 | .child = binfmt_misc_table, |
1424 | }, | 1473 | }, |
1425 | #endif | 1474 | #endif |
1475 | { | ||
1476 | .procname = "pipe-max-size", | ||
1477 | .data = &pipe_max_size, | ||
1478 | .maxlen = sizeof(int), | ||
1479 | .mode = 0644, | ||
1480 | .proc_handler = &pipe_proc_fn, | ||
1481 | .extra1 = &pipe_min_size, | ||
1482 | }, | ||
1426 | /* | 1483 | /* |
1427 | * NOTE: do not add new entries to this table unless you have read | 1484 | * NOTE: do not add new entries to this table unless you have read |
1428 | * Documentation/sysctl/ctl_unnumbered.txt | 1485 | * Documentation/sysctl/ctl_unnumbered.txt |
@@ -1431,7 +1488,8 @@ static struct ctl_table fs_table[] = { | |||
1431 | }; | 1488 | }; |
1432 | 1489 | ||
1433 | static struct ctl_table debug_table[] = { | 1490 | static struct ctl_table debug_table[] = { |
1434 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) | 1491 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \ |
1492 | defined(CONFIG_S390) | ||
1435 | { | 1493 | { |
1436 | .procname = "exception-trace", | 1494 | .procname = "exception-trace", |
1437 | .data = &show_unhandled_signals, | 1495 | .data = &show_unhandled_signals, |
@@ -2040,8 +2098,132 @@ int proc_dostring(struct ctl_table *table, int write, | |||
2040 | buffer, lenp, ppos); | 2098 | buffer, lenp, ppos); |
2041 | } | 2099 | } |
2042 | 2100 | ||
2101 | static size_t proc_skip_spaces(char **buf) | ||
2102 | { | ||
2103 | size_t ret; | ||
2104 | char *tmp = skip_spaces(*buf); | ||
2105 | ret = tmp - *buf; | ||
2106 | *buf = tmp; | ||
2107 | return ret; | ||
2108 | } | ||
2109 | |||
2110 | static void proc_skip_char(char **buf, size_t *size, const char v) | ||
2111 | { | ||
2112 | while (*size) { | ||
2113 | if (**buf != v) | ||
2114 | break; | ||
2115 | (*size)--; | ||
2116 | (*buf)++; | ||
2117 | } | ||
2118 | } | ||
2119 | |||
2120 | #define TMPBUFLEN 22 | ||
2121 | /** | ||
2122 | * proc_get_long - reads an ASCII formatted integer from a user buffer | ||
2123 | * | ||
2124 | * @buf: a kernel buffer | ||
2125 | * @size: size of the kernel buffer | ||
2126 | * @val: this is where the number will be stored | ||
2127 | * @neg: set to %TRUE if number is negative | ||
2128 | * @perm_tr: a vector which contains the allowed trailers | ||
2129 | * @perm_tr_len: size of the perm_tr vector | ||
2130 | * @tr: pointer to store the trailer character | ||
2131 | * | ||
2132 | * In case of success %0 is returned and @buf and @size are updated with | ||
2133 | * the amount of bytes read. If @tr is non-NULL and a trailing | ||
2134 | * character exists (size is non-zero after returning from this | ||
2135 | * function), @tr is updated with the trailing character. | ||
2136 | */ | ||
2137 | static int proc_get_long(char **buf, size_t *size, | ||
2138 | unsigned long *val, bool *neg, | ||
2139 | const char *perm_tr, unsigned perm_tr_len, char *tr) | ||
2140 | { | ||
2141 | int len; | ||
2142 | char *p, tmp[TMPBUFLEN]; | ||
2143 | |||
2144 | if (!*size) | ||
2145 | return -EINVAL; | ||
2146 | |||
2147 | len = *size; | ||
2148 | if (len > TMPBUFLEN - 1) | ||
2149 | len = TMPBUFLEN - 1; | ||
2150 | |||
2151 | memcpy(tmp, *buf, len); | ||
2152 | |||
2153 | tmp[len] = 0; | ||
2154 | p = tmp; | ||
2155 | if (*p == '-' && *size > 1) { | ||
2156 | *neg = true; | ||
2157 | p++; | ||
2158 | } else | ||
2159 | *neg = false; | ||
2160 | if (!isdigit(*p)) | ||
2161 | return -EINVAL; | ||
2162 | |||
2163 | *val = simple_strtoul(p, &p, 0); | ||
2164 | |||
2165 | len = p - tmp; | ||
2166 | |||
2167 | /* We don't know if the next char is whitespace thus we may accept | ||
2168 | * invalid integers (e.g. 1234...a) or two integers instead of one | ||
2169 | * (e.g. 123...1). So lets not allow such large numbers. */ | ||
2170 | if (len == TMPBUFLEN - 1) | ||
2171 | return -EINVAL; | ||
2172 | |||
2173 | if (len < *size && perm_tr_len && !memchr(perm_tr, *p, perm_tr_len)) | ||
2174 | return -EINVAL; | ||
2175 | |||
2176 | if (tr && (len < *size)) | ||
2177 | *tr = *p; | ||
2178 | |||
2179 | *buf += len; | ||
2180 | *size -= len; | ||
2181 | |||
2182 | return 0; | ||
2183 | } | ||
2184 | |||
2185 | /** | ||
2186 | * proc_put_long - converts an integer to a decimal ASCII formatted string | ||
2187 | * | ||
2188 | * @buf: the user buffer | ||
2189 | * @size: the size of the user buffer | ||
2190 | * @val: the integer to be converted | ||
2191 | * @neg: sign of the number, %TRUE for negative | ||
2192 | * | ||
2193 | * In case of success %0 is returned and @buf and @size are updated with | ||
2194 | * the amount of bytes written. | ||
2195 | */ | ||
2196 | static int proc_put_long(void __user **buf, size_t *size, unsigned long val, | ||
2197 | bool neg) | ||
2198 | { | ||
2199 | int len; | ||
2200 | char tmp[TMPBUFLEN], *p = tmp; | ||
2201 | |||
2202 | sprintf(p, "%s%lu", neg ? "-" : "", val); | ||
2203 | len = strlen(tmp); | ||
2204 | if (len > *size) | ||
2205 | len = *size; | ||
2206 | if (copy_to_user(*buf, tmp, len)) | ||
2207 | return -EFAULT; | ||
2208 | *size -= len; | ||
2209 | *buf += len; | ||
2210 | return 0; | ||
2211 | } | ||
2212 | #undef TMPBUFLEN | ||
2043 | 2213 | ||
2044 | static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, | 2214 | static int proc_put_char(void __user **buf, size_t *size, char c) |
2215 | { | ||
2216 | if (*size) { | ||
2217 | char __user **buffer = (char __user **)buf; | ||
2218 | if (put_user(c, *buffer)) | ||
2219 | return -EFAULT; | ||
2220 | (*size)--, (*buffer)++; | ||
2221 | *buf = *buffer; | ||
2222 | } | ||
2223 | return 0; | ||
2224 | } | ||
2225 | |||
2226 | static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, | ||
2045 | int *valp, | 2227 | int *valp, |
2046 | int write, void *data) | 2228 | int write, void *data) |
2047 | { | 2229 | { |
@@ -2050,33 +2232,31 @@ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, | |||
2050 | } else { | 2232 | } else { |
2051 | int val = *valp; | 2233 | int val = *valp; |
2052 | if (val < 0) { | 2234 | if (val < 0) { |
2053 | *negp = -1; | 2235 | *negp = true; |
2054 | *lvalp = (unsigned long)-val; | 2236 | *lvalp = (unsigned long)-val; |
2055 | } else { | 2237 | } else { |
2056 | *negp = 0; | 2238 | *negp = false; |
2057 | *lvalp = (unsigned long)val; | 2239 | *lvalp = (unsigned long)val; |
2058 | } | 2240 | } |
2059 | } | 2241 | } |
2060 | return 0; | 2242 | return 0; |
2061 | } | 2243 | } |
2062 | 2244 | ||
2245 | static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; | ||
2246 | |||
2063 | static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, | 2247 | static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, |
2064 | int write, void __user *buffer, | 2248 | int write, void __user *buffer, |
2065 | size_t *lenp, loff_t *ppos, | 2249 | size_t *lenp, loff_t *ppos, |
2066 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, | 2250 | int (*conv)(bool *negp, unsigned long *lvalp, int *valp, |
2067 | int write, void *data), | 2251 | int write, void *data), |
2068 | void *data) | 2252 | void *data) |
2069 | { | 2253 | { |
2070 | #define TMPBUFLEN 21 | 2254 | int *i, vleft, first = 1, err = 0; |
2071 | int *i, vleft, first = 1, neg; | 2255 | unsigned long page = 0; |
2072 | unsigned long lval; | 2256 | size_t left; |
2073 | size_t left, len; | 2257 | char *kbuf; |
2074 | |||
2075 | char buf[TMPBUFLEN], *p; | ||
2076 | char __user *s = buffer; | ||
2077 | 2258 | ||
2078 | if (!tbl_data || !table->maxlen || !*lenp || | 2259 | if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { |
2079 | (*ppos && !write)) { | ||
2080 | *lenp = 0; | 2260 | *lenp = 0; |
2081 | return 0; | 2261 | return 0; |
2082 | } | 2262 | } |
@@ -2088,89 +2268,71 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, | |||
2088 | if (!conv) | 2268 | if (!conv) |
2089 | conv = do_proc_dointvec_conv; | 2269 | conv = do_proc_dointvec_conv; |
2090 | 2270 | ||
2271 | if (write) { | ||
2272 | if (left > PAGE_SIZE - 1) | ||
2273 | left = PAGE_SIZE - 1; | ||
2274 | page = __get_free_page(GFP_TEMPORARY); | ||
2275 | kbuf = (char *) page; | ||
2276 | if (!kbuf) | ||
2277 | return -ENOMEM; | ||
2278 | if (copy_from_user(kbuf, buffer, left)) { | ||
2279 | err = -EFAULT; | ||
2280 | goto free; | ||
2281 | } | ||
2282 | kbuf[left] = 0; | ||
2283 | } | ||
2284 | |||
2091 | for (; left && vleft--; i++, first=0) { | 2285 | for (; left && vleft--; i++, first=0) { |
2286 | unsigned long lval; | ||
2287 | bool neg; | ||
2288 | |||
2092 | if (write) { | 2289 | if (write) { |
2093 | while (left) { | 2290 | left -= proc_skip_spaces(&kbuf); |
2094 | char c; | 2291 | |
2095 | if (get_user(c, s)) | ||
2096 | return -EFAULT; | ||
2097 | if (!isspace(c)) | ||
2098 | break; | ||
2099 | left--; | ||
2100 | s++; | ||
2101 | } | ||
2102 | if (!left) | 2292 | if (!left) |
2103 | break; | 2293 | break; |
2104 | neg = 0; | 2294 | err = proc_get_long(&kbuf, &left, &lval, &neg, |
2105 | len = left; | 2295 | proc_wspace_sep, |
2106 | if (len > sizeof(buf) - 1) | 2296 | sizeof(proc_wspace_sep), NULL); |
2107 | len = sizeof(buf) - 1; | 2297 | if (err) |
2108 | if (copy_from_user(buf, s, len)) | ||
2109 | return -EFAULT; | ||
2110 | buf[len] = 0; | ||
2111 | p = buf; | ||
2112 | if (*p == '-' && left > 1) { | ||
2113 | neg = 1; | ||
2114 | p++; | ||
2115 | } | ||
2116 | if (*p < '0' || *p > '9') | ||
2117 | break; | ||
2118 | |||
2119 | lval = simple_strtoul(p, &p, 0); | ||
2120 | |||
2121 | len = p-buf; | ||
2122 | if ((len < left) && *p && !isspace(*p)) | ||
2123 | break; | 2298 | break; |
2124 | s += len; | 2299 | if (conv(&neg, &lval, i, 1, data)) { |
2125 | left -= len; | 2300 | err = -EINVAL; |
2126 | |||
2127 | if (conv(&neg, &lval, i, 1, data)) | ||
2128 | break; | 2301 | break; |
2302 | } | ||
2129 | } else { | 2303 | } else { |
2130 | p = buf; | 2304 | if (conv(&neg, &lval, i, 0, data)) { |
2305 | err = -EINVAL; | ||
2306 | break; | ||
2307 | } | ||
2131 | if (!first) | 2308 | if (!first) |
2132 | *p++ = '\t'; | 2309 | err = proc_put_char(&buffer, &left, '\t'); |
2133 | 2310 | if (err) | |
2134 | if (conv(&neg, &lval, i, 0, data)) | 2311 | break; |
2312 | err = proc_put_long(&buffer, &left, lval, neg); | ||
2313 | if (err) | ||
2135 | break; | 2314 | break; |
2136 | |||
2137 | sprintf(p, "%s%lu", neg ? "-" : "", lval); | ||
2138 | len = strlen(buf); | ||
2139 | if (len > left) | ||
2140 | len = left; | ||
2141 | if(copy_to_user(s, buf, len)) | ||
2142 | return -EFAULT; | ||
2143 | left -= len; | ||
2144 | s += len; | ||
2145 | } | 2315 | } |
2146 | } | 2316 | } |
2147 | 2317 | ||
2148 | if (!write && !first && left) { | 2318 | if (!write && !first && left && !err) |
2149 | if(put_user('\n', s)) | 2319 | err = proc_put_char(&buffer, &left, '\n'); |
2150 | return -EFAULT; | 2320 | if (write && !err && left) |
2151 | left--, s++; | 2321 | left -= proc_skip_spaces(&kbuf); |
2152 | } | 2322 | free: |
2153 | if (write) { | 2323 | if (write) { |
2154 | while (left) { | 2324 | free_page(page); |
2155 | char c; | 2325 | if (first) |
2156 | if (get_user(c, s++)) | 2326 | return err ? : -EINVAL; |
2157 | return -EFAULT; | ||
2158 | if (!isspace(c)) | ||
2159 | break; | ||
2160 | left--; | ||
2161 | } | ||
2162 | } | 2327 | } |
2163 | if (write && first) | ||
2164 | return -EINVAL; | ||
2165 | *lenp -= left; | 2328 | *lenp -= left; |
2166 | *ppos += *lenp; | 2329 | *ppos += *lenp; |
2167 | return 0; | 2330 | return err; |
2168 | #undef TMPBUFLEN | ||
2169 | } | 2331 | } |
2170 | 2332 | ||
2171 | static int do_proc_dointvec(struct ctl_table *table, int write, | 2333 | static int do_proc_dointvec(struct ctl_table *table, int write, |
2172 | void __user *buffer, size_t *lenp, loff_t *ppos, | 2334 | void __user *buffer, size_t *lenp, loff_t *ppos, |
2173 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, | 2335 | int (*conv)(bool *negp, unsigned long *lvalp, int *valp, |
2174 | int write, void *data), | 2336 | int write, void *data), |
2175 | void *data) | 2337 | void *data) |
2176 | { | 2338 | { |
@@ -2238,8 +2400,8 @@ struct do_proc_dointvec_minmax_conv_param { | |||
2238 | int *max; | 2400 | int *max; |
2239 | }; | 2401 | }; |
2240 | 2402 | ||
2241 | static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp, | 2403 | static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, |
2242 | int *valp, | 2404 | int *valp, |
2243 | int write, void *data) | 2405 | int write, void *data) |
2244 | { | 2406 | { |
2245 | struct do_proc_dointvec_minmax_conv_param *param = data; | 2407 | struct do_proc_dointvec_minmax_conv_param *param = data; |
@@ -2252,10 +2414,10 @@ static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp, | |||
2252 | } else { | 2414 | } else { |
2253 | int val = *valp; | 2415 | int val = *valp; |
2254 | if (val < 0) { | 2416 | if (val < 0) { |
2255 | *negp = -1; | 2417 | *negp = true; |
2256 | *lvalp = (unsigned long)-val; | 2418 | *lvalp = (unsigned long)-val; |
2257 | } else { | 2419 | } else { |
2258 | *negp = 0; | 2420 | *negp = false; |
2259 | *lvalp = (unsigned long)val; | 2421 | *lvalp = (unsigned long)val; |
2260 | } | 2422 | } |
2261 | } | 2423 | } |
@@ -2295,102 +2457,78 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int | |||
2295 | unsigned long convmul, | 2457 | unsigned long convmul, |
2296 | unsigned long convdiv) | 2458 | unsigned long convdiv) |
2297 | { | 2459 | { |
2298 | #define TMPBUFLEN 21 | 2460 | unsigned long *i, *min, *max; |
2299 | unsigned long *i, *min, *max, val; | 2461 | int vleft, first = 1, err = 0; |
2300 | int vleft, first=1, neg; | 2462 | unsigned long page = 0; |
2301 | size_t len, left; | 2463 | size_t left; |
2302 | char buf[TMPBUFLEN], *p; | 2464 | char *kbuf; |
2303 | char __user *s = buffer; | 2465 | |
2304 | 2466 | if (!data || !table->maxlen || !*lenp || (*ppos && !write)) { | |
2305 | if (!data || !table->maxlen || !*lenp || | ||
2306 | (*ppos && !write)) { | ||
2307 | *lenp = 0; | 2467 | *lenp = 0; |
2308 | return 0; | 2468 | return 0; |
2309 | } | 2469 | } |
2310 | 2470 | ||
2311 | i = (unsigned long *) data; | 2471 | i = (unsigned long *) data; |
2312 | min = (unsigned long *) table->extra1; | 2472 | min = (unsigned long *) table->extra1; |
2313 | max = (unsigned long *) table->extra2; | 2473 | max = (unsigned long *) table->extra2; |
2314 | vleft = table->maxlen / sizeof(unsigned long); | 2474 | vleft = table->maxlen / sizeof(unsigned long); |
2315 | left = *lenp; | 2475 | left = *lenp; |
2316 | 2476 | ||
2477 | if (write) { | ||
2478 | if (left > PAGE_SIZE - 1) | ||
2479 | left = PAGE_SIZE - 1; | ||
2480 | page = __get_free_page(GFP_TEMPORARY); | ||
2481 | kbuf = (char *) page; | ||
2482 | if (!kbuf) | ||
2483 | return -ENOMEM; | ||
2484 | if (copy_from_user(kbuf, buffer, left)) { | ||
2485 | err = -EFAULT; | ||
2486 | goto free; | ||
2487 | } | ||
2488 | kbuf[left] = 0; | ||
2489 | } | ||
2490 | |||
2317 | for (; left && vleft--; i++, min++, max++, first=0) { | 2491 | for (; left && vleft--; i++, min++, max++, first=0) { |
2492 | unsigned long val; | ||
2493 | |||
2318 | if (write) { | 2494 | if (write) { |
2319 | while (left) { | 2495 | bool neg; |
2320 | char c; | 2496 | |
2321 | if (get_user(c, s)) | 2497 | left -= proc_skip_spaces(&kbuf); |
2322 | return -EFAULT; | 2498 | |
2323 | if (!isspace(c)) | 2499 | err = proc_get_long(&kbuf, &left, &val, &neg, |
2324 | break; | 2500 | proc_wspace_sep, |
2325 | left--; | 2501 | sizeof(proc_wspace_sep), NULL); |
2326 | s++; | 2502 | if (err) |
2327 | } | ||
2328 | if (!left) | ||
2329 | break; | ||
2330 | neg = 0; | ||
2331 | len = left; | ||
2332 | if (len > TMPBUFLEN-1) | ||
2333 | len = TMPBUFLEN-1; | ||
2334 | if (copy_from_user(buf, s, len)) | ||
2335 | return -EFAULT; | ||
2336 | buf[len] = 0; | ||
2337 | p = buf; | ||
2338 | if (*p == '-' && left > 1) { | ||
2339 | neg = 1; | ||
2340 | p++; | ||
2341 | } | ||
2342 | if (*p < '0' || *p > '9') | ||
2343 | break; | ||
2344 | val = simple_strtoul(p, &p, 0) * convmul / convdiv ; | ||
2345 | len = p-buf; | ||
2346 | if ((len < left) && *p && !isspace(*p)) | ||
2347 | break; | 2503 | break; |
2348 | if (neg) | 2504 | if (neg) |
2349 | val = -val; | ||
2350 | s += len; | ||
2351 | left -= len; | ||
2352 | |||
2353 | if(neg) | ||
2354 | continue; | 2505 | continue; |
2355 | if ((min && val < *min) || (max && val > *max)) | 2506 | if ((min && val < *min) || (max && val > *max)) |
2356 | continue; | 2507 | continue; |
2357 | *i = val; | 2508 | *i = val; |
2358 | } else { | 2509 | } else { |
2359 | p = buf; | 2510 | val = convdiv * (*i) / convmul; |
2360 | if (!first) | 2511 | if (!first) |
2361 | *p++ = '\t'; | 2512 | err = proc_put_char(&buffer, &left, '\t'); |
2362 | sprintf(p, "%lu", convdiv * (*i) / convmul); | 2513 | err = proc_put_long(&buffer, &left, val, false); |
2363 | len = strlen(buf); | 2514 | if (err) |
2364 | if (len > left) | 2515 | break; |
2365 | len = left; | ||
2366 | if(copy_to_user(s, buf, len)) | ||
2367 | return -EFAULT; | ||
2368 | left -= len; | ||
2369 | s += len; | ||
2370 | } | 2516 | } |
2371 | } | 2517 | } |
2372 | 2518 | ||
2373 | if (!write && !first && left) { | 2519 | if (!write && !first && left && !err) |
2374 | if(put_user('\n', s)) | 2520 | err = proc_put_char(&buffer, &left, '\n'); |
2375 | return -EFAULT; | 2521 | if (write && !err) |
2376 | left--, s++; | 2522 | left -= proc_skip_spaces(&kbuf); |
2377 | } | 2523 | free: |
2378 | if (write) { | 2524 | if (write) { |
2379 | while (left) { | 2525 | free_page(page); |
2380 | char c; | 2526 | if (first) |
2381 | if (get_user(c, s++)) | 2527 | return err ? : -EINVAL; |
2382 | return -EFAULT; | ||
2383 | if (!isspace(c)) | ||
2384 | break; | ||
2385 | left--; | ||
2386 | } | ||
2387 | } | 2528 | } |
2388 | if (write && first) | ||
2389 | return -EINVAL; | ||
2390 | *lenp -= left; | 2529 | *lenp -= left; |
2391 | *ppos += *lenp; | 2530 | *ppos += *lenp; |
2392 | return 0; | 2531 | return err; |
2393 | #undef TMPBUFLEN | ||
2394 | } | 2532 | } |
2395 | 2533 | ||
2396 | static int do_proc_doulongvec_minmax(struct ctl_table *table, int write, | 2534 | static int do_proc_doulongvec_minmax(struct ctl_table *table, int write, |
@@ -2451,7 +2589,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write, | |||
2451 | } | 2589 | } |
2452 | 2590 | ||
2453 | 2591 | ||
2454 | static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp, | 2592 | static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp, |
2455 | int *valp, | 2593 | int *valp, |
2456 | int write, void *data) | 2594 | int write, void *data) |
2457 | { | 2595 | { |
@@ -2463,10 +2601,10 @@ static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp, | |||
2463 | int val = *valp; | 2601 | int val = *valp; |
2464 | unsigned long lval; | 2602 | unsigned long lval; |
2465 | if (val < 0) { | 2603 | if (val < 0) { |
2466 | *negp = -1; | 2604 | *negp = true; |
2467 | lval = (unsigned long)-val; | 2605 | lval = (unsigned long)-val; |
2468 | } else { | 2606 | } else { |
2469 | *negp = 0; | 2607 | *negp = false; |
2470 | lval = (unsigned long)val; | 2608 | lval = (unsigned long)val; |
2471 | } | 2609 | } |
2472 | *lvalp = lval / HZ; | 2610 | *lvalp = lval / HZ; |
@@ -2474,7 +2612,7 @@ static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp, | |||
2474 | return 0; | 2612 | return 0; |
2475 | } | 2613 | } |
2476 | 2614 | ||
2477 | static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp, | 2615 | static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp, |
2478 | int *valp, | 2616 | int *valp, |
2479 | int write, void *data) | 2617 | int write, void *data) |
2480 | { | 2618 | { |
@@ -2486,10 +2624,10 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp, | |||
2486 | int val = *valp; | 2624 | int val = *valp; |
2487 | unsigned long lval; | 2625 | unsigned long lval; |
2488 | if (val < 0) { | 2626 | if (val < 0) { |
2489 | *negp = -1; | 2627 | *negp = true; |
2490 | lval = (unsigned long)-val; | 2628 | lval = (unsigned long)-val; |
2491 | } else { | 2629 | } else { |
2492 | *negp = 0; | 2630 | *negp = false; |
2493 | lval = (unsigned long)val; | 2631 | lval = (unsigned long)val; |
2494 | } | 2632 | } |
2495 | *lvalp = jiffies_to_clock_t(lval); | 2633 | *lvalp = jiffies_to_clock_t(lval); |
@@ -2497,7 +2635,7 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp, | |||
2497 | return 0; | 2635 | return 0; |
2498 | } | 2636 | } |
2499 | 2637 | ||
2500 | static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp, | 2638 | static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, |
2501 | int *valp, | 2639 | int *valp, |
2502 | int write, void *data) | 2640 | int write, void *data) |
2503 | { | 2641 | { |
@@ -2507,10 +2645,10 @@ static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp, | |||
2507 | int val = *valp; | 2645 | int val = *valp; |
2508 | unsigned long lval; | 2646 | unsigned long lval; |
2509 | if (val < 0) { | 2647 | if (val < 0) { |
2510 | *negp = -1; | 2648 | *negp = true; |
2511 | lval = (unsigned long)-val; | 2649 | lval = (unsigned long)-val; |
2512 | } else { | 2650 | } else { |
2513 | *negp = 0; | 2651 | *negp = false; |
2514 | lval = (unsigned long)val; | 2652 | lval = (unsigned long)val; |
2515 | } | 2653 | } |
2516 | *lvalp = jiffies_to_msecs(lval); | 2654 | *lvalp = jiffies_to_msecs(lval); |
@@ -2607,6 +2745,157 @@ static int proc_do_cad_pid(struct ctl_table *table, int write, | |||
2607 | return 0; | 2745 | return 0; |
2608 | } | 2746 | } |
2609 | 2747 | ||
2748 | /** | ||
2749 | * proc_do_large_bitmap - read/write from/to a large bitmap | ||
2750 | * @table: the sysctl table | ||
2751 | * @write: %TRUE if this is a write to the sysctl file | ||
2752 | * @buffer: the user buffer | ||
2753 | * @lenp: the size of the user buffer | ||
2754 | * @ppos: file position | ||
2755 | * | ||
2756 | * The bitmap is stored at table->data and the bitmap length (in bits) | ||
2757 | * in table->maxlen. | ||
2758 | * | ||
2759 | * We use a range comma separated format (e.g. 1,3-4,10-10) so that | ||
2760 | * large bitmaps may be represented in a compact manner. Writing into | ||
2761 | * the file will clear the bitmap then update it with the given input. | ||
2762 | * | ||
2763 | * Returns 0 on success. | ||
2764 | */ | ||
2765 | int proc_do_large_bitmap(struct ctl_table *table, int write, | ||
2766 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2767 | { | ||
2768 | int err = 0; | ||
2769 | bool first = 1; | ||
2770 | size_t left = *lenp; | ||
2771 | unsigned long bitmap_len = table->maxlen; | ||
2772 | unsigned long *bitmap = (unsigned long *) table->data; | ||
2773 | unsigned long *tmp_bitmap = NULL; | ||
2774 | char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c; | ||
2775 | |||
2776 | if (!bitmap_len || !left || (*ppos && !write)) { | ||
2777 | *lenp = 0; | ||
2778 | return 0; | ||
2779 | } | ||
2780 | |||
2781 | if (write) { | ||
2782 | unsigned long page = 0; | ||
2783 | char *kbuf; | ||
2784 | |||
2785 | if (left > PAGE_SIZE - 1) | ||
2786 | left = PAGE_SIZE - 1; | ||
2787 | |||
2788 | page = __get_free_page(GFP_TEMPORARY); | ||
2789 | kbuf = (char *) page; | ||
2790 | if (!kbuf) | ||
2791 | return -ENOMEM; | ||
2792 | if (copy_from_user(kbuf, buffer, left)) { | ||
2793 | free_page(page); | ||
2794 | return -EFAULT; | ||
2795 | } | ||
2796 | kbuf[left] = 0; | ||
2797 | |||
2798 | tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long), | ||
2799 | GFP_KERNEL); | ||
2800 | if (!tmp_bitmap) { | ||
2801 | free_page(page); | ||
2802 | return -ENOMEM; | ||
2803 | } | ||
2804 | proc_skip_char(&kbuf, &left, '\n'); | ||
2805 | while (!err && left) { | ||
2806 | unsigned long val_a, val_b; | ||
2807 | bool neg; | ||
2808 | |||
2809 | err = proc_get_long(&kbuf, &left, &val_a, &neg, tr_a, | ||
2810 | sizeof(tr_a), &c); | ||
2811 | if (err) | ||
2812 | break; | ||
2813 | if (val_a >= bitmap_len || neg) { | ||
2814 | err = -EINVAL; | ||
2815 | break; | ||
2816 | } | ||
2817 | |||
2818 | val_b = val_a; | ||
2819 | if (left) { | ||
2820 | kbuf++; | ||
2821 | left--; | ||
2822 | } | ||
2823 | |||
2824 | if (c == '-') { | ||
2825 | err = proc_get_long(&kbuf, &left, &val_b, | ||
2826 | &neg, tr_b, sizeof(tr_b), | ||
2827 | &c); | ||
2828 | if (err) | ||
2829 | break; | ||
2830 | if (val_b >= bitmap_len || neg || | ||
2831 | val_a > val_b) { | ||
2832 | err = -EINVAL; | ||
2833 | break; | ||
2834 | } | ||
2835 | if (left) { | ||
2836 | kbuf++; | ||
2837 | left--; | ||
2838 | } | ||
2839 | } | ||
2840 | |||
2841 | while (val_a <= val_b) | ||
2842 | set_bit(val_a++, tmp_bitmap); | ||
2843 | |||
2844 | first = 0; | ||
2845 | proc_skip_char(&kbuf, &left, '\n'); | ||
2846 | } | ||
2847 | free_page(page); | ||
2848 | } else { | ||
2849 | unsigned long bit_a, bit_b = 0; | ||
2850 | |||
2851 | while (left) { | ||
2852 | bit_a = find_next_bit(bitmap, bitmap_len, bit_b); | ||
2853 | if (bit_a >= bitmap_len) | ||
2854 | break; | ||
2855 | bit_b = find_next_zero_bit(bitmap, bitmap_len, | ||
2856 | bit_a + 1) - 1; | ||
2857 | |||
2858 | if (!first) { | ||
2859 | err = proc_put_char(&buffer, &left, ','); | ||
2860 | if (err) | ||
2861 | break; | ||
2862 | } | ||
2863 | err = proc_put_long(&buffer, &left, bit_a, false); | ||
2864 | if (err) | ||
2865 | break; | ||
2866 | if (bit_a != bit_b) { | ||
2867 | err = proc_put_char(&buffer, &left, '-'); | ||
2868 | if (err) | ||
2869 | break; | ||
2870 | err = proc_put_long(&buffer, &left, bit_b, false); | ||
2871 | if (err) | ||
2872 | break; | ||
2873 | } | ||
2874 | |||
2875 | first = 0; bit_b++; | ||
2876 | } | ||
2877 | if (!err) | ||
2878 | err = proc_put_char(&buffer, &left, '\n'); | ||
2879 | } | ||
2880 | |||
2881 | if (!err) { | ||
2882 | if (write) { | ||
2883 | if (*ppos) | ||
2884 | bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len); | ||
2885 | else | ||
2886 | memcpy(bitmap, tmp_bitmap, | ||
2887 | BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long)); | ||
2888 | } | ||
2889 | kfree(tmp_bitmap); | ||
2890 | *lenp -= left; | ||
2891 | *ppos += *lenp; | ||
2892 | return 0; | ||
2893 | } else { | ||
2894 | kfree(tmp_bitmap); | ||
2895 | return err; | ||
2896 | } | ||
2897 | } | ||
2898 | |||
2610 | #else /* CONFIG_PROC_FS */ | 2899 | #else /* CONFIG_PROC_FS */ |
2611 | 2900 | ||
2612 | int proc_dostring(struct ctl_table *table, int write, | 2901 | int proc_dostring(struct ctl_table *table, int write, |