Blame bitmap.c

Packit Service 2212bb
/*
Packit Service 2212bb
Packit Service 2212bb
This file is taken from the Linux kernel and minimally adapted for use in userspace
Packit Service 2212bb
Packit Service 2212bb
*/
Packit Service 2212bb
Packit Service 2212bb
/*
Packit Service 2212bb
 * lib/bitmap.c
Packit Service 2212bb
 * Helper functions for bitmap.h.
Packit Service 2212bb
 *
Packit Service 2212bb
 * This source code is licensed under the GNU General Public License,
Packit Service 2212bb
 * Version 2.  See the file COPYING for more details.
Packit Service 2212bb
 */
Packit Service 2212bb
#include "config.h"
Packit Service 2212bb
#include <unistd.h>
Packit Service 2212bb
#include <errno.h>
Packit Service 2212bb
#include <stdio.h>
Packit Service 2212bb
#include <stdlib.h>
Packit Service 2212bb
#include <ctype.h>
Packit Service 2212bb
#include "bitmap.h"
Packit Service 2212bb
#include "non-atomic.h"
Packit Service 2212bb
Packit Service 2212bb
/*
Packit Service 2212bb
 * bitmaps provide an array of bits, implemented using an an
Packit Service 2212bb
 * array of unsigned longs.  The number of valid bits in a
Packit Service 2212bb
 * given bitmap does _not_ need to be an exact multiple of
Packit Service 2212bb
 * BITS_PER_LONG.
Packit Service 2212bb
 *
Packit Service 2212bb
 * The possible unused bits in the last, partially used word
Packit Service 2212bb
 * of a bitmap are 'don't care'.  The implementation makes
Packit Service 2212bb
 * no particular effort to keep them zero.  It ensures that
Packit Service 2212bb
 * their value will not affect the results of any operation.
Packit Service 2212bb
 * The bitmap operations that return Boolean (bitmap_empty,
Packit Service 2212bb
 * for example) or scalar (bitmap_weight, for example) results
Packit Service 2212bb
 * carefully filter out these unused bits from impacting their
Packit Service 2212bb
 * results.
Packit Service 2212bb
 *
Packit Service 2212bb
 * These operations actually hold to a slightly stronger rule:
Packit Service 2212bb
 * if you don't input any bitmaps to these ops that have some
Packit Service 2212bb
 * unused bits set, then they won't output any set unused bits
Packit Service 2212bb
 * in output bitmaps.
Packit Service 2212bb
 *
Packit Service 2212bb
 * The byte ordering of bitmaps is more natural on little
Packit Service 2212bb
 * endian architectures.  See the big-endian headers
Packit Service 2212bb
 * include/asm-ppc64/bitops.h and include/asm-s390/bitops.h
Packit Service 2212bb
 * for the best explanations of this ordering.
Packit Service 2212bb
 */
Packit Service 2212bb
Packit Service 2212bb
int __bitmap_empty(const unsigned long *bitmap, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k, lim = bits/BITS_PER_LONG;
Packit Service 2212bb
	for (k = 0; k < lim; ++k)
Packit Service 2212bb
		if (bitmap[k])
Packit Service 2212bb
			return 0;
Packit Service 2212bb
Packit Service 2212bb
	if (bits % BITS_PER_LONG)
Packit Service 2212bb
		if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits))
Packit Service 2212bb
			return 0;
Packit Service 2212bb
Packit Service 2212bb
	return 1;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
int __bitmap_full(const unsigned long *bitmap, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k, lim = bits/BITS_PER_LONG;
Packit Service 2212bb
	for (k = 0; k < lim; ++k)
Packit Service 2212bb
		if (~bitmap[k])
Packit Service 2212bb
			return 0;
Packit Service 2212bb
Packit Service 2212bb
	if (bits % BITS_PER_LONG)
Packit Service 2212bb
		if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits))
Packit Service 2212bb
			return 0;
Packit Service 2212bb
Packit Service 2212bb
	return 1;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
int __bitmap_weight(const unsigned long *bitmap, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k, w = 0, lim = bits/BITS_PER_LONG;
Packit Service 2212bb
Packit Service 2212bb
	for (k = 0; k < lim; k++)
Packit Service 2212bb
		w += hweight_long(bitmap[k]);
Packit Service 2212bb
Packit Service 2212bb
	if (bits % BITS_PER_LONG)
Packit Service 2212bb
		w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
Packit Service 2212bb
Packit Service 2212bb
	return w;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
int __bitmap_equal(const unsigned long *bitmap1,
Packit Service 2212bb
		const unsigned long *bitmap2, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k, lim = bits/BITS_PER_LONG;
Packit Service 2212bb
	for (k = 0; k < lim; ++k)
Packit Service 2212bb
		if (bitmap1[k] != bitmap2[k])
Packit Service 2212bb
			return 0;
Packit Service 2212bb
Packit Service 2212bb
	if (bits % BITS_PER_LONG)
Packit Service 2212bb
		if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
Packit Service 2212bb
			return 0;
Packit Service 2212bb
Packit Service 2212bb
	return 1;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
void __bitmap_complement(unsigned long *dst, const unsigned long *src, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k, lim = bits/BITS_PER_LONG;
Packit Service 2212bb
	for (k = 0; k < lim; ++k)
Packit Service 2212bb
		dst[k] = ~src[k];
Packit Service 2212bb
Packit Service 2212bb
	if (bits % BITS_PER_LONG)
Packit Service 2212bb
		dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits);
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
/*
Packit Service 2212bb
 * __bitmap_shift_right - logical right shift of the bits in a bitmap
Packit Service 2212bb
 *   @dst - destination bitmap
Packit Service 2212bb
 *   @src - source bitmap
Packit Service 2212bb
 *   @nbits - shift by this many bits
Packit Service 2212bb
 *   @bits - bitmap size, in bits
Packit Service 2212bb
 *
Packit Service 2212bb
 * Shifting right (dividing) means moving bits in the MS -> LS bit
Packit Service 2212bb
 * direction.  Zeros are fed into the vacated MS positions and the
Packit Service 2212bb
 * LS bits shifted off the bottom are lost.
Packit Service 2212bb
 */
Packit Service 2212bb
void __bitmap_shift_right(unsigned long *dst,
Packit Service 2212bb
			const unsigned long *src, int shift, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
Packit Service 2212bb
	int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
Packit Service 2212bb
	unsigned long mask = (1UL << left) - 1;
Packit Service 2212bb
	for (k = 0; off + k < lim; ++k) {
Packit Service 2212bb
		unsigned long upper, lower;
Packit Service 2212bb
Packit Service 2212bb
		/*
Packit Service 2212bb
		 * If shift is not word aligned, take lower rem bits of
Packit Service 2212bb
		 * word above and make them the top rem bits of result.
Packit Service 2212bb
		 */
Packit Service 2212bb
		if (!rem || off + k + 1 >= lim)
Packit Service 2212bb
			upper = 0;
Packit Service 2212bb
		else {
Packit Service 2212bb
			upper = src[off + k + 1];
Packit Service 2212bb
			if (off + k + 1 == lim - 1 && left)
Packit Service 2212bb
				upper &= mask;
Packit Service 2212bb
		}
Packit Service 2212bb
		lower = src[off + k];
Packit Service 2212bb
		if (left && off + k == lim - 1)
Packit Service 2212bb
			lower &= mask;
Packit Service 2212bb
		dst[k] = upper << (BITS_PER_LONG - rem) | lower >> rem;
Packit Service 2212bb
		if (left && k == lim - 1)
Packit Service 2212bb
			dst[k] &= mask;
Packit Service 2212bb
	}
Packit Service 2212bb
	if (off)
Packit Service 2212bb
		memset(&dst[lim - off], 0, off*sizeof(unsigned long));
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
Packit Service 2212bb
/*
Packit Service 2212bb
 * __bitmap_shift_left - logical left shift of the bits in a bitmap
Packit Service 2212bb
 *   @dst - destination bitmap
Packit Service 2212bb
 *   @src - source bitmap
Packit Service 2212bb
 *   @nbits - shift by this many bits
Packit Service 2212bb
 *   @bits - bitmap size, in bits
Packit Service 2212bb
 *
Packit Service 2212bb
 * Shifting left (multiplying) means moving bits in the LS -> MS
Packit Service 2212bb
 * direction.  Zeros are fed into the vacated LS bit positions
Packit Service 2212bb
 * and those MS bits shifted off the top are lost.
Packit Service 2212bb
 */
Packit Service 2212bb
Packit Service 2212bb
void __bitmap_shift_left(unsigned long *dst,
Packit Service 2212bb
			const unsigned long *src, int shift, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
Packit Service 2212bb
	int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
Packit Service 2212bb
	for (k = lim - off - 1; k >= 0; --k) {
Packit Service 2212bb
		unsigned long upper, lower;
Packit Service 2212bb
Packit Service 2212bb
		/*
Packit Service 2212bb
		 * If shift is not word aligned, take upper rem bits of
Packit Service 2212bb
		 * word below and make them the bottom rem bits of result.
Packit Service 2212bb
		 */
Packit Service 2212bb
		if (rem && k > 0)
Packit Service 2212bb
			lower = src[k - 1];
Packit Service 2212bb
		else
Packit Service 2212bb
			lower = 0;
Packit Service 2212bb
		upper = src[k];
Packit Service 2212bb
		if (left && k == lim - 1)
Packit Service 2212bb
			upper &= (1UL << left) - 1;
Packit Service 2212bb
		dst[k + off] = lower  >> (BITS_PER_LONG - rem) | upper << rem;
Packit Service 2212bb
		if (left && k + off == lim - 1)
Packit Service 2212bb
			dst[k + off] &= (1UL << left) - 1;
Packit Service 2212bb
	}
Packit Service 2212bb
	if (off)
Packit Service 2212bb
		memset(dst, 0, off*sizeof(unsigned long));
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
Packit Service 2212bb
				const unsigned long *bitmap2, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k;
Packit Service 2212bb
	int nr = BITS_TO_LONGS(bits);
Packit Service 2212bb
Packit Service 2212bb
	for (k = 0; k < nr; k++)
Packit Service 2212bb
		dst[k] = bitmap1[k] & bitmap2[k];
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
Packit Service 2212bb
				const unsigned long *bitmap2, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k;
Packit Service 2212bb
	int nr = BITS_TO_LONGS(bits);
Packit Service 2212bb
Packit Service 2212bb
	for (k = 0; k < nr; k++)
Packit Service 2212bb
		dst[k] = bitmap1[k] | bitmap2[k];
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
Packit Service 2212bb
				const unsigned long *bitmap2, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k;
Packit Service 2212bb
	int nr = BITS_TO_LONGS(bits);
Packit Service 2212bb
Packit Service 2212bb
	for (k = 0; k < nr; k++)
Packit Service 2212bb
		dst[k] = bitmap1[k] ^ bitmap2[k];
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
Packit Service 2212bb
				const unsigned long *bitmap2, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k;
Packit Service 2212bb
	int nr = BITS_TO_LONGS(bits);
Packit Service 2212bb
Packit Service 2212bb
	for (k = 0; k < nr; k++)
Packit Service 2212bb
		dst[k] = bitmap1[k] & ~bitmap2[k];
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
int __bitmap_intersects(const unsigned long *bitmap1,
Packit Service 2212bb
				const unsigned long *bitmap2, int bits)
Packit Service 2212bb
{
Packit Service 2212bb
	int k, lim = bits/BITS_PER_LONG;
Packit Service 2212bb
	for (k = 0; k < lim; ++k)
Packit Service 2212bb
		if (bitmap1[k] & bitmap2[k])
Packit Service 2212bb
			return 1;
Packit Service 2212bb
Packit Service 2212bb
	if (bits % BITS_PER_LONG)
Packit Service 2212bb
		if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
Packit Service 2212bb
			return 1;
Packit Service 2212bb
	return 0;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
/*
Packit Service 2212bb
 * Bitmap printing & parsing functions: first version by Bill Irwin,
Packit Service 2212bb
 * second version by Paul Jackson, third by Joe Korty.
Packit Service 2212bb
 */
Packit Service 2212bb
Packit Service 2212bb
#define CHUNKSZ				32
Packit Service 2212bb
#define nbits_to_hold_value(val)	fls(val)
Packit Service 2212bb
#define unhex(c)			(isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
Packit Service 2212bb
#define BASEDEC 10		/* fancier cpuset lists input in decimal */
Packit Service 2212bb
Packit Service 2212bb
/**
Packit Service 2212bb
 * bitmap_scnprintf - convert bitmap to an ASCII hex string.
Packit Service 2212bb
 * @buf: byte buffer into which string is placed
Packit Service 2212bb
 * @buflen: reserved size of @buf, in bytes
Packit Service 2212bb
 * @maskp: pointer to bitmap to convert
Packit Service 2212bb
 * @nmaskbits: size of bitmap, in bits
Packit Service 2212bb
 *
Packit Service 2212bb
 * Exactly @nmaskbits bits are displayed.  Hex digits are grouped into
Packit Service 2212bb
 * comma-separated sets of eight digits per set.
Packit Service 2212bb
 */
Packit Service 2212bb
int bitmap_scnprintf(char *buf, unsigned int buflen,
Packit Service 2212bb
	const unsigned long *maskp, int nmaskbits)
Packit Service 2212bb
{
Packit Service 2212bb
	int i, word, bit, len = 0;
Packit Service 2212bb
	unsigned long val;
Packit Service 2212bb
	const char *sep = "";
Packit Service 2212bb
	int chunksz;
Packit Service 2212bb
	uint32_t chunkmask;
Packit Service 2212bb
	int first = 1;
Packit Service 2212bb
Packit Service 2212bb
	chunksz = nmaskbits & (CHUNKSZ - 1);
Packit Service 2212bb
	if (chunksz == 0)
Packit Service 2212bb
		chunksz = CHUNKSZ;
Packit Service 2212bb
Packit Service 2212bb
	i = ALIGN(nmaskbits, CHUNKSZ) - CHUNKSZ;
Packit Service 2212bb
	for (; i >= 0; i -= CHUNKSZ) {
Packit Service 2212bb
		chunkmask = ((1ULL << chunksz) - 1);
Packit Service 2212bb
		word = i / BITS_PER_LONG;
Packit Service 2212bb
		bit = i % BITS_PER_LONG;
Packit Service 2212bb
		val = (maskp[word] >> bit) & chunkmask;
Packit Service 2212bb
		if (val!=0 || !first || i==0)  {
Packit Service 2212bb
			len += snprintf(buf+len, buflen-len, "%s%0*lx", sep,
Packit Service 2212bb
				(chunksz+3)/4, val);
Packit Service 2212bb
			sep = ",";
Packit Service 2212bb
			first = 0;
Packit Service 2212bb
		}
Packit Service 2212bb
		chunksz = CHUNKSZ;
Packit Service 2212bb
	}
Packit Service 2212bb
	return len;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
/**
Packit Service 2212bb
 * __bitmap_parse - convert an ASCII hex string into a bitmap.
Packit Service 2212bb
 * @buf: pointer to buffer containing string.
Packit Service 2212bb
 * @buflen: buffer size in bytes.  If string is smaller than this
Packit Service 2212bb
 *    then it must be terminated with a \0.
Packit Service 2212bb
 * @is_user: location of buffer, 0 indicates kernel space
Packit Service 2212bb
 * @maskp: pointer to bitmap array that will contain result.
Packit Service 2212bb
 * @nmaskbits: size of bitmap, in bits.
Packit Service 2212bb
 *
Packit Service 2212bb
 * Commas group hex digits into chunks.  Each chunk defines exactly 32
Packit Service 2212bb
 * bits of the resultant bitmask.  No chunk may specify a value larger
Packit Service 2212bb
 * than 32 bits (%-EOVERFLOW), and if a chunk specifies a smaller value
Packit Service 2212bb
 * then leading 0-bits are prepended.  %-EINVAL is returned for illegal
Packit Service 2212bb
 * characters and for grouping errors such as "1,,5", ",44", "," and "".
Packit Service 2212bb
 * Leading and trailing whitespace accepted, but not embedded whitespace.
Packit Service 2212bb
 */
Packit Service 2212bb
int __bitmap_parse(const char *buf, unsigned int buflen,
Packit Service 2212bb
		int is_user __attribute((unused)), unsigned long *maskp,
Packit Service 2212bb
		int nmaskbits)
Packit Service 2212bb
{
Packit Service 2212bb
	int c, old_c, totaldigits, ndigits, nchunks, nbits;
Packit Service 2212bb
	uint32_t chunk;
Packit Service 2212bb
Packit Service 2212bb
	bitmap_zero(maskp, nmaskbits);
Packit Service 2212bb
Packit Service 2212bb
	nchunks = nbits = totaldigits = c = 0;
Packit Service 2212bb
	do {
Packit Service 2212bb
		chunk = ndigits = 0;
Packit Service 2212bb
Packit Service 2212bb
		/* Get the next chunk of the bitmap */
Packit Service 2212bb
		while (buflen) {
Packit Service 2212bb
			old_c = c;
Packit Service 2212bb
			c = *buf++;
Packit Service 2212bb
			buflen--;
Packit Service 2212bb
			if (isspace(c))
Packit Service 2212bb
				continue;
Packit Service 2212bb
Packit Service 2212bb
			/*
Packit Service 2212bb
			 * If the last character was a space and the current
Packit Service 2212bb
			 * character isn't '\0', we've got embedded whitespace.
Packit Service 2212bb
			 * This is a no-no, so throw an error.
Packit Service 2212bb
			 */
Packit Service 2212bb
			if (totaldigits && c && isspace(old_c))
Packit Service 2212bb
				return 0;
Packit Service 2212bb
Packit Service 2212bb
			/* A '\0' or a ',' signal the end of the chunk */
Packit Service 2212bb
			if (c == '\0' || c == ',')
Packit Service 2212bb
				break;
Packit Service 2212bb
Packit Service 2212bb
			if (!isxdigit(c))
Packit Service 2212bb
				return -EINVAL;
Packit Service 2212bb
Packit Service 2212bb
			/*
Packit Service 2212bb
			 * Make sure there are at least 4 free bits in 'chunk'.
Packit Service 2212bb
			 * If not, this hexdigit will overflow 'chunk', so
Packit Service 2212bb
			 * throw an error.
Packit Service 2212bb
			 */
Packit Service 2212bb
			if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1))
Packit Service 2212bb
				return -EOVERFLOW;
Packit Service 2212bb
Packit Service 2212bb
			chunk = (chunk << 4) | unhex(c);
Packit Service 2212bb
			ndigits++; totaldigits++;
Packit Service 2212bb
		}
Packit Service 2212bb
		if (ndigits == 0)
Packit Service 2212bb
			return -EINVAL;
Packit Service 2212bb
		if (nchunks == 0 && chunk == 0)
Packit Service 2212bb
			continue;
Packit Service 2212bb
Packit Service 2212bb
		__bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits);
Packit Service 2212bb
		*maskp |= chunk;
Packit Service 2212bb
		nchunks++;
Packit Service 2212bb
		nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;
Packit Service 2212bb
		if (nbits > nmaskbits)
Packit Service 2212bb
			return -EOVERFLOW;
Packit Service 2212bb
	} while (buflen && c == ',');
Packit Service 2212bb
Packit Service 2212bb
	return 0;
Packit Service 2212bb
}
Packit Service 2212bb
Packit Service 2212bb
/**
Packit Service 2212bb
 * __bitmap_parselist - convert list format ASCII string to bitmap
Packit Service 2212bb
 * @buf: read nul-terminated user string from this buffer
Packit Service 2212bb
 * @buflen: buffer size in bytes.  If string is smaller than this
Packit Service 2212bb
 *    then it must be terminated with a \0.
Packit Service 2212bb
 * @is_user: location of buffer, 0 indicates kernel space
Packit Service 2212bb
 * @maskp: write resulting mask here
Packit Service 2212bb
 * @nmaskbits: number of bits in mask to be written
Packit Service 2212bb
 *
Packit Service 2212bb
 * Input format is a comma-separated list of decimal numbers and
Packit Service 2212bb
 * ranges.  Consecutively set bits are shown as two hyphen-separated
Packit Service 2212bb
 * decimal numbers, the smallest and largest bit numbers set in
Packit Service 2212bb
 * the range.
Packit Service 2212bb
 *
Packit Service 2212bb
 * Returns 0 on success, -errno on invalid input strings.
Packit Service 2212bb
 * Error values:
Packit Service 2212bb
 *    %-EINVAL: second number in range smaller than first
Packit Service 2212bb
 *    %-EINVAL: invalid character in string
Packit Service 2212bb
 *    %-ERANGE: bit number specified too large for mask
Packit Service 2212bb
 */
Packit Service 2212bb
int __bitmap_parselist(const char *buf, unsigned int buflen,
Packit Service 2212bb
		int is_user __attribute((unused)), unsigned long *maskp,
Packit Service 2212bb
		int nmaskbits)
Packit Service 2212bb
{
Packit Service 2212bb
	int a, b, c, old_c, totaldigits;
Packit Service 2212bb
	int exp_digit, in_range;
Packit Service 2212bb
Packit Service 2212bb
	totaldigits = c = 0;
Packit Service 2212bb
	bitmap_zero(maskp, nmaskbits);
Packit Service 2212bb
	do {
Packit Service 2212bb
		exp_digit = 1;
Packit Service 2212bb
		in_range = 0;
Packit Service 2212bb
		a = b = 0;
Packit Service 2212bb
Packit Service 2212bb
		/* Get the next cpu# or a range of cpu#'s */
Packit Service 2212bb
		while (buflen) {
Packit Service 2212bb
			old_c = c;
Packit Service 2212bb
			c = *buf++;
Packit Service 2212bb
			buflen--;
Packit Service 2212bb
			if (isspace(c))
Packit Service 2212bb
				continue;
Packit Service 2212bb
Packit Service 2212bb
			/*
Packit Service 2212bb
			 * If the last character was a space and the current
Packit Service 2212bb
			 * character isn't '\0', we've got embedded whitespace.
Packit Service 2212bb
			 * This is a no-no, so throw an error.
Packit Service 2212bb
			 */
Packit Service 2212bb
			if (totaldigits && c && isspace(old_c))
Packit Service 2212bb
				return -EINVAL;
Packit Service 2212bb
Packit Service 2212bb
			/* A '\0' or a ',' signal the end of a cpu# or range */
Packit Service 2212bb
			if (c == '\0' || c == ',')
Packit Service 2212bb
				break;
Packit Service 2212bb
Packit Service 2212bb
			if (c == '-') {
Packit Service 2212bb
				if (exp_digit || in_range)
Packit Service 2212bb
					return -EINVAL;
Packit Service 2212bb
				b = 0;
Packit Service 2212bb
				in_range = 1;
Packit Service 2212bb
				exp_digit = 1;
Packit Service 2212bb
				continue;
Packit Service 2212bb
			}
Packit Service 2212bb
Packit Service 2212bb
			if (!isdigit(c))
Packit Service 2212bb
				return -EINVAL;
Packit Service 2212bb
Packit Service 2212bb
			b = b * 10 + (c - '0');
Packit Service 2212bb
			if (!in_range)
Packit Service 2212bb
				a = b;
Packit Service 2212bb
			exp_digit = 0;
Packit Service 2212bb
			totaldigits++;
Packit Service 2212bb
		}
Packit Service 2212bb
		if (!(a <= b))
Packit Service 2212bb
			return -EINVAL;
Packit Service 2212bb
		if (b >= nmaskbits)
Packit Service 2212bb
			return -ERANGE;
Packit Service 2212bb
		while (a <= b) {
Packit Service 2212bb
			set_bit(a, maskp);
Packit Service 2212bb
			a++;
Packit Service 2212bb
		}
Packit Service 2212bb
	} while (buflen && c == ',');
Packit Service 2212bb
	return 0;
Packit Service 2212bb
}