aboutsummaryrefslogtreecommitdiffstats
path: root/lib/bitmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bitmap.c')
-rw-r--r--lib/bitmap.c50
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 == ',');