ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / lib / bitmap.c
1 /*
2  * lib/bitmap.c
3  * Helper functions for bitmap.h.
4  *
5  * This source code is licensed under the GNU General Public License,
6  * Version 2.  See the file COPYING for more details.
7  */
8 #include <linux/module.h>
9 #include <linux/ctype.h>
10 #include <linux/errno.h>
11 #include <linux/bitmap.h>
12 #include <asm/bitops.h>
13 #include <asm/uaccess.h>
14
15 int bitmap_empty(const unsigned long *bitmap, int bits)
16 {
17         int k, lim = bits/BITS_PER_LONG;
18         for (k = 0; k < lim; ++k)
19                 if (bitmap[k])
20                         return 0;
21
22         if (bits % BITS_PER_LONG)
23                 if (bitmap[k] & ((1UL << (bits % BITS_PER_LONG)) - 1))
24                         return 0;
25
26         return 1;
27 }
28 EXPORT_SYMBOL(bitmap_empty);
29
30 int bitmap_full(const unsigned long *bitmap, int bits)
31 {
32         int k, lim = bits/BITS_PER_LONG;
33         for (k = 0; k < lim; ++k)
34                 if (~bitmap[k])
35                         return 0;
36
37         if (bits % BITS_PER_LONG)
38                 if (~bitmap[k] & ((1UL << (bits % BITS_PER_LONG)) - 1))
39                         return 0;
40
41         return 1;
42 }
43 EXPORT_SYMBOL(bitmap_full);
44
45 int bitmap_equal(const unsigned long *bitmap1,
46                 unsigned long *bitmap2, int bits)
47 {
48         int k, lim = bits/BITS_PER_LONG;
49         for (k = 0; k < lim; ++k)
50                 if (bitmap1[k] != bitmap2[k])
51                         return 0;
52
53         if (bits % BITS_PER_LONG)
54                 if ((bitmap1[k] ^ bitmap2[k]) &
55                                 ((1UL << (bits % BITS_PER_LONG)) - 1))
56                         return 0;
57
58         return 1;
59 }
60 EXPORT_SYMBOL(bitmap_equal);
61
62 void bitmap_complement(unsigned long *bitmap, int bits)
63 {
64         int k;
65         int nr = BITS_TO_LONGS(bits);
66
67         for (k = 0; k < nr; ++k)
68                 bitmap[k] = ~bitmap[k];
69 }
70 EXPORT_SYMBOL(bitmap_complement);
71
72 /*
73  * bitmap_shift_right - logical right shift of the bits in a bitmap
74  *   @dst - destination bitmap
75  *   @src - source bitmap
76  *   @nbits - shift by this many bits
77  *   @bits - bitmap size, in bits
78  *
79  * Shifting right (dividing) means moving bits in the MS -> LS bit
80  * direction.  Zeros are fed into the vacated MS positions and the
81  * LS bits shifted off the bottom are lost.
82  */
83 void bitmap_shift_right(unsigned long *dst,
84                         const unsigned long *src, int shift, int bits)
85 {
86         int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
87         int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
88         unsigned long mask = (1UL << left) - 1;
89         for (k = 0; off + k < lim; ++k) {
90                 unsigned long upper, lower;
91
92                 /*
93                  * If shift is not word aligned, take lower rem bits of
94                  * word above and make them the top rem bits of result.
95                  */
96                 if (!rem || off + k + 1 >= lim)
97                         upper = 0;
98                 else {
99                         upper = src[off + k + 1];
100                         if (off + k + 1 == lim - 1 && left)
101                                 upper &= mask;
102                 }
103                 lower = src[off + k];
104                 if (left && off + k == lim - 1)
105                         lower &= mask;
106                 dst[k] = upper << (BITS_PER_LONG - rem) | lower >> rem;
107                 if (left && k == lim - 1)
108                         dst[k] &= mask;
109         }
110         if (off)
111                 memset(&dst[lim - off], 0, off*sizeof(unsigned long));
112 }
113 EXPORT_SYMBOL(bitmap_shift_right);
114
115 /*
116  * bitmap_shift_left - logical left shift of the bits in a bitmap
117  *   @dst - destination bitmap
118  *   @src - source bitmap
119  *   @nbits - shift by this many bits
120  *   @bits - bitmap size, in bits
121  *
122  * Shifting left (multiplying) means moving bits in the LS -> MS
123  * direction.  Zeros are fed into the vacated LS bit positions
124  * and those MS bits shifted off the top are lost.
125  */
126 void bitmap_shift_left(unsigned long *dst,
127                         const unsigned long *src, int shift, int bits)
128 {
129         int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
130         int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG;
131         for (k = lim - off - 1; k >= 0; --k) {
132                 unsigned long upper, lower;
133
134                 /*
135                  * If shift is not word aligned, take upper rem bits of
136                  * word below and make them the bottom rem bits of result.
137                  */
138                 if (rem && k > 0)
139                         lower = src[k - 1];
140                 else
141                         lower = 0;
142                 upper = src[k];
143                 if (left && k == lim - 1)
144                         upper &= (1UL << left) - 1;
145                 dst[k + off] = lower  >> (BITS_PER_LONG - rem) | upper << rem;
146                 if (left && k + off == lim - 1)
147                         dst[k + off] &= (1UL << left) - 1;
148         }
149         if (off)
150                 memset(dst, 0, off*sizeof(unsigned long));
151 }
152 EXPORT_SYMBOL(bitmap_shift_left);
153
154 void bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
155                                 const unsigned long *bitmap2, int bits)
156 {
157         int k;
158         int nr = BITS_TO_LONGS(bits);
159
160         for (k = 0; k < nr; k++)
161                 dst[k] = bitmap1[k] & bitmap2[k];
162 }
163 EXPORT_SYMBOL(bitmap_and);
164
165 void bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
166                                 const unsigned long *bitmap2, int bits)
167 {
168         int k;
169         int nr = BITS_TO_LONGS(bits);
170
171         for (k = 0; k < nr; k++)
172                 dst[k] = bitmap1[k] | bitmap2[k];
173 }
174 EXPORT_SYMBOL(bitmap_or);
175
176 #if BITS_PER_LONG == 32
177 int bitmap_weight(const unsigned long *bitmap, int bits)
178 {
179         int k, w = 0, lim = bits/BITS_PER_LONG;
180
181         for (k = 0; k < lim; k++)
182                 w += hweight32(bitmap[k]);
183
184         if (bits % BITS_PER_LONG)
185                 w += hweight32(bitmap[k] &
186                                 ((1UL << (bits % BITS_PER_LONG)) - 1));
187
188         return w;
189 }
190 #else
191 int bitmap_weight(const unsigned long *bitmap, int bits)
192 {
193         int k, w = 0, lim = bits/BITS_PER_LONG;
194
195         for (k = 0; k < lim; k++)
196                 w += hweight64(bitmap[k]);
197
198         if (bits % BITS_PER_LONG)
199                 w += hweight64(bitmap[k] &
200                                 ((1UL << (bits % BITS_PER_LONG)) - 1));
201
202         return w;
203 }
204 #endif
205 EXPORT_SYMBOL(bitmap_weight);
206
207 /*
208  * Bitmap printing & parsing functions: first version by Bill Irwin,
209  * second version by Paul Jackson, third by Joe Korty.
210  */
211
212 #define CHUNKSZ                         32
213 #define nbits_to_hold_value(val)        fls(val)
214 #define roundup_power2(val,modulus)     (((val) + (modulus) - 1) & ~((modulus) - 1))
215 #define unhex(c)                        (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
216
217 /**
218  * bitmap_scnprintf - convert bitmap to an ASCII hex string.
219  * @buf: byte buffer into which string is placed
220  * @buflen: reserved size of @buf, in bytes
221  * @maskp: pointer to bitmap to convert
222  * @nmaskbits: size of bitmap, in bits
223  *
224  * Exactly @nmaskbits bits are displayed.  Hex digits are grouped into
225  * comma-separated sets of eight digits per set.
226  */
227 int bitmap_scnprintf(char *buf, unsigned int buflen,
228         const unsigned long *maskp, int nmaskbits)
229 {
230         int i, word, bit, len = 0;
231         unsigned long val;
232         const char *sep = "";
233         int chunksz;
234         u32 chunkmask;
235
236         chunksz = nmaskbits & (CHUNKSZ - 1);
237         if (chunksz == 0)
238                 chunksz = CHUNKSZ;
239
240         i = roundup_power2(nmaskbits, CHUNKSZ) - CHUNKSZ;
241         for (; i >= 0; i -= CHUNKSZ) {
242                 chunkmask = ((1ULL << chunksz) - 1);
243                 word = i / BITS_PER_LONG;
244                 bit = i % BITS_PER_LONG;
245                 val = (maskp[word] >> bit) & chunkmask;
246                 len += scnprintf(buf+len, buflen-len, "%s%0*lx", sep,
247                         (chunksz+3)/4, val);
248                 chunksz = CHUNKSZ;
249                 sep = ",";
250         }
251         return len;
252 }
253 EXPORT_SYMBOL(bitmap_scnprintf);
254
255 /**
256  * bitmap_parse - convert an ASCII hex string into a bitmap.
257  * @buf: pointer to buffer in user space containing string.
258  * @buflen: buffer size in bytes.  If string is smaller than this
259  *    then it must be terminated with a \0.
260  * @maskp: pointer to bitmap array that will contain result.
261  * @nmaskbits: size of bitmap, in bits.
262  *
263  * Commas group hex digits into chunks.  Each chunk defines exactly 32
264  * bits of the resultant bitmask.  No chunk may specify a value larger
265  * than 32 bits (-EOVERFLOW), and if a chunk specifies a smaller value
266  * then leading 0-bits are prepended.  -EINVAL is returned for illegal
267  * characters and for grouping errors such as "1,,5", ",44", "," and "".
268  * Leading and trailing whitespace accepted, but not embedded whitespace.
269  */
270 int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
271         unsigned long *maskp, int nmaskbits)
272 {
273         int c, old_c, totaldigits, ndigits, nchunks, nbits;
274         u32 chunk;
275
276         bitmap_zero(maskp, nmaskbits);
277
278         nchunks = nbits = totaldigits = c = 0;
279         do {
280                 chunk = ndigits = 0;
281
282                 /* Get the next chunk of the bitmap */
283                 while (ubuflen) {
284                         old_c = c;
285                         if (get_user(c, ubuf++))
286                                 return -EFAULT;
287                         ubuflen--;
288                         if (isspace(c))
289                                 continue;
290
291                         /*
292                          * If the last character was a space and the current
293                          * character isn't '\0', we've got embedded whitespace.
294                          * This is a no-no, so throw an error.
295                          */
296                         if (totaldigits && c && isspace(old_c))
297                                 return -EINVAL;
298
299                         /* A '\0' or a ',' signal the end of the chunk */
300                         if (c == '\0' || c == ',')
301                                 break;
302
303                         if (!isxdigit(c))
304                                 return -EINVAL;
305
306                         /*
307                          * Make sure there are at least 4 free bits in 'chunk'.
308                          * If not, this hexdigit will overflow 'chunk', so
309                          * throw an error.
310                          */
311                         if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1))
312                                 return -EOVERFLOW;
313
314                         chunk = (chunk << 4) | unhex(c);
315                         ndigits++; totaldigits++;
316                 }
317                 if (ndigits == 0)
318                         return -EINVAL;
319                 if (nchunks == 0 && chunk == 0)
320                         continue;
321
322                 bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits);
323                 *maskp |= chunk;
324                 nchunks++;
325                 nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;
326                 if (nbits > nmaskbits)
327                         return -EOVERFLOW;
328         } while (ubuflen && c == ',');
329
330         return 0;
331 }
332 EXPORT_SYMBOL(bitmap_parse);