#ifndef _LINUX_DBITMAP_H
#define _LINUX_DBITMAP_H
#include <linux/bitmap.h>
#define NBITS_MIN BITS_PER_TYPE(unsigned long)
struct dbitmap {
unsigned int nbits;
unsigned long *map;
};
static inline int dbitmap_enabled(struct dbitmap *dmap)
{
return !!dmap->nbits;
}
static inline void dbitmap_free(struct dbitmap *dmap)
{
dmap->nbits = 0;
kfree(dmap->map);
dmap->map = NULL;
}
static inline unsigned int dbitmap_shrink_nbits(struct dbitmap *dmap)
{
unsigned int bit;
if (dmap->nbits <= NBITS_MIN)
return 0;
bit = find_last_bit(dmap->map, dmap->nbits);
if (bit < (dmap->nbits >> 2))
return dmap->nbits >> 1;
if (bit == dmap->nbits)
return NBITS_MIN;
return 0;
}
static inline void
dbitmap_replace(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
{
bitmap_copy(new, dmap->map, min(dmap->nbits, nbits));
kfree(dmap->map);
dmap->map = new;
dmap->nbits = nbits;
}
static inline void
dbitmap_shrink(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
{
if (!new)
return;
if (!dbitmap_enabled(dmap) || dbitmap_shrink_nbits(dmap) != nbits) {
kfree(new);
return;
}
dbitmap_replace(dmap, new, nbits);
}
static inline unsigned int dbitmap_grow_nbits(struct dbitmap *dmap)
{
return dmap->nbits << 1;
}
static inline void
dbitmap_grow(struct dbitmap *dmap, unsigned long *new, unsigned int nbits)
{
if (!dbitmap_enabled(dmap) || nbits <= dmap->nbits) {
kfree(new);
return;
}
if (!new) {
dbitmap_free(dmap);
return;
}
dbitmap_replace(dmap, new, nbits);
}
static inline int
dbitmap_acquire_next_zero_bit(struct dbitmap *dmap, unsigned long offset,
unsigned long *bit)
{
unsigned long n;
n = find_next_zero_bit(dmap->map, dmap->nbits, offset);
if (n == dmap->nbits)
return -ENOSPC;
*bit = n;
set_bit(n, dmap->map);
return 0;
}
static inline void
dbitmap_clear_bit(struct dbitmap *dmap, unsigned long bit)
{
clear_bit(bit, dmap->map);
}
static inline int dbitmap_init(struct dbitmap *dmap)
{
dmap->map = bitmap_zalloc(NBITS_MIN, GFP_KERNEL);
if (!dmap->map) {
dmap->nbits = 0;
return -ENOMEM;
}
dmap->nbits = NBITS_MIN;
return 0;
}
#endif