Note that this patch is backward compatible with current syntax.
Signed-off-by: Noam Camus <noa...@mellanox.com>
---
Any sugestions for simpler syntax which keeps its generality are welcomed.
Change Log:
V2: Fix typo in example at function header for __bitmap_parselist()
V3: Fix typo in commit log and also typo at example
---
lib/bitmap.c | 44 ++++++++++++++++++++++++++++++++++++++++----
1 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/lib/bitmap.c b/lib/bitmap.c
index c66da50..bccfd87 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -496,6 +496,9 @@ EXPORT_SYMBOL(bitmap_print_to_pagebuf);
* ranges. Consecutively set bits are shown as two hyphen-separated
* decimal numbers, the smallest and largest bit numbers set in
* the range.
+ * Optionally each range can be postfixed to denote that only parts of it
+ * should be set. The parts are the range of reminders modulo some value.
+ * i.e. range%mod=rem_range e.g. 0-1023%256=0-1 ==> 0,1,256,257,512,513,768,769
*
* Returns 0 on success, -errno on invalid input strings.
* Error values:
@@ -507,12 +510,14 @@ static int __bitmap_parselist(const char *buf, unsigned
int buflen,
int is_user, unsigned long *maskp,
int nmaskbits)
{
- unsigned a, b;
+ unsigned int a, b, old_a, old_b, mod_val, mod_a, mod_b;
int c, old_c, totaldigits, ndigits;
const char __user __force *ubuf = (const char __user __force *)buf;
int at_start, in_range;
totaldigits = c = 0;
+ old_a = old_b = 0;
+ mod_val = mod_a = mod_b = 0;
bitmap_zero(maskp, nmaskbits);
do {
at_start = 1;
@@ -547,6 +552,23 @@ static int __bitmap_parselist(const char *buf, unsigned
int buflen,
if ((totaldigits != ndigits) && isspace(old_c))
return -EINVAL;
+ if (c == '=') {
+ mod_val = a;
+ at_start = 1;
+ in_range = 0;
+ a = b = 0;
+ continue;
+ }
+
+ if (c == '%') {
+ old_a = a;
+ old_b = b;
+ at_start = 1;
+ in_range = 0;
+ a = b = 0;
+ continue;
+ }
+
if (c == '-') {
if (at_start || in_range)
return -EINVAL;
@@ -567,17 +589,31 @@ static int __bitmap_parselist(const char *buf, unsigned
int buflen,
}
if (ndigits == totaldigits)
continue;
+ if (mod_val) {
+ mod_a = a;
+ mod_b = b;
+ a = old_a;
+ b = old_b;
+ old_a = old_b = 0;
+ }
/* if no digit is after '-', it's wrong*/
if (at_start && in_range)
return -EINVAL;
- if (!(a <= b))
+ if (!(a <= b) || !(mod_a <= mod_b))
return -EINVAL;
- if (b >= nmaskbits)
+ if (b >= nmaskbits || (mod_val && (mod_b >= mod_val)))
return -ERANGE;
while (a <= b) {
- set_bit(a, maskp);
+ if (mod_val) {
+ unsigned int rem = a % mod_val;
+
+ if (rem >= mod_a && rem <= mod_b)
+ set_bit(a, maskp);
+ } else
+ set_bit(a, maskp);
a++;
}
+ mod_val = mod_a = mod_b = 0;
} while (buflen && c == ',');
return 0;
}