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