erofs-utils: lib: add some bit operations
authorHongzhen Luo <hongzhen@linux.alibaba.com>
Fri, 3 Jan 2025 09:03:35 +0000 (17:03 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Thu, 6 Feb 2025 05:01:02 +0000 (13:01 +0800)
Introduce following bitmap helpers:
erofs_test_bit
__erofs_set_bit
__erofs_clear_bit
erofs_find_next_bit

[1] https://lore.kernel.org/r/20230802091750.74181-3-jefflexu@linux.alibaba.com

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com> [1]
Signed-off-by: Hongzhen Luo <hongzhen@linux.alibaba.com>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20250103090338.740593-2-hsiangkao@linux.alibaba.com
include/erofs/bitops.h [new file with mode: 0644]
include/erofs/defs.h
lib/Makefile.am
lib/bitops.c [new file with mode: 0644]

diff --git a/include/erofs/bitops.h b/include/erofs/bitops.h
new file mode 100644 (file)
index 0000000..058642f
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */
+#ifndef __EROFS_BITOPS_H
+#define __EROFS_BITOPS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "defs.h"
+
+static inline void __erofs_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 __erofs_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 int __erofs_test_bit(int nr, const volatile unsigned long *addr)
+{
+       return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+unsigned long erofs_find_next_bit(const unsigned long *addr,
+                                 unsigned long nbits, unsigned long start);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index e4623389af64033f75265bbbdc361bf57907da45..051a270531ca10fa1f03fe00ffb580fbe882b042 100644 (file)
@@ -286,6 +286,11 @@ static inline u32 get_unaligned_le64(const void *p)
        (n) & (1ULL <<  1) ?  1 : 0     \
 )
 
+static inline unsigned int ffs_long(unsigned long s)
+{
+       return __builtin_ctzl(s);
+}
+
 static inline unsigned int fls_long(unsigned long x)
 {
        return x ? sizeof(x) * 8 - __builtin_clzl(x) : 0;
index ef98377b9e637b16fdd34fb4e7b02d4bd800f142..9cddc92b1f83a2a9357b7bb61ddde47a8f31693a 100644 (file)
@@ -20,6 +20,7 @@ noinst_HEADERS = $(top_srcdir)/include/erofs_fs.h \
       $(top_srcdir)/include/erofs/io.h \
       $(top_srcdir)/include/erofs/list.h \
       $(top_srcdir)/include/erofs/print.h \
+      $(top_srcdir)/include/erofs/bitops.h \
       $(top_srcdir)/include/erofs/tar.h \
       $(top_srcdir)/include/erofs/trace.h \
       $(top_srcdir)/include/erofs/xattr.h \
@@ -34,7 +35,7 @@ liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c exclude.c \
                      namei.c data.c compress.c compressor.c zmap.c decompress.c \
                      compress_hints.c hashmap.c sha256.c blobchunk.c dir.c \
                      fragments.c dedupe.c uuid_unparse.c uuid.c tar.c \
-                     block_list.c rebuild.c diskbuf.c
+                     block_list.c rebuild.c diskbuf.c bitops.c
 
 liberofs_la_CFLAGS = -Wall ${libuuid_CFLAGS} -I$(top_srcdir)/include
 if ENABLE_LZ4
diff --git a/lib/bitops.c b/lib/bitops.c
new file mode 100644 (file)
index 0000000..bb0c9ee
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
+/*
+ * erofs-utils/lib/bitops.c
+ *
+ * Copyright (C) 2025, Alibaba Cloud
+ */
+#include <erofs/bitops.h>
+
+unsigned long erofs_find_next_bit(const unsigned long *addr,
+                                 unsigned long nbits, unsigned long start)
+{
+       unsigned long tmp;
+
+       if (__erofs_unlikely(start >= nbits))
+               return nbits;
+
+       tmp = addr[start / BITS_PER_LONG];
+
+       tmp &= ~0UL << ((start) & (BITS_PER_LONG - 1));
+       start = round_down(start, BITS_PER_LONG);
+
+       while (!tmp) {
+               start += BITS_PER_LONG;
+               if (start >= nbits)
+                       return nbits;
+
+               tmp = addr[start / BITS_PER_LONG];
+       }
+       return min(start + ffs_long(tmp), nbits);
+}