From: "Yury Norov (NVIDIA)" <yury.norov@gmail.com>
To: Andrew Morton <akpm@linux-foundation.org>,
Thomas Gleixner <tglx@linutronix.de>
Cc: "Yury Norov (NVIDIA)" <yury.norov@gmail.com>,
Rasmus Villemoes <linux@rasmusvillemoes.dk>,
linux-kernel@vger.kernel.org
Subject: [PATCH 1/3] bitmap: cpumask: introduce and_andnot search helper and iterator
Date: Tue, 18 Nov 2025 22:13:03 -0500 [thread overview]
Message-ID: <20251119031306.644129-2-yury.norov@gmail.com> (raw)
In-Reply-To: <20251119031306.644129-1-yury.norov@gmail.com>
Like other similar iterators, *_and_andnot helps to get rid of temporary
on-stack bitmaps and associate housekeeping code.
Signed-off-by: Yury Norov (NVIDIA) <yury.norov@gmail.com>
---
include/linux/cpumask.h | 22 ++++++++++++++++++++++
include/linux/find.h | 38 ++++++++++++++++++++++++++++++++++++++
lib/find_bit.c | 9 +++++++++
3 files changed, 69 insertions(+)
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index ff8f41ab7ce6..6de16a0e6e7b 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -406,6 +406,28 @@ unsigned int cpumask_random(const struct cpumask *src)
#define for_each_cpu_and(cpu, mask1, mask2) \
for_each_and_bit(cpu, cpumask_bits(mask1), cpumask_bits(mask2), small_cpumask_bits)
+/**
+ * for_each_cpu_and_andnot_from - iterate over every cpu in all masks
+ * @cpu: the (optionally unsigned) integer iterator
+ * @mask1: the first cpumask pointer
+ * @mask2: the second cpumask pointer
+ * @mask3: the third cpumask pointer
+ *
+ * This saves a temporary CPU mask in many places. It is equivalent to:
+ * struct cpumask tmp;
+ * cpumask_and(&tmp, &mask1, &mask2);
+ * cpumask_andnot(&tmp, &tmp, &mask3);
+ * for_each_cpu_from(cpu, &tmp)
+ * ...
+ *
+ * After the loop, cpu is >= nr_cpu_ids.
+ */
+#define for_each_cpu_and_andnot_from(cpu, mask1, mask2, mask3) \
+ for_each_and_andnot_bit_from(cpu, cpumask_bits(mask1), \
+ cpumask_bits(mask2), \
+ cpumask_bits(mask3), \
+ small_cpumask_bits)
+
/**
* for_each_cpu_andnot - iterate over every cpu present in one mask, excluding
* those present in another.
diff --git a/include/linux/find.h b/include/linux/find.h
index 9d720ad92bc1..daf72078c25e 100644
--- a/include/linux/find.h
+++ b/include/linux/find.h
@@ -14,6 +14,9 @@ unsigned long _find_next_and_bit(const unsigned long *addr1, const unsigned long
unsigned long nbits, unsigned long start);
unsigned long _find_next_andnot_bit(const unsigned long *addr1, const unsigned long *addr2,
unsigned long nbits, unsigned long start);
+unsigned long _find_next_and_andnot_bit(const unsigned long *addr1, const unsigned long *addr2,
+ const unsigned long *addr3, unsigned long size,
+ unsigned long n);
unsigned long _find_next_or_bit(const unsigned long *addr1, const unsigned long *addr2,
unsigned long nbits, unsigned long start);
unsigned long _find_next_zero_bit(const unsigned long *addr, unsigned long nbits,
@@ -135,6 +138,36 @@ unsigned long find_next_andnot_bit(const unsigned long *addr1,
}
#endif
+/**
+ * find_next_and_andnot_bit - find the next set bit in *addr1 and *addr2
+ * excluding all the bits in *addr3
+ * @addr1: The first address to base the search on
+ * @addr2: The second address to base the search on
+ * @addr3: The second address to base the search on
+ * @size: The bitmap size in bits
+ * @offset: The bitnumber to start searching at
+ *
+ * Returns the bit number for the next set bit
+ * If no bits found, returns >= @size.
+ */
+static __always_inline
+unsigned long find_next_and_andnot_bit(const unsigned long *addr1,
+ const unsigned long *addr2, const unsigned long *addr3,
+ unsigned long size, unsigned long offset)
+{
+ if (small_const_nbits(size)) {
+ unsigned long val;
+
+ if (unlikely(offset >= size))
+ return size;
+
+ val = *addr1 & *addr2 & ~*addr3;
+ return val ? __ffs(val) : size;
+ }
+
+ return _find_next_and_andnot_bit(addr1, addr2, addr3, size, offset);
+}
+
#ifndef find_next_or_bit
/**
* find_next_or_bit - find the next set bit in either memory regions
@@ -595,6 +628,11 @@ unsigned long find_next_bit_le(const void *addr, unsigned
(bit) = find_next_andnot_bit((addr1), (addr2), (size), (bit)), (bit) < (size);\
(bit)++)
+#define for_each_and_andnot_bit_from(bit, addr1, addr2, addr3, size) \
+ for (; (bit) = find_next_and_andnot_bit((addr1), (addr2), (addr3), \
+ (size), (bit)), (bit) < (size); \
+ (bit)++)
+
#define for_each_or_bit(bit, addr1, addr2, size) \
for ((bit) = 0; \
(bit) = find_next_or_bit((addr1), (addr2), (size), (bit)), (bit) < (size);\
diff --git a/lib/find_bit.c b/lib/find_bit.c
index d4b5a29e3e72..aec79207c566 100644
--- a/lib/find_bit.c
+++ b/lib/find_bit.c
@@ -206,6 +206,15 @@ unsigned long _find_next_andnot_bit(const unsigned long *addr1, const unsigned l
EXPORT_SYMBOL(_find_next_andnot_bit);
#endif
+unsigned long _find_next_and_andnot_bit(const unsigned long *addr1,
+ const unsigned long *addr2,
+ const unsigned long *addr3,
+ unsigned long nbits, unsigned long start)
+{
+ return FIND_NEXT_BIT(addr1[idx] & addr2[idx] & ~addr3[idx], /* nop */, nbits, start);
+}
+EXPORT_SYMBOL(_find_next_and_andnot_bit);
+
#ifndef find_next_or_bit
unsigned long _find_next_or_bit(const unsigned long *addr1, const unsigned long *addr2,
unsigned long nbits, unsigned long start)
--
2.43.0
next prev parent reply other threads:[~2025-11-19 3:13 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-19 3:13 [PATCH 0/3] improve group_cpus initialization routines Yury Norov (NVIDIA)
2025-11-19 3:13 ` Yury Norov (NVIDIA) [this message]
2025-11-19 3:13 ` [PATCH 2/3] group_cpus: don't call cpumask_weight() prematurely Yury Norov (NVIDIA)
2025-11-19 3:13 ` [PATCH 3/3] group_cpus: simplify inner loop in grp_spread_init_one() Yury Norov (NVIDIA)
2025-11-28 2:25 ` [PATCH 0/3] improve group_cpus initialization routines Yury Norov
-- strict thread matches above, loose matches on Subject: below --
2025-09-10 21:08 Yury Norov
2025-09-10 21:08 ` [PATCH 1/3] bitmap: cpumask: introduce and_andnot search helper and iterator Yury Norov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251119031306.644129-2-yury.norov@gmail.com \
--to=yury.norov@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@rasmusvillemoes.dk \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.