diff options
author | Reinette Chatre <reinette.chatre@linux.intel.com> | 2006-10-11 04:21:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-11 14:14:22 -0400 |
commit | 01a3ee2b203e511e20f98b85a9172fd32c53e87c (patch) | |
tree | 0dd90d81dc86f231828af23bdb97522405b06cab /lib/bitmap.c | |
parent | 39484e53bb00f55b6303a908070db133608ef2a5 (diff) |
[PATCH] bitmap: parse input from kernel and user buffers
lib/bitmap.c:bitmap_parse() is a library function that received as input a
user buffer. This seemed to have originated from the way the write_proc
function of the /proc filesystem operates.
This has been reworked to not use kmalloc and eliminates a lot of
get_user() overhead by performing one access_ok before using __get_user().
We need to test if we are in kernel or user space (is_user) and access the
buffer differently. We cannot use __get_user() to access kernel addresses
in all cases, for example in architectures with separate address space for
kernel and user.
This function will be useful for other uses as well; for example, taking
input for /sysfs instead of /proc, so it was changed to accept kernel
buffers. We have this use for the Linux UWB project, as part as the
upcoming bandwidth allocator code.
Only a few routines used this function and they were changed too.
Signed-off-by: Reinette Chatre <reinette.chatre@linux.intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Cc: Paul Jackson <pj@sgi.com>
Cc: Joe Korty <joe.korty@ccur.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'lib/bitmap.c')
-rw-r--r-- | lib/bitmap.c | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/lib/bitmap.c b/lib/bitmap.c index d71e38c54ea5..037fa9aa2ed7 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c | |||
@@ -316,10 +316,11 @@ int bitmap_scnprintf(char *buf, unsigned int buflen, | |||
316 | EXPORT_SYMBOL(bitmap_scnprintf); | 316 | EXPORT_SYMBOL(bitmap_scnprintf); |
317 | 317 | ||
318 | /** | 318 | /** |
319 | * bitmap_parse - convert an ASCII hex string into a bitmap. | 319 | * __bitmap_parse - convert an ASCII hex string into a bitmap. |
320 | * @ubuf: pointer to buffer in user space containing string. | 320 | * @buf: pointer to buffer containing string. |
321 | * @ubuflen: buffer size in bytes. If string is smaller than this | 321 | * @buflen: buffer size in bytes. If string is smaller than this |
322 | * then it must be terminated with a \0. | 322 | * then it must be terminated with a \0. |
323 | * @is_user: location of buffer, 0 indicates kernel space | ||
323 | * @maskp: pointer to bitmap array that will contain result. | 324 | * @maskp: pointer to bitmap array that will contain result. |
324 | * @nmaskbits: size of bitmap, in bits. | 325 | * @nmaskbits: size of bitmap, in bits. |
325 | * | 326 | * |
@@ -330,11 +331,13 @@ EXPORT_SYMBOL(bitmap_scnprintf); | |||
330 | * characters and for grouping errors such as "1,,5", ",44", "," and "". | 331 | * characters and for grouping errors such as "1,,5", ",44", "," and "". |
331 | * Leading and trailing whitespace accepted, but not embedded whitespace. | 332 | * Leading and trailing whitespace accepted, but not embedded whitespace. |
332 | */ | 333 | */ |
333 | int bitmap_parse(const char __user *ubuf, unsigned int ubuflen, | 334 | int __bitmap_parse(const char *buf, unsigned int buflen, |
334 | unsigned long *maskp, int nmaskbits) | 335 | int is_user, unsigned long *maskp, |
336 | int nmaskbits) | ||
335 | { | 337 | { |
336 | int c, old_c, totaldigits, ndigits, nchunks, nbits; | 338 | int c, old_c, totaldigits, ndigits, nchunks, nbits; |
337 | u32 chunk; | 339 | u32 chunk; |
340 | const char __user *ubuf = buf; | ||
338 | 341 | ||
339 | bitmap_zero(maskp, nmaskbits); | 342 | bitmap_zero(maskp, nmaskbits); |
340 | 343 | ||
@@ -343,11 +346,15 @@ int bitmap_parse(const char __user *ubuf, unsigned int ubuflen, | |||
343 | chunk = ndigits = 0; | 346 | chunk = ndigits = 0; |
344 | 347 | ||
345 | /* Get the next chunk of the bitmap */ | 348 | /* Get the next chunk of the bitmap */ |
346 | while (ubuflen) { | 349 | while (buflen) { |
347 | old_c = c; | 350 | old_c = c; |
348 | if (get_user(c, ubuf++)) | 351 | if (is_user) { |
349 | return -EFAULT; | 352 | if (__get_user(c, ubuf++)) |
350 | ubuflen--; | 353 | return -EFAULT; |
354 | } | ||
355 | else | ||
356 | c = *buf++; | ||
357 | buflen--; | ||
351 | if (isspace(c)) | 358 | if (isspace(c)) |
352 | continue; | 359 | continue; |
353 | 360 | ||
@@ -388,11 +395,36 @@ int bitmap_parse(const char __user *ubuf, unsigned int ubuflen, | |||
388 | nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ; | 395 | nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ; |
389 | if (nbits > nmaskbits) | 396 | if (nbits > nmaskbits) |
390 | return -EOVERFLOW; | 397 | return -EOVERFLOW; |
391 | } while (ubuflen && c == ','); | 398 | } while (buflen && c == ','); |
392 | 399 | ||
393 | return 0; | 400 | return 0; |
394 | } | 401 | } |
395 | EXPORT_SYMBOL(bitmap_parse); | 402 | EXPORT_SYMBOL(__bitmap_parse); |
403 | |||
404 | /** | ||
405 | * bitmap_parse_user() | ||
406 | * | ||
407 | * @ubuf: pointer to user buffer containing string. | ||
408 | * @ulen: buffer size in bytes. If string is smaller than this | ||
409 | * then it must be terminated with a \0. | ||
410 | * @maskp: pointer to bitmap array that will contain result. | ||
411 | * @nmaskbits: size of bitmap, in bits. | ||
412 | * | ||
413 | * Wrapper for __bitmap_parse(), providing it with user buffer. | ||
414 | * | ||
415 | * We cannot have this as an inline function in bitmap.h because it needs | ||
416 | * linux/uaccess.h to get the access_ok() declaration and this causes | ||
417 | * cyclic dependencies. | ||
418 | */ | ||
419 | int bitmap_parse_user(const char __user *ubuf, | ||
420 | unsigned int ulen, unsigned long *maskp, | ||
421 | int nmaskbits) | ||
422 | { | ||
423 | if (!access_ok(VERIFY_READ, ubuf, ulen)) | ||
424 | return -EFAULT; | ||
425 | return __bitmap_parse((const char *)ubuf, ulen, 1, maskp, nmaskbits); | ||
426 | } | ||
427 | EXPORT_SYMBOL(bitmap_parse_user); | ||
396 | 428 | ||
397 | /* | 429 | /* |
398 | * bscnl_emit(buf, buflen, rbot, rtop, bp) | 430 | * bscnl_emit(buf, buflen, rbot, rtop, bp) |