bitops.h revision 3034f62a0f9c31e6dce8bd1237cffd3851847250
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/* These two routines moved to gen_bitmap.c */
358extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
359					 __u32 bitno);
360extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
361					   blk_t bitno);
362_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
363					blk_t bitno);
364
365_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
366					blk_t bitno)
367{
368	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
369		ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
370		return 0;
371	}
372	return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
373}
374
375_INLINE_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
376				       blk_t block)
377{
378	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
379				       bitmap,
380					  block);
381}
382
383_INLINE_ int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
384					 blk_t block)
385{
386	return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
387					    block);
388}
389
390_INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
391				       blk_t block)
392{
393	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
394					  block);
395}
396
397_INLINE_ int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
398				       ext2_ino_t inode)
399{
400	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
401					  inode);
402}
403
404_INLINE_ int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
405					 ext2_ino_t inode)
406{
407	return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
408				     inode);
409}
410
411_INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
412				       ext2_ino_t inode)
413{
414	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
415					  inode);
416}
417
418_INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
419					    blk_t block)
420{
421#ifdef EXT2FS_DEBUG_FAST_OPS
422	if ((block < bitmap->start) || (block > bitmap->end)) {
423		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
424				   bitmap->description);
425		return;
426	}
427#endif
428	ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
429}
430
431_INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
432					      blk_t block)
433{
434#ifdef EXT2FS_DEBUG_FAST_OPS
435	if ((block < bitmap->start) || (block > bitmap->end)) {
436		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
437				   block, bitmap->description);
438		return;
439	}
440#endif
441	ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
442}
443
444_INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
445					    blk_t block)
446{
447#ifdef EXT2FS_DEBUG_FAST_OPS
448	if ((block < bitmap->start) || (block > bitmap->end)) {
449		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
450				   block, bitmap->description);
451		return 0;
452	}
453#endif
454	return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
455}
456
457_INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
458					    ext2_ino_t inode)
459{
460#ifdef EXT2FS_DEBUG_FAST_OPS
461	if ((inode < bitmap->start) || (inode > bitmap->end)) {
462		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
463				   inode, bitmap->description);
464		return;
465	}
466#endif
467	ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
468}
469
470_INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
471					      ext2_ino_t inode)
472{
473#ifdef EXT2FS_DEBUG_FAST_OPS
474	if ((inode < bitmap->start) || (inode > bitmap->end)) {
475		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
476				   inode, bitmap->description);
477		return;
478	}
479#endif
480	ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
481}
482
483_INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
484					   ext2_ino_t inode)
485{
486#ifdef EXT2FS_DEBUG_FAST_OPS
487	if ((inode < bitmap->start) || (inode > bitmap->end)) {
488		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
489				   inode, bitmap->description);
490		return 0;
491	}
492#endif
493	return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
494}
495
496_INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
497{
498	return bitmap->start;
499}
500
501_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
502{
503	return bitmap->start;
504}
505
506_INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
507{
508	return bitmap->end;
509}
510
511_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
512{
513	return bitmap->end;
514}
515
516_INLINE_ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
517					    blk_t block, int num)
518{
519	int	i;
520
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	for (i=0; i < num; i++) {
527		if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
528			return 0;
529	}
530	return 1;
531}
532
533_INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
534						 blk_t block, int num)
535{
536	int	i;
537
538#ifdef EXT2FS_DEBUG_FAST_OPS
539	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
540		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
541				   block, bitmap->description);
542		return 0;
543	}
544#endif
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_ void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
553					     blk_t block, int num)
554{
555	int	i;
556
557	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
558		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
559				   bitmap->description);
560		return;
561	}
562	for (i=0; i < num; i++)
563		ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
564}
565
566_INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
567						  blk_t block, int num)
568{
569	int	i;
570
571#ifdef EXT2FS_DEBUG_FAST_OPS
572	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
573		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
574				   bitmap->description);
575		return;
576	}
577#endif
578	for (i=0; i < num; i++)
579		ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
580}
581
582_INLINE_ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
583					       blk_t block, int num)
584{
585	int	i;
586
587	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
588		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
589				   bitmap->description);
590		return;
591	}
592	for (i=0; i < num; i++)
593		ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
594}
595
596_INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
597						    blk_t block, int num)
598{
599	int	i;
600
601#ifdef EXT2FS_DEBUG_FAST_OPS
602	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
603		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
604				   bitmap->description);
605		return;
606	}
607#endif
608	for (i=0; i < num; i++)
609		ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
610}
611#undef _INLINE_
612#endif
613
614