Whamcloud - gitweb
Many files:
[tools/e2fsprogs.git] / lib / ext2fs / bitops.h
1 /*
2  * bitops.h --- Bitmap frobbing code.  The byte swapping routines are
3  *      also included here.
4  * 
5  * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
6  *
7  * %Begin-Header%
8  * This file may be redistributed under the terms of the GNU Public
9  * License.
10  * %End-Header%
11  * 
12  * i386 bitops operations taken from <asm/bitops.h>, Copyright 1992,
13  * Linus Torvalds.
14  */
15
16
17 extern int ext2fs_set_bit(int nr,void * addr);
18 extern int ext2fs_clear_bit(int nr, void * addr);
19 extern int ext2fs_test_bit(int nr, const void * addr);
20 extern __u16 ext2fs_swab16(__u16 val);
21 extern __u32 ext2fs_swab32(__u32 val);
22
23 /*
24  * EXT2FS bitmap manipulation routines.
25  */
26
27 /* Support for sending warning messages from the inline subroutines */
28 extern const char *ext2fs_block_string;
29 extern const char *ext2fs_inode_string;
30 extern const char *ext2fs_mark_string;
31 extern const char *ext2fs_unmark_string;
32 extern const char *ext2fs_test_string;
33 extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
34                                const char *description);
35 extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
36                                 int code, unsigned long arg);
37
38 extern void ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
39 extern void ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
40                                        blk_t block);
41 extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
42
43 extern void ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ino_t inode);
44 extern void ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
45                                        ino_t inode);
46 extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ino_t inode);
47
48 extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
49                                           blk_t block);
50 extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
51                                             blk_t block);
52 extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
53                                          blk_t block);
54
55 extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
56                                           ino_t inode);
57 extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
58                                             ino_t inode);
59 extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
60                                          ino_t inode);
61 extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap);
62 extern ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
63 extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
64 extern ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
65
66 extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
67                                            blk_t block, int num);
68 extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
69                                              blk_t block, int num);
70 extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
71                                           blk_t block, int num);
72 extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
73                                                 blk_t block, int num);
74 extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
75                                                   blk_t block, int num);
76 extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
77                                                blk_t block, int num);
78
79 /*
80  * The inline routines themselves...
81  * 
82  * If NO_INLINE_FUNCS is defined, then we won't try to do inline
83  * functions at all; they will be included as normal functions in
84  * inline.c
85  */
86 #ifdef NO_INLINE_FUNCS
87 #if (defined(__i386__) || defined(__i486__) || defined(__i586__) || \
88      defined(__mc68000__) || defined(__sparc__))
89         /* This prevents bitops.c from trying to include the C */
90         /* function version of these functions */
91 #define _EXT2_HAVE_ASM_BITOPS_
92 #endif
93 #endif /* NO_INLINE_FUNCS */
94
95 #if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
96 #ifdef INCLUDE_INLINE_FUNCS
97 #define _INLINE_ extern
98 #else
99 #define _INLINE_ extern __inline__
100 #endif
101
102 #if (defined(__i386__) || defined(__i486__) || defined(__i586__))
103
104 #define _EXT2_HAVE_ASM_BITOPS_
105         
106 /*
107  * These are done by inline assembly for speed reasons.....
108  *
109  * All bitoperations return 0 if the bit was cleared before the
110  * operation and != 0 if it was not.  Bit 0 is the LSB of addr; bit 32
111  * is the LSB of (addr+1).
112  */
113
114 /*
115  * Some hacks to defeat gcc over-optimizations..
116  */
117 struct __dummy_h { unsigned long a[100]; };
118 #define EXT2FS_ADDR (*(struct __dummy_h *) addr)
119 #define EXT2FS_CONST_ADDR (*(const struct __dummy_h *) addr)    
120
121 _INLINE_ int ext2fs_set_bit(int nr, void * addr)
122 {
123         int oldbit;
124
125         __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
126                 :"=r" (oldbit),"=m" (EXT2FS_ADDR)
127                 :"r" (nr));
128         return oldbit;
129 }
130
131 _INLINE_ int ext2fs_clear_bit(int nr, void * addr)
132 {
133         int oldbit;
134
135         __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
136                 :"=r" (oldbit),"=m" (EXT2FS_ADDR)
137                 :"r" (nr));
138         return oldbit;
139 }
140
141 _INLINE_ int ext2fs_test_bit(int nr, const void * addr)
142 {
143         int oldbit;
144
145         __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
146                 :"=r" (oldbit)
147                 :"m" (EXT2FS_CONST_ADDR),"r" (nr));
148         return oldbit;
149 }
150
151 #undef EXT2FS_ADDR
152
153 #endif  /* i386 */
154
155 #ifdef __mc68000__
156
157 #define _EXT2_HAVE_ASM_BITOPS_
158
159 _INLINE_ int ext2fs_set_bit(int nr,void * addr)
160 {
161         char retval;
162
163         __asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
164              : "=d" (retval) : "d" (nr^7), "a" (addr));
165
166         return retval;
167 }
168
169 _INLINE_ int ext2fs_clear_bit(int nr, void * addr)
170 {
171         char retval;
172
173         __asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
174              : "=d" (retval) : "d" (nr^7), "a" (addr));
175
176         return retval;
177 }
178
179 _INLINE_ int ext2fs_test_bit(int nr, const void * addr)
180 {
181         char retval;
182
183         __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
184              : "=d" (retval) : "d" (nr^7), "a" (addr));
185
186         return retval;
187 }
188
189 #endif /* __mc68000__ */
190
191 #ifdef __sparc__
192
193 #define _EXT2_HAVE_ASM_BITOPS_
194
195 #ifndef EXT2_OLD_BITOPS
196
197 /*
198  * Do the bitops so that we are compatible with the standard i386
199  * convention.
200  */
201
202 _INLINE_ int ext2fs_set_bit(int nr,void * addr)
203 {
204 #if 1
205         int             mask;
206         unsigned char   *ADDR = (unsigned char *) addr;
207
208         ADDR += nr >> 3;
209         mask = 1 << (nr & 0x07);
210         __asm__ __volatile__("ldub      [%0], %%g6\n\t"
211                              "or        %%g6, %2, %%g5\n\t"
212                              "stb       %%g5, [%0]\n\t"
213                              "and       %%g6, %2, %0\n"
214         : "=&r" (ADDR)
215         : "0" (ADDR), "r" (mask)
216         : "g5", "g6");
217         return (int) ADDR;
218 #else
219         int             mask, retval;
220         unsigned char   *ADDR = (unsigned char *) addr;
221
222         ADDR += nr >> 3;
223         mask = 1 << (nr & 0x07);
224         retval = (mask & *ADDR) != 0;
225         *ADDR |= mask;
226         return retval;
227 #endif
228 }
229
230 _INLINE_ int ext2fs_clear_bit(int nr, void * addr)
231 {
232 #if 1
233         int             mask;
234         unsigned char   *ADDR = (unsigned char *) addr;
235
236         ADDR += nr >> 3;
237         mask = 1 << (nr & 0x07);
238         __asm__ __volatile__("ldub      [%0], %%g6\n\t"
239                              "andn      %%g6, %2, %%g5\n\t"
240                              "stb       %%g5, [%0]\n\t"
241                              "and       %%g6, %2, %0\n"
242         : "=&r" (ADDR)
243         : "0" (ADDR), "r" (mask)
244         : "g5", "g6");
245         return (int) ADDR;
246         
247 #else
248         int             mask, retval;
249         unsigned char   *ADDR = (unsigned char *) addr;
250
251         ADDR += nr >> 3;
252         mask = 1 << (nr & 0x07);
253         retval = (mask & *ADDR) != 0;
254         *ADDR &= ~mask;
255         return retval;
256 #endif
257 }
258
259 _INLINE_ int ext2fs_test_bit(int nr, const void * addr)
260 {
261         int                     mask;
262         const unsigned char     *ADDR = (const unsigned char *) addr;
263
264         ADDR += nr >> 3;
265         mask = 1 << (nr & 0x07);
266         return ((mask & *ADDR) != 0);
267 }
268
269 #else
270
271 /* Do things the old, unplesant way. */
272
273 _INLINE_ int ext2fs_set_bit(int nr, void *addr)
274 {
275         int             mask, retval;
276         unsigned long   *ADDR = (unsigned long *) addr;
277
278         ADDR += nr >> 5;
279         mask = 1 << (nr & 31);
280         retval = ((mask & *ADDR) != 0);
281         *ADDR |= mask;
282         return retval;
283 }
284
285 _INLINE_ int ext2fs_clear_bit(int nr, void *addr)
286 {
287         int             mask, retval;
288         unsigned long   *ADDR = (unsigned long *) addr;
289
290         ADDR += nr >> 5;
291         mask = 1 << (nr & 31);
292         retval = ((mask & *ADDR) != 0);
293         *ADDR &= ~mask;
294         return retval;
295 }
296
297 _INLINE_ int ext2fs_test_bit(int nr, const void *addr)
298 {
299         int                     mask;
300         const unsigned long     *ADDR = (const unsigned long *) addr;
301
302         ADDR += nr >> 5;
303         mask = 1 << (nr & 31);
304         return ((mask & *ADDR) != 0);
305 }
306 #endif
307
308 #endif /* __sparc__ */
309
310 #ifndef _EXT2_HAVE_ASM_SWAB
311
312 _INLINE_ __u16 ext2fs_swab16(__u16 val)
313 {
314         return (val >> 8) | (val << 8);
315 }
316
317 _INLINE_ __u32 ext2fs_swab32(__u32 val)
318 {
319         return ((val>>24) | ((val>>8)&0xFF00) |
320                 ((val<<8)&0xFF0000) | (val<<24));
321 }
322
323 #endif /* !_EXT2_HAVE_ASM_SWAB */
324
325 _INLINE_ void ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
326                                          __u32 bitno);
327 _INLINE_ void ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
328                                            blk_t bitno);
329 _INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
330                                         blk_t bitno);
331
332 _INLINE_ void ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
333                                          __u32 bitno)
334 {
335         if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
336                 ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
337                 return;
338         }
339         ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
340 }
341
342 _INLINE_ void ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
343                                            blk_t bitno)
344 {
345         if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
346                 ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
347                 return;
348         }
349         ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
350 }
351
352 _INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
353                                         blk_t bitno)
354 {
355         if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
356                 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
357                 return 0;
358         }
359         return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
360 }
361
362 _INLINE_ void ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
363                                        blk_t block)
364 {
365         ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block);
366 }
367
368 _INLINE_ void ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
369                                          blk_t block)
370 {
371         ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block);
372 }
373
374 _INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
375                                        blk_t block)
376 {
377         return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
378                                           block);
379 }
380
381 _INLINE_ void ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
382                                        ino_t inode)
383 {
384         ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode);
385 }
386
387 _INLINE_ void ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
388                                          ino_t inode)
389 {
390         ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode);
391 }
392
393 _INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
394                                        ino_t inode)
395 {
396         return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
397                                           inode);
398 }
399
400 _INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
401                                             blk_t block)
402 {
403 #ifdef EXT2FS_DEBUG_FAST_OPS
404         if ((block < bitmap->start) || (block > bitmap->end)) {
405                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
406                                    bitmap->description);
407                 return;
408         }
409 #endif  
410         ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
411 }
412
413 _INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
414                                               blk_t block)
415 {
416 #ifdef EXT2FS_DEBUG_FAST_OPS
417         if ((block < bitmap->start) || (block > bitmap->end)) {
418                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
419                                    block, bitmap->description);
420                 return;
421         }
422 #endif
423         ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
424 }
425
426 _INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
427                                             blk_t block)
428 {
429 #ifdef EXT2FS_DEBUG_FAST_OPS
430         if ((block < bitmap->start) || (block > bitmap->end)) {
431                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
432                                    block, bitmap->description);
433                 return 0;
434         }
435 #endif
436         return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
437 }
438
439 _INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
440                                             ino_t inode)
441 {
442 #ifdef EXT2FS_DEBUG_FAST_OPS
443         if ((inode < bitmap->start) || (inode > bitmap->end)) {
444                 ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
445                                    inode, bitmap->description);
446                 return;
447         }
448 #endif
449         ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
450 }
451
452 _INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
453                                               ino_t inode)
454 {
455 #ifdef EXT2FS_DEBUG_FAST_OPS
456         if ((inode < bitmap->start) || (inode > bitmap->end)) {
457                 ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
458                                    inode, bitmap->description);
459                 return;
460         }
461 #endif
462         ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
463 }
464
465 _INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
466                                            ino_t inode)
467 {
468 #ifdef EXT2FS_DEBUG_FAST_OPS
469         if ((inode < bitmap->start) || (inode > bitmap->end)) {
470                 ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
471                                    inode, bitmap->description);
472                 return 0;
473         }
474 #endif
475         return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
476 }
477
478 _INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
479 {
480         return bitmap->start;
481 }
482
483 _INLINE_ ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
484 {
485         return bitmap->start;
486 }
487
488 _INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
489 {
490         return bitmap->end;
491 }
492
493 _INLINE_ ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
494 {
495         return bitmap->end;
496 }
497
498 _INLINE_ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
499                                             blk_t block, int num)
500 {
501         int     i;
502
503         if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
504                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
505                                    block, bitmap->description);
506                 return 0;
507         }
508         for (i=0; i < num; i++) {
509                 if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
510                         return 0;
511         }
512         return 1;
513 }
514
515 _INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
516                                                  blk_t block, int num)
517 {
518         int     i;
519
520 #ifdef EXT2FS_DEBUG_FAST_OPS
521         if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
522                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
523                                    block, bitmap->description);
524                 return 0;
525         }
526 #endif
527         for (i=0; i < num; i++) {
528                 if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
529                         return 0;
530         }
531         return 1;
532 }
533
534 _INLINE_ void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
535                                              blk_t block, int num)
536 {
537         int     i;
538         
539         if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
540                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
541                                    bitmap->description);
542                 return;
543         }
544         for (i=0; i < num; i++)
545                 ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
546 }
547
548 _INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
549                                                   blk_t block, int num)
550 {
551         int     i;
552         
553 #ifdef EXT2FS_DEBUG_FAST_OPS
554         if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
555                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
556                                    bitmap->description);
557                 return;
558         }
559 #endif  
560         for (i=0; i < num; i++)
561                 ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
562 }
563
564 _INLINE_ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
565                                                blk_t block, int num)
566 {
567         int     i;
568         
569         if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
570                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
571                                    bitmap->description);
572                 return;
573         }
574         for (i=0; i < num; i++)
575                 ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
576 }
577
578 _INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
579                                                     blk_t block, int num)
580 {
581         int     i;
582         
583 #ifdef EXT2FS_DEBUG_FAST_OPS
584         if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
585                 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
586                                    bitmap->description);
587                 return;
588         }
589 #endif  
590         for (i=0; i < num; i++)
591                 ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
592 }
593
594 #undef _INLINE_
595 #endif
596