Commit 930ae745f50088279fdc06057a429f16495b53a2
Committed by
Linus Torvalds
1 parent
a54baa1487
Exists in
master
and in
7 other branches
[PATCH] bitops: generic ext2_{set,clear,test,find_first_zero,find_next_zero}_bit()
This patch introduces the C-language equivalents of the functions below: int ext2_set_bit(int nr, volatile unsigned long *addr); int ext2_clear_bit(int nr, volatile unsigned long *addr); int ext2_test_bit(int nr, const volatile unsigned long *addr); unsigned long ext2_find_first_zero_bit(const unsigned long *addr, unsigned long size); unsinged long ext2_find_next_zero_bit(const unsigned long *addr, unsigned long size); In include/asm-generic/bitops/ext2-non-atomic.h This code largely copied from: include/asm-powerpc/bitops.h include/asm-parisc/bitops.h Signed-off-by: Akinobu Mita <mita@miraclelinux.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 3 changed files with 144 additions and 0 deletions Side-by-side Diff
include/asm-generic/bitops/ext2-non-atomic.h
1 | +#ifndef _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_ | |
2 | +#define _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_ | |
3 | + | |
4 | +#include <asm-generic/bitops/le.h> | |
5 | + | |
6 | +#define ext2_set_bit(nr,addr) \ | |
7 | + generic___test_and_set_le_bit((nr),(unsigned long *)(addr)) | |
8 | +#define ext2_clear_bit(nr,addr) \ | |
9 | + generic___test_and_clear_le_bit((nr),(unsigned long *)(addr)) | |
10 | + | |
11 | +#define ext2_test_bit(nr,addr) \ | |
12 | + generic_test_le_bit((nr),(unsigned long *)(addr)) | |
13 | +#define ext2_find_first_zero_bit(addr, size) \ | |
14 | + generic_find_first_zero_le_bit((unsigned long *)(addr), (size)) | |
15 | +#define ext2_find_next_zero_bit(addr, size, off) \ | |
16 | + generic_find_next_zero_le_bit((unsigned long *)(addr), (size), (off)) | |
17 | + | |
18 | +#endif /* _ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_ */ |
include/asm-generic/bitops/le.h
1 | +#ifndef _ASM_GENERIC_BITOPS_LE_H_ | |
2 | +#define _ASM_GENERIC_BITOPS_LE_H_ | |
3 | + | |
4 | +#include <asm/types.h> | |
5 | +#include <asm/byteorder.h> | |
6 | + | |
7 | +#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) | |
8 | +#define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) | |
9 | + | |
10 | +#if defined(__LITTLE_ENDIAN) | |
11 | + | |
12 | +#define generic_test_le_bit(nr, addr) test_bit(nr, addr) | |
13 | +#define generic___set_le_bit(nr, addr) __set_bit(nr, addr) | |
14 | +#define generic___clear_le_bit(nr, addr) __clear_bit(nr, addr) | |
15 | + | |
16 | +#define generic_test_and_set_le_bit(nr, addr) test_and_set_bit(nr, addr) | |
17 | +#define generic_test_and_clear_le_bit(nr, addr) test_and_clear_bit(nr, addr) | |
18 | + | |
19 | +#define generic___test_and_set_le_bit(nr, addr) __test_and_set_bit(nr, addr) | |
20 | +#define generic___test_and_clear_le_bit(nr, addr) __test_and_clear_bit(nr, addr) | |
21 | + | |
22 | +#define generic_find_next_zero_le_bit(addr, size, offset) find_next_zero_bit(addr, size, offset) | |
23 | + | |
24 | +#elif defined(__BIG_ENDIAN) | |
25 | + | |
26 | +#define generic_test_le_bit(nr, addr) \ | |
27 | + test_bit((nr) ^ BITOP_LE_SWIZZLE, (addr)) | |
28 | +#define generic___set_le_bit(nr, addr) \ | |
29 | + __set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr)) | |
30 | +#define generic___clear_le_bit(nr, addr) \ | |
31 | + __clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr)) | |
32 | + | |
33 | +#define generic_test_and_set_le_bit(nr, addr) \ | |
34 | + test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr)) | |
35 | +#define generic_test_and_clear_le_bit(nr, addr) \ | |
36 | + test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr)) | |
37 | + | |
38 | +#define generic___test_and_set_le_bit(nr, addr) \ | |
39 | + __test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, (addr)) | |
40 | +#define generic___test_and_clear_le_bit(nr, addr) \ | |
41 | + __test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, (addr)) | |
42 | + | |
43 | +extern unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, | |
44 | + unsigned long size, unsigned long offset); | |
45 | + | |
46 | +#else | |
47 | +#error "Please fix <asm/byteorder.h>" | |
48 | +#endif | |
49 | + | |
50 | +#define generic_find_first_zero_le_bit(addr, size) \ | |
51 | + generic_find_next_zero_le_bit((addr), (size), 0) | |
52 | + | |
53 | +#endif /* _ASM_GENERIC_BITOPS_LE_H_ */ |
lib/find_next_bit.c
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | #include <linux/bitops.h> |
13 | 13 | #include <linux/module.h> |
14 | 14 | #include <asm/types.h> |
15 | +#include <asm/byteorder.h> | |
15 | 16 | |
16 | 17 | #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) |
17 | 18 | |
... | ... | @@ -106,4 +107,76 @@ |
106 | 107 | } |
107 | 108 | |
108 | 109 | EXPORT_SYMBOL(find_next_zero_bit); |
110 | + | |
111 | +#ifdef __BIG_ENDIAN | |
112 | + | |
113 | +/* include/linux/byteorder does not support "unsigned long" type */ | |
114 | +static inline unsigned long ext2_swabp(const unsigned long * x) | |
115 | +{ | |
116 | +#if BITS_PER_LONG == 64 | |
117 | + return (unsigned long) __swab64p((u64 *) x); | |
118 | +#elif BITS_PER_LONG == 32 | |
119 | + return (unsigned long) __swab32p((u32 *) x); | |
120 | +#else | |
121 | +#error BITS_PER_LONG not defined | |
122 | +#endif | |
123 | +} | |
124 | + | |
125 | +/* include/linux/byteorder doesn't support "unsigned long" type */ | |
126 | +static inline unsigned long ext2_swab(const unsigned long y) | |
127 | +{ | |
128 | +#if BITS_PER_LONG == 64 | |
129 | + return (unsigned long) __swab64((u64) y); | |
130 | +#elif BITS_PER_LONG == 32 | |
131 | + return (unsigned long) __swab32((u32) y); | |
132 | +#else | |
133 | +#error BITS_PER_LONG not defined | |
134 | +#endif | |
135 | +} | |
136 | + | |
137 | +unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned | |
138 | + long size, unsigned long offset) | |
139 | +{ | |
140 | + const unsigned long *p = addr + BITOP_WORD(offset); | |
141 | + unsigned long result = offset & ~(BITS_PER_LONG - 1); | |
142 | + unsigned long tmp; | |
143 | + | |
144 | + if (offset >= size) | |
145 | + return size; | |
146 | + size -= result; | |
147 | + offset &= (BITS_PER_LONG - 1UL); | |
148 | + if (offset) { | |
149 | + tmp = ext2_swabp(p++); | |
150 | + tmp |= (~0UL >> (BITS_PER_LONG - offset)); | |
151 | + if (size < BITS_PER_LONG) | |
152 | + goto found_first; | |
153 | + if (~tmp) | |
154 | + goto found_middle; | |
155 | + size -= BITS_PER_LONG; | |
156 | + result += BITS_PER_LONG; | |
157 | + } | |
158 | + | |
159 | + while (size & ~(BITS_PER_LONG - 1)) { | |
160 | + if (~(tmp = *(p++))) | |
161 | + goto found_middle_swap; | |
162 | + result += BITS_PER_LONG; | |
163 | + size -= BITS_PER_LONG; | |
164 | + } | |
165 | + if (!size) | |
166 | + return result; | |
167 | + tmp = ext2_swabp(p); | |
168 | +found_first: | |
169 | + tmp |= ~0UL << size; | |
170 | + if (tmp == ~0UL) /* Are any bits zero? */ | |
171 | + return result + size; /* Nope. Skip ffz */ | |
172 | +found_middle: | |
173 | + return result + ffz(tmp); | |
174 | + | |
175 | +found_middle_swap: | |
176 | + return result + ffz(ext2_swab(tmp)); | |
177 | +} | |
178 | + | |
179 | +EXPORT_SYMBOL(generic_find_next_zero_le_bit); | |
180 | + | |
181 | +#endif /* __BIG_ENDIAN */ |