hi, Yury
        
On 2015年07月01日 17:16, Yury wrote:
>> Subject: lib/bitmap.c: rewrite __bitmap_parse && __bitmap_parselist
>     scripts/checkpatch.pl 
> lib_bitmap.c:-rewrite-__bitmap_parse-__bitmap_parselist.patch
>     total: 134 errors, 1 warnings, 284 lines checked
> 
>     NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch 
> or
>           scripts/cleanfile
> 
> Most of them are about DOS line endings, but it prevents me to apply your 
> patch:
>     patch -p1 < lib_bitmap.c:-rewrite-__bitmap_parse-__bitmap_parselist.patch
>     (Stripping trailing CRs from patch; use --binary to disable.)
>     patching file lib/bitmap.c
>     Hunk #1 FAILED at 16.
>     Hunk #2 FAILED at 331.
>     Hunk #3 FAILED at 359.
>     Hunk #4 FAILED at 417.
>     Hunk #5 FAILED at 503.
>     5 out of 5 hunks FAILED -- saving rejects to file lib/bitmap.c.rej

sorry for that I did not configure thunderbird correctly.
tab becomes spaces unexpectedly. :(

>>
>> add __bitmap_parse_common to match any contents and return expected reslut.
>>
>> as __bitmap_parse_common need NULL-terminated string, we alloc a new buf.
>>
>> this patch also fix an unexpected parse result issue in __bitmap_parselist.
>>
>> Signed-off-by: Pan Xinhui <xinhuix....@intel.com>
>> ---
>>   lib/bitmap.c | 238 
>> +++++++++++++++++++++++++++++++++--------------------------
>>   1 file changed, 134 insertions(+), 104 deletions(-)
>> ---
>> change log
>> v3:
>> __bitmap_parselist now allow some extra input, like ",2, 3,,,, 5-8", at 
>> least one digit inside.
>> input like " " ", " is still not allowed.
>>
>> V2:
>> __bitmap_parse_common need *base* to parse correct result
>>
>> V1:
>> add __bitmap_parse_common and rewrite __bitmap_parse && __bitmap_parselist
>> ---
>>
>> diff --git a/lib/bitmap.c b/lib/bitmap.c
>> index 64c0926..f2095e1d 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 base)
> 
> It looks weird, and I don't like in your version too much:
> Name is bad.
> There's nothing about bitmap. You just parsing a string for two patterns: %d, 
> and %d-%d.
> 
yes, this is a bad name.

> You do your work twice (at least): first you detect digits in match_token, 
> then - in kstrtoul.
> You allocate kbuf unconditionally, no matter you need it or not.
> You do more than one thing in __bitmap_parse_common (you search number and 
> region).
> You modify initial string.
> 
I will try to find a better way. thanks for pointing out the bad codes design.

> Let's consider a more straight interface:
> 
>     /*
>      * I don't know why this function is not written yet.
>      * Maybe it's something ideological...
>      */
>     void set_bits(unsigned long *bitmap, unsigned long start, unsigned long 
> len);
> 
>     /*
>      * Takes care of all user whitespaces and commas,
>      * Return endp, or error if parse fails, or null if string reached the 
> end.
>      */
>     char *parse_range(const char *buf, unsigned long *start, unsigned long 
> *len);
> 
> than pattern usage would be:
> 
>     while (str = parse_range(str, &start, &len)) {
>         if (IS_ERROR(str))
>             return ...;
>         if (start + len >= nbits)
>             return ...;
> 
>         set_bits(bitmap, start, len);
>     }
> 

agree!
a minor change.
int parse_range(const char *buf, char *endp, unsigned long *start, unsigned 
long *len)
seems better, I prefer ret value as error codes only.

thanks for your advices. :)
I will rewrite them.

thanks,
xinhui

>> +{
>> +    int ret;
>> +    int token;
>> +    const match_table_t table = {
>> +        {
>> +            .token = 1,
>> +            .pattern = "%x",
>> +        },
>> +        {
>> +            .token = 2,
>> +            .pattern = "%x-%x",
>> +        },
>> +        {
>> +            .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, base, a);
>> +        if (b)
>> +            *b = *a;
>> +        break;
>> +    case 2:
>> +        *substr[0].to = '\0';
>> +        *substr[1].to = '\0';
>> +        ret = kstrtoul(substr[0].from, base, a);
>> +        ret |= b ? kstrtoul(substr[1].from, base, 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,45 @@ 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, 16);
>> +        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 +459,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 +547,56 @@ 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 = -EINVAL;
>>       const char __user __force *ubuf = (const char __user __force *)buf;
>> -    int exp_digit, in_range;
>> +    char *kbuf, *endp, *ibuf;
>> +
>> +    if (!buflen)
>> +        return -EINVAL;
>> +    ibuf = 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';
>>
>> -    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(ibuf, ',');
>> +        if (endp)
>> +            *endp = '\0';
>> +        ibuf = strim(ibuf);
>> +        if (*ibuf == 0) {
>> +            ibuf = endp + 1;
>> +            continue;
>> +        }
>> +        ret = __bitmap_parse_common(ibuf, strlen(ibuf),
>> +                                &a, &b, 0);
>> +        if (ret)
>> +            break;
>> +        ibuf = 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
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to