aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r--kernel/sysctl.c579
1 files changed, 415 insertions, 164 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c649d1c5fe09..18821e77b2a0 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -164,6 +164,27 @@ static int proc_taint(struct ctl_table *table, int write,
164 void __user *buffer, size_t *lenp, loff_t *ppos); 164 void __user *buffer, size_t *lenp, loff_t *ppos);
165#endif 165#endif
166 166
167#ifdef CONFIG_MAGIC_SYSRQ
168static int __sysrq_enabled; /* Note: sysrq code ises it's own private copy */
169
170static int sysrq_sysctl_handler(ctl_table *table, int write,
171 void __user *buffer, size_t *lenp,
172 loff_t *ppos)
173{
174 int error;
175
176 error = proc_dointvec(table, write, buffer, lenp, ppos);
177 if (error)
178 return error;
179
180 if (write)
181 sysrq_toggle_support(__sysrq_enabled);
182
183 return 0;
184}
185
186#endif
187
167static struct ctl_table root_table[]; 188static struct ctl_table root_table[];
168static struct ctl_table_root sysctl_table_root; 189static struct ctl_table_root sysctl_table_root;
169static struct ctl_table_header root_table_header = { 190static struct ctl_table_header root_table_header = {
@@ -568,7 +589,7 @@ static struct ctl_table kern_table[] = {
568 .data = &__sysrq_enabled, 589 .data = &__sysrq_enabled,
569 .maxlen = sizeof (int), 590 .maxlen = sizeof (int),
570 .mode = 0644, 591 .mode = 0644,
571 .proc_handler = proc_dointvec, 592 .proc_handler = sysrq_sysctl_handler,
572 }, 593 },
573#endif 594#endif
574#ifdef CONFIG_PROC_SYSCTL 595#ifdef CONFIG_PROC_SYSCTL
@@ -622,7 +643,7 @@ static struct ctl_table kern_table[] = {
622#endif 643#endif
623 { 644 {
624 .procname = "userprocess_debug", 645 .procname = "userprocess_debug",
625 .data = &sysctl_userprocess_debug, 646 .data = &show_unhandled_signals,
626 .maxlen = sizeof(int), 647 .maxlen = sizeof(int),
627 .mode = 0644, 648 .mode = 0644,
628 .proc_handler = proc_dointvec, 649 .proc_handler = proc_dointvec,
@@ -1440,7 +1461,8 @@ static struct ctl_table fs_table[] = {
1440}; 1461};
1441 1462
1442static struct ctl_table debug_table[] = { 1463static struct ctl_table debug_table[] = {
1443#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) 1464#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \
1465 defined(CONFIG_S390)
1444 { 1466 {
1445 .procname = "exception-trace", 1467 .procname = "exception-trace",
1446 .data = &show_unhandled_signals, 1468 .data = &show_unhandled_signals,
@@ -2049,8 +2071,132 @@ int proc_dostring(struct ctl_table *table, int write,
2049 buffer, lenp, ppos); 2071 buffer, lenp, ppos);
2050} 2072}
2051 2073
2074static size_t proc_skip_spaces(char **buf)
2075{
2076 size_t ret;
2077 char *tmp = skip_spaces(*buf);
2078 ret = tmp - *buf;
2079 *buf = tmp;
2080 return ret;
2081}
2082
2083static void proc_skip_char(char **buf, size_t *size, const char v)
2084{
2085 while (*size) {
2086 if (**buf != v)
2087 break;
2088 (*size)--;
2089 (*buf)++;
2090 }
2091}
2092
2093#define TMPBUFLEN 22
2094/**
2095 * proc_get_long - reads an ASCII formated integer from a user buffer
2096 *
2097 * @buf - a kernel buffer
2098 * @size - size of the kernel buffer
2099 * @val - this is where the number will be stored
2100 * @neg - set to %TRUE if number is negative
2101 * @perm_tr - a vector which contains the allowed trailers
2102 * @perm_tr_len - size of the perm_tr vector
2103 * @tr - pointer to store the trailer character
2104 *
2105 * In case of success 0 is returned and buf and size are updated with
2106 * the amount of bytes read. If tr is non NULL and a trailing
2107 * character exist (size is non zero after returning from this
2108 * function) tr is updated with the trailing character.
2109 */
2110static int proc_get_long(char **buf, size_t *size,
2111 unsigned long *val, bool *neg,
2112 const char *perm_tr, unsigned perm_tr_len, char *tr)
2113{
2114 int len;
2115 char *p, tmp[TMPBUFLEN];
2116
2117 if (!*size)
2118 return -EINVAL;
2119
2120 len = *size;
2121 if (len > TMPBUFLEN - 1)
2122 len = TMPBUFLEN - 1;
2123
2124 memcpy(tmp, *buf, len);
2125
2126 tmp[len] = 0;
2127 p = tmp;
2128 if (*p == '-' && *size > 1) {
2129 *neg = true;
2130 p++;
2131 } else
2132 *neg = false;
2133 if (!isdigit(*p))
2134 return -EINVAL;
2135
2136 *val = simple_strtoul(p, &p, 0);
2137
2138 len = p - tmp;
2139
2140 /* We don't know if the next char is whitespace thus we may accept
2141 * invalid integers (e.g. 1234...a) or two integers instead of one
2142 * (e.g. 123...1). So lets not allow such large numbers. */
2143 if (len == TMPBUFLEN - 1)
2144 return -EINVAL;
2145
2146 if (len < *size && perm_tr_len && !memchr(perm_tr, *p, perm_tr_len))
2147 return -EINVAL;
2148
2149 if (tr && (len < *size))
2150 *tr = *p;
2151
2152 *buf += len;
2153 *size -= len;
2154
2155 return 0;
2156}
2157
2158/**
2159 * proc_put_long - coverts an integer to a decimal ASCII formated string
2160 *
2161 * @buf - the user buffer
2162 * @size - the size of the user buffer
2163 * @val - the integer to be converted
2164 * @neg - sign of the number, %TRUE for negative
2165 *
2166 * In case of success 0 is returned and buf and size are updated with
2167 * the amount of bytes read.
2168 */
2169static int proc_put_long(void __user **buf, size_t *size, unsigned long val,
2170 bool neg)
2171{
2172 int len;
2173 char tmp[TMPBUFLEN], *p = tmp;
2174
2175 sprintf(p, "%s%lu", neg ? "-" : "", val);
2176 len = strlen(tmp);
2177 if (len > *size)
2178 len = *size;
2179 if (copy_to_user(*buf, tmp, len))
2180 return -EFAULT;
2181 *size -= len;
2182 *buf += len;
2183 return 0;
2184}
2185#undef TMPBUFLEN
2052 2186
2053static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, 2187static int proc_put_char(void __user **buf, size_t *size, char c)
2188{
2189 if (*size) {
2190 char __user **buffer = (char __user **)buf;
2191 if (put_user(c, *buffer))
2192 return -EFAULT;
2193 (*size)--, (*buffer)++;
2194 *buf = *buffer;
2195 }
2196 return 0;
2197}
2198
2199static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
2054 int *valp, 2200 int *valp,
2055 int write, void *data) 2201 int write, void *data)
2056{ 2202{
@@ -2059,33 +2205,31 @@ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
2059 } else { 2205 } else {
2060 int val = *valp; 2206 int val = *valp;
2061 if (val < 0) { 2207 if (val < 0) {
2062 *negp = -1; 2208 *negp = true;
2063 *lvalp = (unsigned long)-val; 2209 *lvalp = (unsigned long)-val;
2064 } else { 2210 } else {
2065 *negp = 0; 2211 *negp = false;
2066 *lvalp = (unsigned long)val; 2212 *lvalp = (unsigned long)val;
2067 } 2213 }
2068 } 2214 }
2069 return 0; 2215 return 0;
2070} 2216}
2071 2217
2218static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
2219
2072static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, 2220static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
2073 int write, void __user *buffer, 2221 int write, void __user *buffer,
2074 size_t *lenp, loff_t *ppos, 2222 size_t *lenp, loff_t *ppos,
2075 int (*conv)(int *negp, unsigned long *lvalp, int *valp, 2223 int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
2076 int write, void *data), 2224 int write, void *data),
2077 void *data) 2225 void *data)
2078{ 2226{
2079#define TMPBUFLEN 21 2227 int *i, vleft, first = 1, err = 0;
2080 int *i, vleft, first = 1, neg; 2228 unsigned long page = 0;
2081 unsigned long lval; 2229 size_t left;
2082 size_t left, len; 2230 char *kbuf;
2083 2231
2084 char buf[TMPBUFLEN], *p; 2232 if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
2085 char __user *s = buffer;
2086
2087 if (!tbl_data || !table->maxlen || !*lenp ||
2088 (*ppos && !write)) {
2089 *lenp = 0; 2233 *lenp = 0;
2090 return 0; 2234 return 0;
2091 } 2235 }
@@ -2097,89 +2241,69 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
2097 if (!conv) 2241 if (!conv)
2098 conv = do_proc_dointvec_conv; 2242 conv = do_proc_dointvec_conv;
2099 2243
2244 if (write) {
2245 if (left > PAGE_SIZE - 1)
2246 left = PAGE_SIZE - 1;
2247 page = __get_free_page(GFP_TEMPORARY);
2248 kbuf = (char *) page;
2249 if (!kbuf)
2250 return -ENOMEM;
2251 if (copy_from_user(kbuf, buffer, left)) {
2252 err = -EFAULT;
2253 goto free;
2254 }
2255 kbuf[left] = 0;
2256 }
2257
2100 for (; left && vleft--; i++, first=0) { 2258 for (; left && vleft--; i++, first=0) {
2101 if (write) { 2259 unsigned long lval;
2102 while (left) { 2260 bool neg;
2103 char c;
2104 if (get_user(c, s))
2105 return -EFAULT;
2106 if (!isspace(c))
2107 break;
2108 left--;
2109 s++;
2110 }
2111 if (!left)
2112 break;
2113 neg = 0;
2114 len = left;
2115 if (len > sizeof(buf) - 1)
2116 len = sizeof(buf) - 1;
2117 if (copy_from_user(buf, s, len))
2118 return -EFAULT;
2119 buf[len] = 0;
2120 p = buf;
2121 if (*p == '-' && left > 1) {
2122 neg = 1;
2123 p++;
2124 }
2125 if (*p < '0' || *p > '9')
2126 break;
2127 2261
2128 lval = simple_strtoul(p, &p, 0); 2262 if (write) {
2263 left -= proc_skip_spaces(&kbuf);
2129 2264
2130 len = p-buf; 2265 err = proc_get_long(&kbuf, &left, &lval, &neg,
2131 if ((len < left) && *p && !isspace(*p)) 2266 proc_wspace_sep,
2267 sizeof(proc_wspace_sep), NULL);
2268 if (err)
2132 break; 2269 break;
2133 s += len; 2270 if (conv(&neg, &lval, i, 1, data)) {
2134 left -= len; 2271 err = -EINVAL;
2135
2136 if (conv(&neg, &lval, i, 1, data))
2137 break; 2272 break;
2273 }
2138 } else { 2274 } else {
2139 p = buf; 2275 if (conv(&neg, &lval, i, 0, data)) {
2276 err = -EINVAL;
2277 break;
2278 }
2140 if (!first) 2279 if (!first)
2141 *p++ = '\t'; 2280 err = proc_put_char(&buffer, &left, '\t');
2142 2281 if (err)
2143 if (conv(&neg, &lval, i, 0, data)) 2282 break;
2283 err = proc_put_long(&buffer, &left, lval, neg);
2284 if (err)
2144 break; 2285 break;
2145
2146 sprintf(p, "%s%lu", neg ? "-" : "", lval);
2147 len = strlen(buf);
2148 if (len > left)
2149 len = left;
2150 if(copy_to_user(s, buf, len))
2151 return -EFAULT;
2152 left -= len;
2153 s += len;
2154 } 2286 }
2155 } 2287 }
2156 2288
2157 if (!write && !first && left) { 2289 if (!write && !first && left && !err)
2158 if(put_user('\n', s)) 2290 err = proc_put_char(&buffer, &left, '\n');
2159 return -EFAULT; 2291 if (write && !err)
2160 left--, s++; 2292 left -= proc_skip_spaces(&kbuf);
2161 } 2293free:
2162 if (write) { 2294 if (write) {
2163 while (left) { 2295 free_page(page);
2164 char c; 2296 if (first)
2165 if (get_user(c, s++)) 2297 return err ? : -EINVAL;
2166 return -EFAULT;
2167 if (!isspace(c))
2168 break;
2169 left--;
2170 }
2171 } 2298 }
2172 if (write && first)
2173 return -EINVAL;
2174 *lenp -= left; 2299 *lenp -= left;
2175 *ppos += *lenp; 2300 *ppos += *lenp;
2176 return 0; 2301 return err;
2177#undef TMPBUFLEN
2178} 2302}
2179 2303
2180static int do_proc_dointvec(struct ctl_table *table, int write, 2304static int do_proc_dointvec(struct ctl_table *table, int write,
2181 void __user *buffer, size_t *lenp, loff_t *ppos, 2305 void __user *buffer, size_t *lenp, loff_t *ppos,
2182 int (*conv)(int *negp, unsigned long *lvalp, int *valp, 2306 int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
2183 int write, void *data), 2307 int write, void *data),
2184 void *data) 2308 void *data)
2185{ 2309{
@@ -2247,8 +2371,8 @@ struct do_proc_dointvec_minmax_conv_param {
2247 int *max; 2371 int *max;
2248}; 2372};
2249 2373
2250static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp, 2374static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
2251 int *valp, 2375 int *valp,
2252 int write, void *data) 2376 int write, void *data)
2253{ 2377{
2254 struct do_proc_dointvec_minmax_conv_param *param = data; 2378 struct do_proc_dointvec_minmax_conv_param *param = data;
@@ -2261,10 +2385,10 @@ static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp,
2261 } else { 2385 } else {
2262 int val = *valp; 2386 int val = *valp;
2263 if (val < 0) { 2387 if (val < 0) {
2264 *negp = -1; 2388 *negp = true;
2265 *lvalp = (unsigned long)-val; 2389 *lvalp = (unsigned long)-val;
2266 } else { 2390 } else {
2267 *negp = 0; 2391 *negp = false;
2268 *lvalp = (unsigned long)val; 2392 *lvalp = (unsigned long)val;
2269 } 2393 }
2270 } 2394 }
@@ -2304,102 +2428,78 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
2304 unsigned long convmul, 2428 unsigned long convmul,
2305 unsigned long convdiv) 2429 unsigned long convdiv)
2306{ 2430{
2307#define TMPBUFLEN 21 2431 unsigned long *i, *min, *max;
2308 unsigned long *i, *min, *max, val; 2432 int vleft, first = 1, err = 0;
2309 int vleft, first=1, neg; 2433 unsigned long page = 0;
2310 size_t len, left; 2434 size_t left;
2311 char buf[TMPBUFLEN], *p; 2435 char *kbuf;
2312 char __user *s = buffer; 2436
2313 2437 if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {
2314 if (!data || !table->maxlen || !*lenp ||
2315 (*ppos && !write)) {
2316 *lenp = 0; 2438 *lenp = 0;
2317 return 0; 2439 return 0;
2318 } 2440 }
2319 2441
2320 i = (unsigned long *) data; 2442 i = (unsigned long *) data;
2321 min = (unsigned long *) table->extra1; 2443 min = (unsigned long *) table->extra1;
2322 max = (unsigned long *) table->extra2; 2444 max = (unsigned long *) table->extra2;
2323 vleft = table->maxlen / sizeof(unsigned long); 2445 vleft = table->maxlen / sizeof(unsigned long);
2324 left = *lenp; 2446 left = *lenp;
2325 2447
2448 if (write) {
2449 if (left > PAGE_SIZE - 1)
2450 left = PAGE_SIZE - 1;
2451 page = __get_free_page(GFP_TEMPORARY);
2452 kbuf = (char *) page;
2453 if (!kbuf)
2454 return -ENOMEM;
2455 if (copy_from_user(kbuf, buffer, left)) {
2456 err = -EFAULT;
2457 goto free;
2458 }
2459 kbuf[left] = 0;
2460 }
2461
2326 for (; left && vleft--; i++, min++, max++, first=0) { 2462 for (; left && vleft--; i++, min++, max++, first=0) {
2463 unsigned long val;
2464
2327 if (write) { 2465 if (write) {
2328 while (left) { 2466 bool neg;
2329 char c; 2467
2330 if (get_user(c, s)) 2468 left -= proc_skip_spaces(&kbuf);
2331 return -EFAULT; 2469
2332 if (!isspace(c)) 2470 err = proc_get_long(&kbuf, &left, &val, &neg,
2333 break; 2471 proc_wspace_sep,
2334 left--; 2472 sizeof(proc_wspace_sep), NULL);
2335 s++; 2473 if (err)
2336 }
2337 if (!left)
2338 break;
2339 neg = 0;
2340 len = left;
2341 if (len > TMPBUFLEN-1)
2342 len = TMPBUFLEN-1;
2343 if (copy_from_user(buf, s, len))
2344 return -EFAULT;
2345 buf[len] = 0;
2346 p = buf;
2347 if (*p == '-' && left > 1) {
2348 neg = 1;
2349 p++;
2350 }
2351 if (*p < '0' || *p > '9')
2352 break;
2353 val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
2354 len = p-buf;
2355 if ((len < left) && *p && !isspace(*p))
2356 break; 2474 break;
2357 if (neg) 2475 if (neg)
2358 val = -val;
2359 s += len;
2360 left -= len;
2361
2362 if(neg)
2363 continue; 2476 continue;
2364 if ((min && val < *min) || (max && val > *max)) 2477 if ((min && val < *min) || (max && val > *max))
2365 continue; 2478 continue;
2366 *i = val; 2479 *i = val;
2367 } else { 2480 } else {
2368 p = buf; 2481 val = convdiv * (*i) / convmul;
2369 if (!first) 2482 if (!first)
2370 *p++ = '\t'; 2483 err = proc_put_char(&buffer, &left, '\t');
2371 sprintf(p, "%lu", convdiv * (*i) / convmul); 2484 err = proc_put_long(&buffer, &left, val, false);
2372 len = strlen(buf); 2485 if (err)
2373 if (len > left) 2486 break;
2374 len = left;
2375 if(copy_to_user(s, buf, len))
2376 return -EFAULT;
2377 left -= len;
2378 s += len;
2379 } 2487 }
2380 } 2488 }
2381 2489
2382 if (!write && !first && left) { 2490 if (!write && !first && left && !err)
2383 if(put_user('\n', s)) 2491 err = proc_put_char(&buffer, &left, '\n');
2384 return -EFAULT; 2492 if (write && !err)
2385 left--, s++; 2493 left -= proc_skip_spaces(&kbuf);
2386 } 2494free:
2387 if (write) { 2495 if (write) {
2388 while (left) { 2496 free_page(page);
2389 char c; 2497 if (first)
2390 if (get_user(c, s++)) 2498 return err ? : -EINVAL;
2391 return -EFAULT;
2392 if (!isspace(c))
2393 break;
2394 left--;
2395 }
2396 } 2499 }
2397 if (write && first)
2398 return -EINVAL;
2399 *lenp -= left; 2500 *lenp -= left;
2400 *ppos += *lenp; 2501 *ppos += *lenp;
2401 return 0; 2502 return err;
2402#undef TMPBUFLEN
2403} 2503}
2404 2504
2405static int do_proc_doulongvec_minmax(struct ctl_table *table, int write, 2505static int do_proc_doulongvec_minmax(struct ctl_table *table, int write,
@@ -2460,7 +2560,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
2460} 2560}
2461 2561
2462 2562
2463static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp, 2563static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp,
2464 int *valp, 2564 int *valp,
2465 int write, void *data) 2565 int write, void *data)
2466{ 2566{
@@ -2472,10 +2572,10 @@ static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
2472 int val = *valp; 2572 int val = *valp;
2473 unsigned long lval; 2573 unsigned long lval;
2474 if (val < 0) { 2574 if (val < 0) {
2475 *negp = -1; 2575 *negp = true;
2476 lval = (unsigned long)-val; 2576 lval = (unsigned long)-val;
2477 } else { 2577 } else {
2478 *negp = 0; 2578 *negp = false;
2479 lval = (unsigned long)val; 2579 lval = (unsigned long)val;
2480 } 2580 }
2481 *lvalp = lval / HZ; 2581 *lvalp = lval / HZ;
@@ -2483,7 +2583,7 @@ static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
2483 return 0; 2583 return 0;
2484} 2584}
2485 2585
2486static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp, 2586static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp,
2487 int *valp, 2587 int *valp,
2488 int write, void *data) 2588 int write, void *data)
2489{ 2589{
@@ -2495,10 +2595,10 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
2495 int val = *valp; 2595 int val = *valp;
2496 unsigned long lval; 2596 unsigned long lval;
2497 if (val < 0) { 2597 if (val < 0) {
2498 *negp = -1; 2598 *negp = true;
2499 lval = (unsigned long)-val; 2599 lval = (unsigned long)-val;
2500 } else { 2600 } else {
2501 *negp = 0; 2601 *negp = false;
2502 lval = (unsigned long)val; 2602 lval = (unsigned long)val;
2503 } 2603 }
2504 *lvalp = jiffies_to_clock_t(lval); 2604 *lvalp = jiffies_to_clock_t(lval);
@@ -2506,7 +2606,7 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
2506 return 0; 2606 return 0;
2507} 2607}
2508 2608
2509static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp, 2609static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
2510 int *valp, 2610 int *valp,
2511 int write, void *data) 2611 int write, void *data)
2512{ 2612{
@@ -2516,10 +2616,10 @@ static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp,
2516 int val = *valp; 2616 int val = *valp;
2517 unsigned long lval; 2617 unsigned long lval;
2518 if (val < 0) { 2618 if (val < 0) {
2519 *negp = -1; 2619 *negp = true;
2520 lval = (unsigned long)-val; 2620 lval = (unsigned long)-val;
2521 } else { 2621 } else {
2522 *negp = 0; 2622 *negp = false;
2523 lval = (unsigned long)val; 2623 lval = (unsigned long)val;
2524 } 2624 }
2525 *lvalp = jiffies_to_msecs(lval); 2625 *lvalp = jiffies_to_msecs(lval);
@@ -2616,6 +2716,157 @@ static int proc_do_cad_pid(struct ctl_table *table, int write,
2616 return 0; 2716 return 0;
2617} 2717}
2618 2718
2719/**
2720 * proc_do_large_bitmap - read/write from/to a large bitmap
2721 * @table: the sysctl table
2722 * @write: %TRUE if this is a write to the sysctl file
2723 * @buffer: the user buffer
2724 * @lenp: the size of the user buffer
2725 * @ppos: file position
2726 *
2727 * The bitmap is stored at table->data and the bitmap length (in bits)
2728 * in table->maxlen.
2729 *
2730 * We use a range comma separated format (e.g. 1,3-4,10-10) so that
2731 * large bitmaps may be represented in a compact manner. Writing into
2732 * the file will clear the bitmap then update it with the given input.
2733 *
2734 * Returns 0 on success.
2735 */
2736int proc_do_large_bitmap(struct ctl_table *table, int write,
2737 void __user *buffer, size_t *lenp, loff_t *ppos)
2738{
2739 int err = 0;
2740 bool first = 1;
2741 size_t left = *lenp;
2742 unsigned long bitmap_len = table->maxlen;
2743 unsigned long *bitmap = (unsigned long *) table->data;
2744 unsigned long *tmp_bitmap = NULL;
2745 char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c;
2746
2747 if (!bitmap_len || !left || (*ppos && !write)) {
2748 *lenp = 0;
2749 return 0;
2750 }
2751
2752 if (write) {
2753 unsigned long page = 0;
2754 char *kbuf;
2755
2756 if (left > PAGE_SIZE - 1)
2757 left = PAGE_SIZE - 1;
2758
2759 page = __get_free_page(GFP_TEMPORARY);
2760 kbuf = (char *) page;
2761 if (!kbuf)
2762 return -ENOMEM;
2763 if (copy_from_user(kbuf, buffer, left)) {
2764 free_page(page);
2765 return -EFAULT;
2766 }
2767 kbuf[left] = 0;
2768
2769 tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long),
2770 GFP_KERNEL);
2771 if (!tmp_bitmap) {
2772 free_page(page);
2773 return -ENOMEM;
2774 }
2775 proc_skip_char(&kbuf, &left, '\n');
2776 while (!err && left) {
2777 unsigned long val_a, val_b;
2778 bool neg;
2779
2780 err = proc_get_long(&kbuf, &left, &val_a, &neg, tr_a,
2781 sizeof(tr_a), &c);
2782 if (err)
2783 break;
2784 if (val_a >= bitmap_len || neg) {
2785 err = -EINVAL;
2786 break;
2787 }
2788
2789 val_b = val_a;
2790 if (left) {
2791 kbuf++;
2792 left--;
2793 }
2794
2795 if (c == '-') {
2796 err = proc_get_long(&kbuf, &left, &val_b,
2797 &neg, tr_b, sizeof(tr_b),
2798 &c);
2799 if (err)
2800 break;
2801 if (val_b >= bitmap_len || neg ||
2802 val_a > val_b) {
2803 err = -EINVAL;
2804 break;
2805 }
2806 if (left) {
2807 kbuf++;
2808 left--;
2809 }
2810 }
2811
2812 while (val_a <= val_b)
2813 set_bit(val_a++, tmp_bitmap);
2814
2815 first = 0;
2816 proc_skip_char(&kbuf, &left, '\n');
2817 }
2818 free_page(page);
2819 } else {
2820 unsigned long bit_a, bit_b = 0;
2821
2822 while (left) {
2823 bit_a = find_next_bit(bitmap, bitmap_len, bit_b);
2824 if (bit_a >= bitmap_len)
2825 break;
2826 bit_b = find_next_zero_bit(bitmap, bitmap_len,
2827 bit_a + 1) - 1;
2828
2829 if (!first) {
2830 err = proc_put_char(&buffer, &left, ',');
2831 if (err)
2832 break;
2833 }
2834 err = proc_put_long(&buffer, &left, bit_a, false);
2835 if (err)
2836 break;
2837 if (bit_a != bit_b) {
2838 err = proc_put_char(&buffer, &left, '-');
2839 if (err)
2840 break;
2841 err = proc_put_long(&buffer, &left, bit_b, false);
2842 if (err)
2843 break;
2844 }
2845
2846 first = 0; bit_b++;
2847 }
2848 if (!err)
2849 err = proc_put_char(&buffer, &left, '\n');
2850 }
2851
2852 if (!err) {
2853 if (write) {
2854 if (*ppos)
2855 bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len);
2856 else
2857 memcpy(bitmap, tmp_bitmap,
2858 BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long));
2859 }
2860 kfree(tmp_bitmap);
2861 *lenp -= left;
2862 *ppos += *lenp;
2863 return 0;
2864 } else {
2865 kfree(tmp_bitmap);
2866 return err;
2867 }
2868}
2869
2619#else /* CONFIG_PROC_FS */ 2870#else /* CONFIG_PROC_FS */
2620 2871
2621int proc_dostring(struct ctl_table *table, int write, 2872int proc_dostring(struct ctl_table *table, int write,