From: Hongzhen Luo <hongz...@linux.alibaba.com>

Introduce following bitmap helpers:
        erofs_test_bit
        __erofs_set_bit
        __erofs_clear_bit
        erofs_find_next_bit

Signed-off-by: Jingbo Xu <jeffl...@linux.alibaba.com> [1]
[1] https://lore.kernel.org/r/20230802091750.74181-3-jeffl...@linux.alibaba.com
Signed-off-by: Hongzhen Luo <hongz...@linux.alibaba.com>
Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com>
---
 include/erofs/bitops.h | 40 ++++++++++++++++++++++++++++++++++++++++
 include/erofs/defs.h   |  5 +++++
 lib/Makefile.am        |  3 ++-
 lib/bitops.c           | 30 ++++++++++++++++++++++++++++++
 4 files changed, 77 insertions(+), 1 deletion(-)
 create mode 100644 include/erofs/bitops.h
 create mode 100644 lib/bitops.c

diff --git a/include/erofs/bitops.h b/include/erofs/bitops.h
new file mode 100644
index 0000000..058642f
--- /dev/null
+++ b/include/erofs/bitops.h
@@ -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
diff --git a/include/erofs/defs.h b/include/erofs/defs.h
index e462338..051a270 100644
--- a/include/erofs/defs.h
+++ b/include/erofs/defs.h
@@ -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;
diff --git a/lib/Makefile.am b/lib/Makefile.am
index ef98377..9cddc92 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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
index 0000000..bb0c9ee
--- /dev/null
+++ b/lib/bitops.c
@@ -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);
+}
-- 
2.43.5

Reply via email to