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