bitops.h revision 31dbecd482405e0d3a67eb58e1a1c8cb9f2ad83e
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
17extern int ext2fs_set_bit(int nr,void * addr);
18extern int ext2fs_clear_bit(int nr, void * addr);
19extern int ext2fs_test_bit(int nr, const void * addr);
20extern __u16 ext2fs_swab16(__u16 val);
21extern __u32 ext2fs_swab32(__u32 val);
22
23/*
24 * EXT2FS bitmap manipulation routines.
25 */
26
27/* Support for sending warning messages from the inline subroutines */
28extern const char *ext2fs_block_string;
29extern const char *ext2fs_inode_string;
30extern const char *ext2fs_mark_string;
31extern const char *ext2fs_unmark_string;
32extern const char *ext2fs_test_string;
33extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
34			       const char *description);
35extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
36				int code, unsigned long arg);
37
38extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
39extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
40				       blk_t block);
41extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
42
43extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
44extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
45				       ext2_ino_t inode);
46extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
47
48extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
49					  blk_t block);
50extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
51					    blk_t block);
52extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
53					 blk_t block);
54
55extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
56					  ext2_ino_t inode);
57extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
58					    ext2_ino_t inode);
59extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
60					 ext2_ino_t inode);
61extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap);
62extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
63extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
64extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
65
66extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
67					   blk_t block, int num);
68extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
69					     blk_t block, int num);
70extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
71					  blk_t block, int num);
72extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
73						blk_t block, int num);
74extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
75						  blk_t block, int num);
76extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
77					       blk_t block, int num);
78extern 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 */
124struct __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_ int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
333					 __u32 bitno);
334_INLINE_ int 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_ int 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 0;
345	}
346	return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
347}
348
349_INLINE_ int 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 0;
355	}
356	return 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_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
370				       blk_t block)
371{
372	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
373				       bitmap,
374					  block);
375}
376
377_INLINE_ int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
378					 blk_t block)
379{
380	return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
381					    block);
382}
383
384_INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
385				       blk_t block)
386{
387	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
388					  block);
389}
390
391_INLINE_ int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
392				       ext2_ino_t inode)
393{
394	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
395					  inode);
396}
397
398_INLINE_ int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
399					 ext2_ino_t inode)
400{
401	return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
402				     inode);
403}
404
405_INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
406				       ext2_ino_t inode)
407{
408	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
409					  inode);
410}
411
412_INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
413					    blk_t block)
414{
415#ifdef EXT2FS_DEBUG_FAST_OPS
416	if ((block < bitmap->start) || (block > bitmap->end)) {
417		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
418				   bitmap->description);
419		return;
420	}
421#endif
422	ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
423}
424
425_INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
426					      blk_t block)
427{
428#ifdef EXT2FS_DEBUG_FAST_OPS
429	if ((block < bitmap->start) || (block > bitmap->end)) {
430		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
431				   block, bitmap->description);
432		return;
433	}
434#endif
435	ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
436}
437
438_INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
439					    blk_t block)
440{
441#ifdef EXT2FS_DEBUG_FAST_OPS
442	if ((block < bitmap->start) || (block > bitmap->end)) {
443		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
444				   block, bitmap->description);
445		return 0;
446	}
447#endif
448	return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
449}
450
451_INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
452					    ext2_ino_t inode)
453{
454#ifdef EXT2FS_DEBUG_FAST_OPS
455	if ((inode < bitmap->start) || (inode > bitmap->end)) {
456		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
457				   inode, bitmap->description);
458		return;
459	}
460#endif
461	ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
462}
463
464_INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
465					      ext2_ino_t inode)
466{
467#ifdef EXT2FS_DEBUG_FAST_OPS
468	if ((inode < bitmap->start) || (inode > bitmap->end)) {
469		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
470				   inode, bitmap->description);
471		return;
472	}
473#endif
474	ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
475}
476
477_INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
478					   ext2_ino_t inode)
479{
480#ifdef EXT2FS_DEBUG_FAST_OPS
481	if ((inode < bitmap->start) || (inode > bitmap->end)) {
482		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
483				   inode, bitmap->description);
484		return 0;
485	}
486#endif
487	return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
488}
489
490_INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
491{
492	return bitmap->start;
493}
494
495_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
496{
497	return bitmap->start;
498}
499
500_INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
501{
502	return bitmap->end;
503}
504
505_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
506{
507	return bitmap->end;
508}
509
510_INLINE_ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
511					    blk_t block, int num)
512{
513	int	i;
514
515	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
516		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
517				   block, bitmap->description);
518		return 0;
519	}
520	for (i=0; i < num; i++) {
521		if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
522			return 0;
523	}
524	return 1;
525}
526
527_INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
528						 blk_t block, int num)
529{
530	int	i;
531
532#ifdef EXT2FS_DEBUG_FAST_OPS
533	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
534		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
535				   block, bitmap->description);
536		return 0;
537	}
538#endif
539	for (i=0; i < num; i++) {
540		if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
541			return 0;
542	}
543	return 1;
544}
545
546_INLINE_ void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
547					     blk_t block, int num)
548{
549	int	i;
550
551	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
552		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
553				   bitmap->description);
554		return;
555	}
556	for (i=0; i < num; i++)
557		ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
558}
559
560_INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
561						  blk_t block, int num)
562{
563	int	i;
564
565#ifdef EXT2FS_DEBUG_FAST_OPS
566	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
567		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
568				   bitmap->description);
569		return;
570	}
571#endif
572	for (i=0; i < num; i++)
573		ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
574}
575
576_INLINE_ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
577					       blk_t block, int num)
578{
579	int	i;
580
581	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
582		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
583				   bitmap->description);
584		return;
585	}
586	for (i=0; i < num; i++)
587		ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
588}
589
590_INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
591						    blk_t block, int num)
592{
593	int	i;
594
595#ifdef EXT2FS_DEBUG_FAST_OPS
596	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
597		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
598				   bitmap->description);
599		return;
600	}
601#endif
602	for (i=0; i < num; i++)
603		ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
604}
605
606#undef _INLINE_
607#endif
608
609