diff options
Diffstat (limited to 'lib/bitmap.c')
-rw-r--r-- | lib/bitmap.c | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/lib/bitmap.c b/lib/bitmap.c index eca88087fa8a..0b66f0e5eb6b 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c | |||
@@ -496,6 +496,11 @@ EXPORT_SYMBOL(bitmap_print_to_pagebuf); | |||
496 | * ranges. Consecutively set bits are shown as two hyphen-separated | 496 | * ranges. Consecutively set bits are shown as two hyphen-separated |
497 | * decimal numbers, the smallest and largest bit numbers set in | 497 | * decimal numbers, the smallest and largest bit numbers set in |
498 | * the range. | 498 | * the range. |
499 | * Optionally each range can be postfixed to denote that only parts of it | ||
500 | * should be set. The range will divided to groups of specific size. | ||
501 | * From each group will be used only defined amount of bits. | ||
502 | * Syntax: range:used_size/group_size | ||
503 | * Example: 0-1023:2/256 ==> 0,1,256,257,512,513,768,769 | ||
499 | * | 504 | * |
500 | * Returns 0 on success, -errno on invalid input strings. | 505 | * Returns 0 on success, -errno on invalid input strings. |
501 | * Error values: | 506 | * Error values: |
@@ -507,16 +512,20 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, | |||
507 | int is_user, unsigned long *maskp, | 512 | int is_user, unsigned long *maskp, |
508 | int nmaskbits) | 513 | int nmaskbits) |
509 | { | 514 | { |
510 | unsigned a, b; | 515 | unsigned int a, b, old_a, old_b; |
516 | unsigned int group_size, used_size; | ||
511 | int c, old_c, totaldigits, ndigits; | 517 | int c, old_c, totaldigits, ndigits; |
512 | const char __user __force *ubuf = (const char __user __force *)buf; | 518 | const char __user __force *ubuf = (const char __user __force *)buf; |
513 | int at_start, in_range; | 519 | int at_start, in_range, in_partial_range; |
514 | 520 | ||
515 | totaldigits = c = 0; | 521 | totaldigits = c = 0; |
522 | old_a = old_b = 0; | ||
523 | group_size = used_size = 0; | ||
516 | bitmap_zero(maskp, nmaskbits); | 524 | bitmap_zero(maskp, nmaskbits); |
517 | do { | 525 | do { |
518 | at_start = 1; | 526 | at_start = 1; |
519 | in_range = 0; | 527 | in_range = 0; |
528 | in_partial_range = 0; | ||
520 | a = b = 0; | 529 | a = b = 0; |
521 | ndigits = totaldigits; | 530 | ndigits = totaldigits; |
522 | 531 | ||
@@ -547,6 +556,24 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, | |||
547 | if ((totaldigits != ndigits) && isspace(old_c)) | 556 | if ((totaldigits != ndigits) && isspace(old_c)) |
548 | return -EINVAL; | 557 | return -EINVAL; |
549 | 558 | ||
559 | if (c == '/') { | ||
560 | used_size = a; | ||
561 | at_start = 1; | ||
562 | in_range = 0; | ||
563 | a = b = 0; | ||
564 | continue; | ||
565 | } | ||
566 | |||
567 | if (c == ':') { | ||
568 | old_a = a; | ||
569 | old_b = b; | ||
570 | at_start = 1; | ||
571 | in_range = 0; | ||
572 | in_partial_range = 1; | ||
573 | a = b = 0; | ||
574 | continue; | ||
575 | } | ||
576 | |||
550 | if (c == '-') { | 577 | if (c == '-') { |
551 | if (at_start || in_range) | 578 | if (at_start || in_range) |
552 | return -EINVAL; | 579 | return -EINVAL; |
@@ -567,15 +594,30 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, | |||
567 | } | 594 | } |
568 | if (ndigits == totaldigits) | 595 | if (ndigits == totaldigits) |
569 | continue; | 596 | continue; |
597 | if (in_partial_range) { | ||
598 | group_size = a; | ||
599 | a = old_a; | ||
600 | b = old_b; | ||
601 | old_a = old_b = 0; | ||
602 | } | ||
570 | /* if no digit is after '-', it's wrong*/ | 603 | /* if no digit is after '-', it's wrong*/ |
571 | if (at_start && in_range) | 604 | if (at_start && in_range) |
572 | return -EINVAL; | 605 | return -EINVAL; |
573 | if (!(a <= b)) | 606 | if (!(a <= b) || !(used_size <= group_size)) |
574 | return -EINVAL; | 607 | return -EINVAL; |
575 | if (b >= nmaskbits) | 608 | if (b >= nmaskbits) |
576 | return -ERANGE; | 609 | return -ERANGE; |
577 | while (a <= b) { | 610 | while (a <= b) { |
578 | set_bit(a, maskp); | 611 | if (in_partial_range) { |
612 | static int pos_in_group = 1; | ||
613 | |||
614 | if (pos_in_group <= used_size) | ||
615 | set_bit(a, maskp); | ||
616 | |||
617 | if (a == b || ++pos_in_group > group_size) | ||
618 | pos_in_group = 1; | ||
619 | } else | ||
620 | set_bit(a, maskp); | ||
579 | a++; | 621 | a++; |
580 | } | 622 | } |
581 | } while (buflen && c == ','); | 623 | } while (buflen && c == ','); |