]> www.infradead.org Git - mtd-utils.git/commitdiff
ubifs-utils: Add bit operations implementations
authorZhihao Cheng <chengzhihao1@huawei.com>
Mon, 11 Nov 2024 08:36:46 +0000 (16:36 +0800)
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>
Mon, 11 Nov 2024 09:32:45 +0000 (10:32 +0100)
Add bit operations implementations, because there are some bit operations
(eg. __set_bit, test_bit) used in UBIFS linux kernel libs.

This is a preparation for replacing implementation of UBIFS utils with
linux kernel libs.

Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
ubifs-utils/Makemodule.am
ubifs-utils/common/bitops.c [new file with mode: 0644]
ubifs-utils/common/bitops.h [new file with mode: 0644]
ubifs-utils/common/defs.h
ubifs-utils/common/lpt.c

index 5816257993e989787026c896461257beb9a13ffb..9e075071d6d0270784fe4391067f56192badbe05 100644 (file)
@@ -3,6 +3,8 @@ common_SOURCES = \
        ubifs-utils/common/linux_types.h \
        ubifs-utils/common/linux_err.h \
        ubifs-utils/common/atomic.h \
+       ubifs-utils/common/bitops.h \
+       ubifs-utils/common/bitops.c \
        ubifs-utils/common/kmem.h \
        ubifs-utils/common/kmem.c \
        ubifs-utils/common/defs.h \
diff --git a/ubifs-utils/common/bitops.c b/ubifs-utils/common/bitops.c
new file mode 100644 (file)
index 0000000..c82f1fa
--- /dev/null
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realizations of bit operations.
+ */
+
+#include "bitops.h"
+#include "defs.h"
+
+/*
+ * This is a common helper function for find_next_bit and
+ * find_next_zero_bit.  The difference is the "invert" argument, which
+ * is XORed with each fetched word before searching it for one bits.
+ */
+unsigned long _find_next_bit(const unsigned long *addr,
+               unsigned long nbits, unsigned long start, unsigned long invert)
+{
+       unsigned long tmp;
+
+       if (!nbits || start >= nbits)
+               return nbits;
+
+       tmp = addr[start / BITS_PER_LONG] ^ invert;
+
+       /* Handle 1st word. */
+       tmp &= BITMAP_FIRST_WORD_MASK(start);
+       start = round_down(start, BITS_PER_LONG);
+
+       while (!tmp) {
+               start += BITS_PER_LONG;
+               if (start >= nbits)
+                       return nbits;
+
+               tmp = addr[start / BITS_PER_LONG] ^ invert;
+       }
+
+       return min(start + __ffs(tmp), nbits);
+}
diff --git a/ubifs-utils/common/bitops.h b/ubifs-utils/common/bitops.h
new file mode 100644 (file)
index 0000000..3a2d3f8
--- /dev/null
@@ -0,0 +1,152 @@
+#ifndef __BITOPS_H__
+#define __BITOPS_H__
+
+/*
+ * Non-atomic bitops.
+ */
+
+#include <stdbool.h>
+
+#define BITS_PER_LONG                  __LONG_WIDTH__
+#define DIV_ROUND_UP(n, d)             (((n) + (d) - 1) / (d))
+#define BITS_TO_LONGS(nr)              DIV_ROUND_UP(nr, BITS_PER_LONG)
+
+#define BIT_MASK(nr)                   (1UL << ((nr) % BITS_PER_LONG))
+#define BIT_WORD(nr)                   ((nr) / BITS_PER_LONG)
+#define BITMAP_FIRST_WORD_MASK(start)  (~0UL << ((start) & (BITS_PER_LONG - 1)))
+
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+       *p  |= mask;
+}
+
+static inline void set_bit(int nr, volatile unsigned long *addr)
+{
+       __set_bit(nr, addr);
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+       *p &= ~mask;
+}
+
+static inline void clear_bit(int nr, volatile unsigned long *addr)
+{
+       __clear_bit(nr, addr);
+}
+
+static inline bool test_bit(int nr, const volatile unsigned long *addr)
+{
+       unsigned long mask = BIT_MASK(nr);
+       unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+       return (*p & mask) != 0;
+}
+
+/* Sets and returns original value of the bit */
+static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+       if (test_bit(nr, addr))
+               return 1;
+       set_bit(nr, addr);
+       return 0;
+}
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+static inline int fls(int x)
+{
+       int r = 32;
+
+       if (!x)
+               return 0;
+       if (!(x & 0xffff0000u)) {
+               x <<= 16;
+               r -= 16;
+       }
+       if (!(x & 0xff000000u)) {
+               x <<= 8;
+               r -= 8;
+       }
+       if (!(x & 0xf0000000u)) {
+               x <<= 4;
+               r -= 4;
+       }
+       if (!(x & 0xc0000000u)) {
+               x <<= 2;
+               r -= 2;
+       }
+       if (!(x & 0x80000000u)) {
+               x <<= 1;
+               r -= 1;
+       }
+       return r;
+}
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+       int num = 0;
+
+#if BITS_PER_LONG == 64
+       if ((word & 0xffffffff) == 0) {
+               num += 32;
+               word >>= 32;
+       }
+#endif
+       if ((word & 0xffff) == 0) {
+               num += 16;
+               word >>= 16;
+       }
+       if ((word & 0xff) == 0) {
+               num += 8;
+               word >>= 8;
+       }
+       if ((word & 0xf) == 0) {
+               num += 4;
+               word >>= 4;
+       }
+       if ((word & 0x3) == 0) {
+               num += 2;
+               word >>= 2;
+       }
+       if ((word & 0x1) == 0)
+               num += 1;
+       return num;
+}
+
+unsigned long _find_next_bit(const unsigned long *addr,
+               unsigned long nbits, unsigned long start, unsigned long invert);
+
+/*
+ * Find the next set bit in a memory region.
+ */
+static inline unsigned long find_next_bit(const unsigned long *addr,
+                       unsigned long size, unsigned long offset)
+{
+       return _find_next_bit(addr, size, offset, 0UL);
+}
+
+static inline unsigned long find_next_zero_bit(const unsigned long *addr,
+                       unsigned long size, unsigned long offset)
+{
+       return _find_next_bit(addr, size, offset, ~0UL);
+}
+
+#endif
index dd3b806e3263b891a4010086b5ae15d43cc08a2f..485c50c06f3af07496a087c7e60b9c7efb0642b3 100644 (file)
@@ -28,42 +28,6 @@ enum { MKFS_PROGRAM_TYPE = 0 };
 
 #define unlikely(x) (x)
 
-/**
- * fls - find last (most-significant) bit set
- * @x: the word to search
- *
- * This is defined the same way as ffs.
- * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
- */
-static inline int fls(int x)
-{
-       int r = 32;
-
-       if (!x)
-               return 0;
-       if (!(x & 0xffff0000u)) {
-               x <<= 16;
-               r -= 16;
-       }
-       if (!(x & 0xff000000u)) {
-               x <<= 8;
-               r -= 8;
-       }
-       if (!(x & 0xf0000000u)) {
-               x <<= 4;
-               r -= 4;
-       }
-       if (!(x & 0xc0000000u)) {
-               x <<= 2;
-               r -= 2;
-       }
-       if (!(x & 0x80000000u)) {
-               x <<= 1;
-               r -= 1;
-       }
-       return r;
-}
-
 #define do_div(n,base) ({ \
 int __res; \
 __res = ((unsigned long) n) % (unsigned) base; \
index d07f569f3c3fd8e561b2fed11de912421c93255e..3c55f91bf2bf7a906b2c1afee1edc6a505f17682 100644 (file)
@@ -25,6 +25,7 @@
 #endif
 
 #include "lpt.h"
+#include "bitops.h"
 #include "defs.h"
 #include "ubifs.h"
 #include "crc16.h"