From: Pan Xinhui <xinhuix.pan@intel.com>
To: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Cc: Yury Norov <yury.norov@gmail.com>,
Andrew Morton <akpm@linux-foundation.org>,
Rasmus Villemoes <linux@rasmusvillemoes.dk>,
tj@kernel.org, peterz@infradead.org, sudeep.holla@arm.com,
mina86@mina86.com, "mnipxh@163.com" <mnipxh@163.com>,
Alexey Klimov <klimov.linux@gmail.com>
Subject: [PATCH] lib/bitmap.c: rewrite __bitmap_parse && __bitmap_parselist
Date: Tue, 30 Jun 2015 16:01:29 +0800 [thread overview]
Message-ID: <55924CD9.9020001@intel.com> (raw)
In-Reply-To: <55934441.9010304@intel.com>
add __bitmap_parse_common to match any contents and return expected result.
as __bitmap_parse_common need NULL-terminated string, we alloc a new buf.
this patch also fix some parse issues in __bitmap_parselist.
now it can handle grouping errors with input like " ", ",", etc.
Signed-off-by: xinhuix.pan <xinhuix.pan@intel.com>
---
lib/bitmap.c | 232 ++++++++++++++++++++++++++++++++---------------------------
1 file changed, 128 insertions(+), 104 deletions(-)
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 64c0926..bc53c4f 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -16,6 +16,8 @@
#include <asm/page.h>
#include <asm/uaccess.h>
+#include <linux/parser.h>
+#include <linux/slab.h>
/*
* bitmaps provide an array of bits, implemented using an an
* array of unsigned longs. The number of valid bits in a
@@ -331,6 +333,58 @@ again:
EXPORT_SYMBOL(bitmap_find_next_zero_area_off);
/*
+ * __bitmap_parse_common - parse expected number from buf
+ * Return 0 on success.
+ * there two patterns.
+ * if buf's contents did not match any of them, reutrn equivalent error.
+ * Notice buf's contents may be changed.
+ */
+static int __bitmap_parse_common(char *buf, unsigned int buflen,
+ unsigned long *a, unsigned long *b)
+{
+ int ret;
+ int token;
+ const match_table_t table = {
+ {
+ .token = 1,
+ .pattern = "%u",
+ },
+ {
+ .token = 2,
+ .pattern = "%u-%u",
+ },
+ {
+ .token = 0,
+ .pattern = NULL,
+ }
+ };
+ substring_t substr[MAX_OPT_ARGS];
+
+ if (!buflen || !a)
+ return -EINVAL;
+
+ token = match_token((char *)buf, table, substr);
+ switch (token) {
+ case 1:
+ *substr[0].to = '\0';
+ ret = kstrtoul(substr[0].from, 0, a);
+ if (b)
+ *b = *a;
+ break;
+ case 2:
+ *substr[0].to = '\0';
+ *substr[1].to = '\0';
+ ret = kstrtoul(substr[0].from, 0, a);
+ ret |= b ? kstrtoul(substr[1].from, 0, b) : -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/*
* Bitmap printing & parsing functions: first version by Nadia Yvette Chambers,
* second version by Paul Jackson, third by Joe Korty.
*/
@@ -359,57 +413,44 @@ int __bitmap_parse(const char *buf, unsigned int buflen,
int is_user, unsigned long *maskp,
int nmaskbits)
{
- int c, old_c, totaldigits, ndigits, nchunks, nbits;
+ int nchunks, nbits, ret;
+ unsigned long a;
u32 chunk;
const char __user __force *ubuf = (const char __user __force *)buf;
+ char *kbuf, *endp;
+
+ if (!buflen)
+ return -EINVAL;
+ kbuf = kmalloc(buflen + 1, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+ if (is_user) {
+ if (copy_from_user(kbuf, ubuf, buflen) != 0) {
+ kfree(kbuf);
+ return -EFAULT;
+ }
+ } else
+ memcpy(kbuf, buf, buflen);
+ kbuf[buflen] = '\0';
+ buf = strim(kbuf);
bitmap_zero(maskp, nmaskbits);
- nchunks = nbits = totaldigits = c = 0;
+ nchunks = nbits = 0;
do {
- chunk = ndigits = 0;
-
- /* Get the next chunk of the bitmap */
- while (buflen) {
- old_c = c;
- if (is_user) {
- if (__get_user(c, ubuf++))
- return -EFAULT;
- }
- else
- c = *buf++;
- buflen--;
- if (isspace(c))
- continue;
-
- /*
- * If the last character was a space and the current
- * character isn't '\0', we've got embedded whitespace.
- * This is a no-no, so throw an error.
- */
- if (totaldigits && c && isspace(old_c))
- return -EINVAL;
-
- /* A '\0' or a ',' signal the end of the chunk */
- if (c == '\0' || c == ',')
- break;
-
- if (!isxdigit(c))
- return -EINVAL;
-
- /*
- * Make sure there are at least 4 free bits in 'chunk'.
- * If not, this hexdigit will overflow 'chunk', so
- * throw an error.
- */
- if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1))
- return -EOVERFLOW;
-
- chunk = (chunk << 4) | hex_to_bin(c);
- ndigits++; totaldigits++;
+ endp = strchr(buf, ',');
+ if (endp)
+ *endp = '\0';
+ ret = __bitmap_parse_common((char *)buf, strlen(buf), &a, NULL);
+ if (ret)
+ break;
+ buf = endp + 1;
+
+ if (unlikely(a > U32_MAX)) {
+ ret = -ERANGE;
+ break;
}
- if (ndigits == 0)
- return -EINVAL;
+ chunk = (u32)a;
if (nchunks == 0 && chunk == 0)
continue;
@@ -417,11 +458,13 @@ int __bitmap_parse(const char *buf, unsigned int buflen,
*maskp |= chunk;
nchunks++;
nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;
- if (nbits > nmaskbits)
- return -EOVERFLOW;
- } while (buflen && c == ',');
-
- return 0;
+ if (nbits > nmaskbits) {
+ ret = -EOVERFLOW;
+ break;
+ }
+ } while (endp);
+ kfree(kbuf);
+ return ret;
}
EXPORT_SYMBOL(__bitmap_parse);
@@ -503,70 +546,51 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen,
int is_user, unsigned long *maskp,
int nmaskbits)
{
- unsigned a, b;
- int c, old_c, totaldigits;
+ unsigned long a, b;
+ int ret = 0;
const char __user __force *ubuf = (const char __user __force *)buf;
- int exp_digit, in_range;
+ char *kbuf, *endp;
+
+ if (!buflen)
+ return -EINVAL;
+ kbuf = kmalloc(buflen + 1, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+ if (is_user) {
+ if (copy_from_user(kbuf, ubuf, buflen) != 0) {
+ kfree(kbuf);
+ return -EFAULT;
+ }
+ } else
+ memcpy(kbuf, buf, buflen);
+ kbuf[buflen] = '\0';
+ buf = strim(kbuf);
- totaldigits = c = 0;
bitmap_zero(maskp, nmaskbits);
do {
- exp_digit = 1;
- in_range = 0;
- a = b = 0;
-
- /* Get the next cpu# or a range of cpu#'s */
- while (buflen) {
- old_c = c;
- if (is_user) {
- if (__get_user(c, ubuf++))
- return -EFAULT;
- } else
- c = *buf++;
- buflen--;
- if (isspace(c))
- continue;
-
- /*
- * If the last character was a space and the current
- * character isn't '\0', we've got embedded whitespace.
- * This is a no-no, so throw an error.
- */
- if (totaldigits && c && isspace(old_c))
- return -EINVAL;
-
- /* A '\0' or a ',' signal the end of a cpu# or range */
- if (c == '\0' || c == ',')
- break;
-
- if (c == '-') {
- if (exp_digit || in_range)
- return -EINVAL;
- b = 0;
- in_range = 1;
- exp_digit = 1;
- continue;
- }
-
- if (!isdigit(c))
- return -EINVAL;
-
- b = b * 10 + (c - '0');
- if (!in_range)
- a = b;
- exp_digit = 0;
- totaldigits++;
+ endp = strchr(buf, ',');
+ if (endp)
+ *endp = '\0';
+ ret = __bitmap_parse_common((char *)buf, strlen(buf), &a, &b);
+ if (ret)
+ break;
+ buf = endp + 1;
+
+ if (!(a <= b)) {
+ ret = -EINVAL;
+ break;
+ }
+ if (b >= nmaskbits) {
+ ret = -ERANGE;
+ break;
}
- if (!(a <= b))
- return -EINVAL;
- if (b >= nmaskbits)
- return -ERANGE;
while (a <= b) {
set_bit(a, maskp);
a++;
}
- } while (buflen && c == ',');
- return 0;
+ } while (endp);
+ kfree(kbuf);
+ return ret;
}
int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
--
1.9.1
next prev parent reply other threads:[~2015-06-30 8:04 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-06-30 7:42 [PATCH] lib/bitmap.c: return -EINVAL for grouping errors in __bitmap_parselist Pan Xinhui
2015-06-29 13:39 ` Yury Norov
2015-07-01 1:37 ` Pan Xinhui
2015-06-30 8:01 ` Pan Xinhui [this message]
2015-06-30 8:31 ` [PATCH V2] lib/bitmap.c: rewrite __bitmap_parse && __bitmap_parselist Pan Xinhui
2015-06-30 10:02 ` [PATCH V3] " Pan Xinhui
2015-07-01 3:17 ` Pan Xinhui
2015-07-01 9:16 ` Yury
2015-07-01 11:08 ` Pan Xinhui
2015-06-30 8:32 ` [PATCH] lib/bitmap.c: return -EINVAL for grouping errors in __bitmap_parselist Yury Norov
2015-06-30 8:37 ` Pan Xinhui
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55924CD9.9020001@intel.com \
--to=xinhuix.pan@intel.com \
--cc=akpm@linux-foundation.org \
--cc=klimov.linux@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@rasmusvillemoes.dk \
--cc=mina86@mina86.com \
--cc=mnipxh@163.com \
--cc=peterz@infradead.org \
--cc=sudeep.holla@arm.com \
--cc=tj@kernel.org \
--cc=yury.norov@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.