Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
import __bitmap_parselist from Linux kernel
Import __bitmap_parselist from the Linux kernel, in order to parse
CPU ranges as used in eg. the kernel isolcpus= commandline argument.

This code appears to have been in the Linux kernel since the initial
git import in 2005, so I do not have attribution of which changeset(s)
introduced it into the kernel.

Signed-off-by: Rik van Riel <riel@redhat.com>
  • Loading branch information
Rik van Riel committed Mar 12, 2015
1 parent f498717 commit 976e741
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 2 deletions.
84 changes: 84 additions & 0 deletions bitmap.c
Expand Up @@ -377,3 +377,87 @@ int __bitmap_parse(const char *buf, unsigned int buflen,

return 0;
}

/**
* __bitmap_parselist - convert list format ASCII string to bitmap
* @buf: read nul-terminated user string from this buffer
* @buflen: buffer size in bytes. If string is smaller than this
* then it must be terminated with a \0.
* @is_user: location of buffer, 0 indicates kernel space
* @maskp: write resulting mask here
* @nmaskbits: number of bits in mask to be written
*
* Input format is a comma-separated list of decimal numbers and
* ranges. Consecutively set bits are shown as two hyphen-separated
* decimal numbers, the smallest and largest bit numbers set in
* the range.
*
* Returns 0 on success, -errno on invalid input strings.
* Error values:
* %-EINVAL: second number in range smaller than first
* %-EINVAL: invalid character in string
* %-ERANGE: bit number specified too large for mask
*/
int __bitmap_parselist(const char *buf, unsigned int buflen,
int is_user __attribute((unused)), unsigned long *maskp,
int nmaskbits)
{
int a, b, c, old_c, totaldigits;
int exp_digit, in_range;

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;
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++;
}
if (!(a <= b))
return -EINVAL;
if (b >= nmaskbits)
return -ERANGE;
while (a <= b) {
set_bit(a, maskp);
a++;
}
} while (buflen && c == ',');
return 0;
}
10 changes: 8 additions & 2 deletions bitmap.h
Expand Up @@ -185,8 +185,8 @@ extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user,
unsigned long *dst, int nbits);
extern int bitmap_scnlistprintf(char *buf, unsigned int len,
const unsigned long *src, int nbits);
extern int bitmap_parselist(const char *buf, unsigned long *maskp,
int nmaskbits);
extern int __bitmap_parselist(const char *buf, unsigned int buflen, int is_user,
unsigned long *dst, int nbits);
extern void bitmap_remap(unsigned long *dst, const unsigned long *src,
const unsigned long *old, const unsigned long *new, int bits);
extern int bitmap_bitremap(int oldbit,
Expand Down Expand Up @@ -351,6 +351,12 @@ static inline int bitmap_parse(const char *buf, unsigned int buflen,
return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits);
}

static inline int bitmap_parselist(const char *buf, unsigned int buflen,
unsigned long *maskp, int nmaskbits)
{
return __bitmap_parselist(buf, buflen, 0, maskp, nmaskbits);
}

#endif /* __ASSEMBLY__ */

#endif /* __LINUX_BITMAP_H */

0 comments on commit 976e741

Please sign in to comment.