⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bitmap.c

📁 Lib files of linux kernel
💻 C
📖 第 1 页 / 共 3 页
字号:
 * Commas group hex digits into chunks.  Each chunk defines exactly 32 * bits of the resultant bitmask.  No chunk may specify a value larger * than 32 bits (%-EOVERFLOW), and if a chunk specifies a smaller value * then leading 0-bits are prepended.  %-EINVAL is returned for illegal * characters and for grouping errors such as "1,,5", ",44", "," and "". * Leading and trailing whitespace accepted, but not embedded whitespace. */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;	u32 chunk;	const char __user *ubuf = buf;	bitmap_zero(maskp, nmaskbits);	nchunks = nbits = totaldigits = c = 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) | unhex(c);			ndigits++; totaldigits++;		}		if (ndigits == 0)			return -EINVAL;		if (nchunks == 0 && chunk == 0)			continue;		__bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits);		*maskp |= chunk;		nchunks++;		nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;		if (nbits > nmaskbits)			return -EOVERFLOW;	} while (buflen && c == ',');	return 0;}EXPORT_SYMBOL(__bitmap_parse);/** * bitmap_parse_user() * * @ubuf: pointer to user buffer containing string. * @ulen: buffer size in bytes.  If string is smaller than this *    then it must be terminated with a \0. * @maskp: pointer to bitmap array that will contain result. * @nmaskbits: size of bitmap, in bits. * * Wrapper for __bitmap_parse(), providing it with user buffer. * * We cannot have this as an inline function in bitmap.h because it needs * linux/uaccess.h to get the access_ok() declaration and this causes * cyclic dependencies. */int bitmap_parse_user(const char __user *ubuf,			unsigned int ulen, unsigned long *maskp,			int nmaskbits){	if (!access_ok(VERIFY_READ, ubuf, ulen))		return -EFAULT;	return __bitmap_parse((const char *)ubuf, ulen, 1, maskp, nmaskbits);}EXPORT_SYMBOL(bitmap_parse_user);/* * bscnl_emit(buf, buflen, rbot, rtop, bp) * * Helper routine for bitmap_scnlistprintf().  Write decimal number * or range to buf, suppressing output past buf+buflen, with optional * comma-prefix.  Return len of what would be written to buf, if it * all fit. */static inline int bscnl_emit(char *buf, int buflen, int rbot, int rtop, int len){	if (len > 0)		len += scnprintf(buf + len, buflen - len, ",");	if (rbot == rtop)		len += scnprintf(buf + len, buflen - len, "%d", rbot);	else		len += scnprintf(buf + len, buflen - len, "%d-%d", rbot, rtop);	return len;}/** * bitmap_scnlistprintf - convert bitmap to list format ASCII string * @buf: byte buffer into which string is placed * @buflen: reserved size of @buf, in bytes * @maskp: pointer to bitmap to convert * @nmaskbits: size of bitmap, in bits * * Output 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.  Output format is compatible with the format * accepted as input by bitmap_parselist(). * * The return value is the number of characters which would be * generated for the given input, excluding the trailing '\0', as * per ISO C99. */int bitmap_scnlistprintf(char *buf, unsigned int buflen,	const unsigned long *maskp, int nmaskbits){	int len = 0;	/* current bit is 'cur', most recently seen range is [rbot, rtop] */	int cur, rbot, rtop;	if (buflen == 0)		return 0;	buf[0] = 0;	rbot = cur = find_first_bit(maskp, nmaskbits);	while (cur < nmaskbits) {		rtop = cur;		cur = find_next_bit(maskp, nmaskbits, cur+1);		if (cur >= nmaskbits || cur > rtop + 1) {			len = bscnl_emit(buf, buflen, rbot, rtop, len);			rbot = cur;		}	}	return len;}EXPORT_SYMBOL(bitmap_scnlistprintf);/** * bitmap_parselist - convert list format ASCII string to bitmap * @bp: read nul-terminated user string from this buffer * @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 *bp, unsigned long *maskp, int nmaskbits){	unsigned a, b;	bitmap_zero(maskp, nmaskbits);	do {		if (!isdigit(*bp))			return -EINVAL;		b = a = simple_strtoul(bp, (char **)&bp, BASEDEC);		if (*bp == '-') {			bp++;			if (!isdigit(*bp))				return -EINVAL;			b = simple_strtoul(bp, (char **)&bp, BASEDEC);		}		if (!(a <= b))			return -EINVAL;		if (b >= nmaskbits)			return -ERANGE;		while (a <= b) {			set_bit(a, maskp);			a++;		}		if (*bp == ',')			bp++;	} while (*bp != '\0' && *bp != '\n');	return 0;}EXPORT_SYMBOL(bitmap_parselist);/** * bitmap_pos_to_ord(buf, pos, bits) *	@buf: pointer to a bitmap *	@pos: a bit position in @buf (0 <= @pos < @bits) *	@bits: number of valid bit positions in @buf * * Map the bit at position @pos in @buf (of length @bits) to the * ordinal of which set bit it is.  If it is not set or if @pos * is not a valid bit position, map to -1. * * If for example, just bits 4 through 7 are set in @buf, then @pos * values 4 through 7 will get mapped to 0 through 3, respectively, * and other @pos values will get mapped to 0.  When @pos value 7 * gets mapped to (returns) @ord value 3 in this example, that means * that bit 7 is the 3rd (starting with 0th) set bit in @buf. * * The bit positions 0 through @bits are valid positions in @buf. */static int bitmap_pos_to_ord(const unsigned long *buf, int pos, int bits){	int i, ord;	if (pos < 0 || pos >= bits || !test_bit(pos, buf))		return -1;	i = find_first_bit(buf, bits);	ord = 0;	while (i < pos) {		i = find_next_bit(buf, bits, i + 1);	     	ord++;	}	BUG_ON(i != pos);	return ord;}/** * bitmap_ord_to_pos(buf, ord, bits) *	@buf: pointer to bitmap *	@ord: ordinal bit position (n-th set bit, n >= 0) *	@bits: number of valid bit positions in @buf * * Map the ordinal offset of bit @ord in @buf to its position in @buf. * Value of @ord should be in range 0 <= @ord < weight(buf), else * results are undefined. * * If for example, just bits 4 through 7 are set in @buf, then @ord * values 0 through 3 will get mapped to 4 through 7, respectively, * and all other @ord values return undefined values.  When @ord value 3 * gets mapped to (returns) @pos value 7 in this example, that means * that the 3rd set bit (starting with 0th) is at position 7 in @buf. * * The bit positions 0 through @bits are valid positions in @buf. */static int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits){	int pos = 0;	if (ord >= 0 && ord < bits) {		int i;		for (i = find_first_bit(buf, bits);		     i < bits && ord > 0;		     i = find_next_bit(buf, bits, i + 1))	     		ord--;		if (i < bits && ord == 0)			pos = i;	}	return pos;}/** * bitmap_remap - Apply map defined by a pair of bitmaps to another bitmap *	@dst: remapped result *	@src: subset to be remapped *	@old: defines domain of map *	@new: defines range of map *	@bits: number of bits in each of these bitmaps * * Let @old and @new define a mapping of bit positions, such that * whatever position is held by the n-th set bit in @old is mapped * to the n-th set bit in @new.  In the more general case, allowing * for the possibility that the weight 'w' of @new is less than the * weight of @old, map the position of the n-th set bit in @old to * the position of the m-th set bit in @new, where m == n % w. * * If either of the @old and @new bitmaps are empty, or if @src and * @dst point to the same location, then this routine copies @src * to @dst. * * The positions of unset bits in @old are mapped to themselves * (the identify map). * * Apply the above specified mapping to @src, placing the result in * @dst, clearing any bits previously set in @dst. * * For example, lets say that @old has bits 4 through 7 set, and * @new has bits 12 through 15 set.  This defines the mapping of bit * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other * bit positions unchanged.  So if say @src comes into this routine * with bits 1, 5 and 7 set, then @dst should leave with bits 1, * 13 and 15 set. */void bitmap_remap(unsigned long *dst, const unsigned long *src,		const unsigned long *old, const unsigned long *new,		int bits){	int oldbit, w;	if (dst == src)		/* following doesn't handle inplace remaps */		return;	bitmap_zero(dst, bits);	w = bitmap_weight(new, bits);	for (oldbit = find_first_bit(src, bits);	     oldbit < bits;	     oldbit = find_next_bit(src, bits, oldbit + 1)) {	     	int n = bitmap_pos_to_ord(old, oldbit, bits);		if (n < 0 || w == 0)			set_bit(oldbit, dst);	/* identity map */		else			set_bit(bitmap_ord_to_pos(new, n % w, bits), dst);	}}EXPORT_SYMBOL(bitmap_remap);/**

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -