diff options
Diffstat (limited to 'lib/bitmap.c')
| -rw-r--r-- | lib/bitmap.c | 91 | 
1 files changed, 67 insertions, 24 deletions
diff --git a/lib/bitmap.c b/lib/bitmap.c index 75006c4036e9..74ceb02f45e3 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -3,17 +3,19 @@   * lib/bitmap.c   * Helper functions for bitmap.h.   */ -#include <linux/export.h> -#include <linux/thread_info.h> -#include <linux/ctype.h> -#include <linux/errno.h> +  #include <linux/bitmap.h>  #include <linux/bitops.h>  #include <linux/bug.h> +#include <linux/ctype.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/export.h>  #include <linux/kernel.h>  #include <linux/mm.h>  #include <linux/slab.h>  #include <linux/string.h> +#include <linux/thread_info.h>  #include <linux/uaccess.h>  #include <asm/page.h> @@ -487,30 +489,25 @@ EXPORT_SYMBOL(bitmap_print_to_pagebuf);  /*   * Region 9-38:4/10 describes the following bitmap structure: - * 0	   9  12    18			38 - * .........****......****......****...... - *	    ^  ^     ^			 ^ - *      start  off   group_len	       end + * 0	   9  12    18			38	     N + * .........****......****......****.................. + *	    ^  ^     ^			 ^	     ^ + *      start  off   group_len	       end	 nbits   */  struct region {  	unsigned int start;  	unsigned int off;  	unsigned int group_len;  	unsigned int end; +	unsigned int nbits;  }; -static int bitmap_set_region(const struct region *r, -				unsigned long *bitmap, int nbits) +static void bitmap_set_region(const struct region *r, unsigned long *bitmap)  {  	unsigned int start; -	if (r->end >= nbits) -		return -ERANGE; -  	for (start = r->start; start <= r->end; start += r->group_len)  		bitmap_set(bitmap, start, min(r->end - start + 1, r->off)); - -	return 0;  }  static int bitmap_check_region(const struct region *r) @@ -518,14 +515,23 @@ static int bitmap_check_region(const struct region *r)  	if (r->start > r->end || r->group_len == 0 || r->off > r->group_len)  		return -EINVAL; +	if (r->end >= r->nbits) +		return -ERANGE; +  	return 0;  } -static const char *bitmap_getnum(const char *str, unsigned int *num) +static const char *bitmap_getnum(const char *str, unsigned int *num, +				 unsigned int lastbit)  {  	unsigned long long n;  	unsigned int len; +	if (str[0] == 'N') { +		*num = lastbit; +		return str + 1; +	} +  	len = _parse_integer(str, 10, &n);  	if (!len)  		return ERR_PTR(-EINVAL); @@ -573,7 +579,9 @@ static const char *bitmap_find_region_reverse(const char *start, const char *end  static const char *bitmap_parse_region(const char *str, struct region *r)  { -	str = bitmap_getnum(str, &r->start); +	unsigned int lastbit = r->nbits - 1; + +	str = bitmap_getnum(str, &r->start, lastbit);  	if (IS_ERR(str))  		return str; @@ -583,7 +591,7 @@ static const char *bitmap_parse_region(const char *str, struct region *r)  	if (*str != '-')  		return ERR_PTR(-EINVAL); -	str = bitmap_getnum(str + 1, &r->end); +	str = bitmap_getnum(str + 1, &r->end, lastbit);  	if (IS_ERR(str))  		return str; @@ -593,14 +601,14 @@ static const char *bitmap_parse_region(const char *str, struct region *r)  	if (*str != ':')  		return ERR_PTR(-EINVAL); -	str = bitmap_getnum(str + 1, &r->off); +	str = bitmap_getnum(str + 1, &r->off, lastbit);  	if (IS_ERR(str))  		return str;  	if (*str != '/')  		return ERR_PTR(-EINVAL); -	return bitmap_getnum(str + 1, &r->group_len); +	return bitmap_getnum(str + 1, &r->group_len, lastbit);  no_end:  	r->end = r->start; @@ -627,6 +635,10 @@ no_pattern:   * From each group will be used only defined amount of bits.   * Syntax: range:used_size/group_size   * Example: 0-1023:2/256 ==> 0,1,256,257,512,513,768,769 + * The value 'N' can be used as a dynamically substituted token for the + * maximum allowed value; i.e (nmaskbits - 1).  Keep in mind that it is + * dynamic, so if system changes cause the bitmap width to change, such + * as more cores in a CPU list, then any ranges using N will also change.   *   * Returns: 0 on success, -errno on invalid input strings. Error values:   * @@ -640,7 +652,8 @@ int bitmap_parselist(const char *buf, unsigned long *maskp, int nmaskbits)  	struct region r;  	long ret; -	bitmap_zero(maskp, nmaskbits); +	r.nbits = nmaskbits; +	bitmap_zero(maskp, r.nbits);  	while (buf) {  		buf = bitmap_find_region(buf); @@ -655,9 +668,7 @@ int bitmap_parselist(const char *buf, unsigned long *maskp, int nmaskbits)  		if (ret)  			return ret; -		ret = bitmap_set_region(&r, maskp, nmaskbits); -		if (ret) -			return ret; +		bitmap_set_region(&r, maskp);  	}  	return 0; @@ -1262,6 +1273,38 @@ void bitmap_free(const unsigned long *bitmap)  }  EXPORT_SYMBOL(bitmap_free); +static void devm_bitmap_free(void *data) +{ +	unsigned long *bitmap = data; + +	bitmap_free(bitmap); +} + +unsigned long *devm_bitmap_alloc(struct device *dev, +				 unsigned int nbits, gfp_t flags) +{ +	unsigned long *bitmap; +	int ret; + +	bitmap = bitmap_alloc(nbits, flags); +	if (!bitmap) +		return NULL; + +	ret = devm_add_action_or_reset(dev, devm_bitmap_free, bitmap); +	if (ret) +		return NULL; + +	return bitmap; +} +EXPORT_SYMBOL_GPL(devm_bitmap_alloc); + +unsigned long *devm_bitmap_zalloc(struct device *dev, +				  unsigned int nbits, gfp_t flags) +{ +	return devm_bitmap_alloc(dev, nbits, flags | __GFP_ZERO); +} +EXPORT_SYMBOL_GPL(devm_bitmap_zalloc); +  #if BITS_PER_LONG == 64  /**   * bitmap_from_arr32 - copy the contents of u32 array of bits to bitmap  | 
