xref: /openbmc/linux/Documentation/bpf/cpumasks.rst (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1bdbda395SDavid Vernet.. SPDX-License-Identifier: GPL-2.0
2bdbda395SDavid Vernet
3bdbda395SDavid Vernet.. _cpumasks-header-label:
4bdbda395SDavid Vernet
5bdbda395SDavid Vernet==================
6bdbda395SDavid VernetBPF cpumask kfuncs
7bdbda395SDavid Vernet==================
8bdbda395SDavid Vernet
9bdbda395SDavid Vernet1. Introduction
10bdbda395SDavid Vernet===============
11bdbda395SDavid Vernet
12bdbda395SDavid Vernet``struct cpumask`` is a bitmap data structure in the kernel whose indices
13bdbda395SDavid Vernetreflect the CPUs on the system. Commonly, cpumasks are used to track which CPUs
14bdbda395SDavid Verneta task is affinitized to, but they can also be used to e.g. track which cores
15bdbda395SDavid Vernetare associated with a scheduling domain, which cores on a machine are idle,
16bdbda395SDavid Vernetetc.
17bdbda395SDavid Vernet
18bdbda395SDavid VernetBPF provides programs with a set of :ref:`kfuncs-header-label` that can be
19bdbda395SDavid Vernetused to allocate, mutate, query, and free cpumasks.
20bdbda395SDavid Vernet
21bdbda395SDavid Vernet2. BPF cpumask objects
22bdbda395SDavid Vernet======================
23bdbda395SDavid Vernet
24bdbda395SDavid VernetThere are two different types of cpumasks that can be used by BPF programs.
25bdbda395SDavid Vernet
26bdbda395SDavid Vernet2.1 ``struct bpf_cpumask *``
27bdbda395SDavid Vernet----------------------------
28bdbda395SDavid Vernet
29bdbda395SDavid Vernet``struct bpf_cpumask *`` is a cpumask that is allocated by BPF, on behalf of a
30bdbda395SDavid VernetBPF program, and whose lifecycle is entirely controlled by BPF. These cpumasks
31bdbda395SDavid Vernetare RCU-protected, can be mutated, can be used as kptrs, and can be safely cast
32bdbda395SDavid Vernetto a ``struct cpumask *``.
33bdbda395SDavid Vernet
34bdbda395SDavid Vernet2.1.1 ``struct bpf_cpumask *`` lifecycle
35bdbda395SDavid Vernet----------------------------------------
36bdbda395SDavid Vernet
37bdbda395SDavid VernetA ``struct bpf_cpumask *`` is allocated, acquired, and released, using the
38bdbda395SDavid Vernetfollowing functions:
39bdbda395SDavid Vernet
40bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
41bdbda395SDavid Vernet  :identifiers: bpf_cpumask_create
42bdbda395SDavid Vernet
43bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
44bdbda395SDavid Vernet  :identifiers: bpf_cpumask_acquire
45bdbda395SDavid Vernet
46bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
47bdbda395SDavid Vernet  :identifiers: bpf_cpumask_release
48bdbda395SDavid Vernet
49bdbda395SDavid VernetFor example:
50bdbda395SDavid Vernet
51bdbda395SDavid Vernet.. code-block:: c
52bdbda395SDavid Vernet
53bdbda395SDavid Vernet        struct cpumask_map_value {
5403b77e17SAlexei Starovoitov                struct bpf_cpumask __kptr * cpumask;
55bdbda395SDavid Vernet        };
56bdbda395SDavid Vernet
57bdbda395SDavid Vernet        struct array_map {
58bdbda395SDavid Vernet                __uint(type, BPF_MAP_TYPE_ARRAY);
59bdbda395SDavid Vernet                __type(key, int);
60bdbda395SDavid Vernet                __type(value, struct cpumask_map_value);
61bdbda395SDavid Vernet                __uint(max_entries, 65536);
62bdbda395SDavid Vernet        } cpumask_map SEC(".maps");
63bdbda395SDavid Vernet
64bdbda395SDavid Vernet        static int cpumask_map_insert(struct bpf_cpumask *mask, u32 pid)
65bdbda395SDavid Vernet        {
66bdbda395SDavid Vernet                struct cpumask_map_value local, *v;
67bdbda395SDavid Vernet                long status;
68bdbda395SDavid Vernet                struct bpf_cpumask *old;
69bdbda395SDavid Vernet                u32 key = pid;
70bdbda395SDavid Vernet
71bdbda395SDavid Vernet                local.cpumask = NULL;
72bdbda395SDavid Vernet                status = bpf_map_update_elem(&cpumask_map, &key, &local, 0);
73bdbda395SDavid Vernet                if (status) {
74bdbda395SDavid Vernet                        bpf_cpumask_release(mask);
75bdbda395SDavid Vernet                        return status;
76bdbda395SDavid Vernet                }
77bdbda395SDavid Vernet
78bdbda395SDavid Vernet                v = bpf_map_lookup_elem(&cpumask_map, &key);
79bdbda395SDavid Vernet                if (!v) {
80bdbda395SDavid Vernet                        bpf_cpumask_release(mask);
81bdbda395SDavid Vernet                        return -ENOENT;
82bdbda395SDavid Vernet                }
83bdbda395SDavid Vernet
84bdbda395SDavid Vernet                old = bpf_kptr_xchg(&v->cpumask, mask);
85bdbda395SDavid Vernet                if (old)
86bdbda395SDavid Vernet                        bpf_cpumask_release(old);
87bdbda395SDavid Vernet
88bdbda395SDavid Vernet                return 0;
89bdbda395SDavid Vernet        }
90bdbda395SDavid Vernet
91bdbda395SDavid Vernet        /**
92bdbda395SDavid Vernet         * A sample tracepoint showing how a task's cpumask can be queried and
93bdbda395SDavid Vernet         * recorded as a kptr.
94bdbda395SDavid Vernet         */
95bdbda395SDavid Vernet        SEC("tp_btf/task_newtask")
96bdbda395SDavid Vernet        int BPF_PROG(record_task_cpumask, struct task_struct *task, u64 clone_flags)
97bdbda395SDavid Vernet        {
98bdbda395SDavid Vernet                struct bpf_cpumask *cpumask;
99bdbda395SDavid Vernet                int ret;
100bdbda395SDavid Vernet
101bdbda395SDavid Vernet                cpumask = bpf_cpumask_create();
102bdbda395SDavid Vernet                if (!cpumask)
103bdbda395SDavid Vernet                        return -ENOMEM;
104bdbda395SDavid Vernet
105bdbda395SDavid Vernet                if (!bpf_cpumask_full(task->cpus_ptr))
106bdbda395SDavid Vernet                        bpf_printk("task %s has CPU affinity", task->comm);
107bdbda395SDavid Vernet
108bdbda395SDavid Vernet                bpf_cpumask_copy(cpumask, task->cpus_ptr);
109bdbda395SDavid Vernet                return cpumask_map_insert(cpumask, task->pid);
110bdbda395SDavid Vernet        }
111bdbda395SDavid Vernet
112bdbda395SDavid Vernet----
113bdbda395SDavid Vernet
114bdbda395SDavid Vernet2.1.1 ``struct bpf_cpumask *`` as kptrs
115bdbda395SDavid Vernet---------------------------------------
116bdbda395SDavid Vernet
117bdbda395SDavid VernetAs mentioned and illustrated above, these ``struct bpf_cpumask *`` objects can
118bdbda395SDavid Vernetalso be stored in a map and used as kptrs. If a ``struct bpf_cpumask *`` is in
119bdbda395SDavid Verneta map, the reference can be removed from the map with bpf_kptr_xchg(), or
120fec2c6d1SDavid Vernetopportunistically acquired using RCU:
121bdbda395SDavid Vernet
122bdbda395SDavid Vernet.. code-block:: c
123bdbda395SDavid Vernet
124bdbda395SDavid Vernet	/* struct containing the struct bpf_cpumask kptr which is stored in the map. */
125bdbda395SDavid Vernet	struct cpumasks_kfunc_map_value {
12603b77e17SAlexei Starovoitov		struct bpf_cpumask __kptr * bpf_cpumask;
127bdbda395SDavid Vernet	};
128bdbda395SDavid Vernet
129bdbda395SDavid Vernet	/* The map containing struct cpumasks_kfunc_map_value entries. */
130bdbda395SDavid Vernet	struct {
131bdbda395SDavid Vernet		__uint(type, BPF_MAP_TYPE_ARRAY);
132bdbda395SDavid Vernet		__type(key, int);
133bdbda395SDavid Vernet		__type(value, struct cpumasks_kfunc_map_value);
134bdbda395SDavid Vernet		__uint(max_entries, 1);
135bdbda395SDavid Vernet	} cpumasks_kfunc_map SEC(".maps");
136bdbda395SDavid Vernet
137bdbda395SDavid Vernet	/* ... */
138bdbda395SDavid Vernet
139bdbda395SDavid Vernet	/**
140bdbda395SDavid Vernet	 * A simple example tracepoint program showing how a
141bdbda395SDavid Vernet	 * struct bpf_cpumask * kptr that is stored in a map can
142fec2c6d1SDavid Vernet	 * be passed to kfuncs using RCU protection.
143bdbda395SDavid Vernet	 */
144bdbda395SDavid Vernet	SEC("tp_btf/cgroup_mkdir")
145bdbda395SDavid Vernet	int BPF_PROG(cgrp_ancestor_example, struct cgroup *cgrp, const char *path)
146bdbda395SDavid Vernet	{
147bdbda395SDavid Vernet		struct bpf_cpumask *kptr;
148bdbda395SDavid Vernet		struct cpumasks_kfunc_map_value *v;
149bdbda395SDavid Vernet		u32 key = 0;
150bdbda395SDavid Vernet
151bdbda395SDavid Vernet		/* Assume a bpf_cpumask * kptr was previously stored in the map. */
152bdbda395SDavid Vernet		v = bpf_map_lookup_elem(&cpumasks_kfunc_map, &key);
153bdbda395SDavid Vernet		if (!v)
154bdbda395SDavid Vernet			return -ENOENT;
155bdbda395SDavid Vernet
156fec2c6d1SDavid Vernet		bpf_rcu_read_lock();
157bdbda395SDavid Vernet		/* Acquire a reference to the bpf_cpumask * kptr that's already stored in the map. */
158fec2c6d1SDavid Vernet		kptr = v->cpumask;
159fec2c6d1SDavid Vernet		if (!kptr) {
160bdbda395SDavid Vernet			/* If no bpf_cpumask was present in the map, it's because
161bdbda395SDavid Vernet			 * we're racing with another CPU that removed it with
162bdbda395SDavid Vernet			 * bpf_kptr_xchg() between the bpf_map_lookup_elem()
163fec2c6d1SDavid Vernet			 * above, and our load of the pointer from the map.
164bdbda395SDavid Vernet			 */
165fec2c6d1SDavid Vernet			bpf_rcu_read_unlock();
166bdbda395SDavid Vernet			return -EBUSY;
167fec2c6d1SDavid Vernet		}
168bdbda395SDavid Vernet
169fec2c6d1SDavid Vernet		bpf_cpumask_setall(kptr);
170fec2c6d1SDavid Vernet		bpf_rcu_read_unlock();
171bdbda395SDavid Vernet
172bdbda395SDavid Vernet		return 0;
173bdbda395SDavid Vernet	}
174bdbda395SDavid Vernet
175bdbda395SDavid Vernet----
176bdbda395SDavid Vernet
177bdbda395SDavid Vernet2.2 ``struct cpumask``
178bdbda395SDavid Vernet----------------------
179bdbda395SDavid Vernet
180bdbda395SDavid Vernet``struct cpumask`` is the object that actually contains the cpumask bitmap
181bdbda395SDavid Vernetbeing queried, mutated, etc. A ``struct bpf_cpumask`` wraps a ``struct
182bdbda395SDavid Vernetcpumask``, which is why it's safe to cast it as such (note however that it is
183bdbda395SDavid Vernet**not** safe to cast a ``struct cpumask *`` to a ``struct bpf_cpumask *``, and
184bdbda395SDavid Vernetthe verifier will reject any program that tries to do so).
185bdbda395SDavid Vernet
186bdbda395SDavid VernetAs we'll see below, any kfunc that mutates its cpumask argument will take a
187bdbda395SDavid Vernet``struct bpf_cpumask *`` as that argument. Any argument that simply queries the
188bdbda395SDavid Vernetcpumask will instead take a ``struct cpumask *``.
189bdbda395SDavid Vernet
190bdbda395SDavid Vernet3. cpumask kfuncs
191bdbda395SDavid Vernet=================
192bdbda395SDavid Vernet
193bdbda395SDavid VernetAbove, we described the kfuncs that can be used to allocate, acquire, release,
194bdbda395SDavid Vernetetc a ``struct bpf_cpumask *``. This section of the document will describe the
195bdbda395SDavid Vernetkfuncs for mutating and querying cpumasks.
196bdbda395SDavid Vernet
197bdbda395SDavid Vernet3.1 Mutating cpumasks
198bdbda395SDavid Vernet---------------------
199bdbda395SDavid Vernet
200bdbda395SDavid VernetSome cpumask kfuncs are "read-only" in that they don't mutate any of their
201bdbda395SDavid Vernetarguments, whereas others mutate at least one argument (which means that the
202bdbda395SDavid Vernetargument must be a ``struct bpf_cpumask *``, as described above).
203bdbda395SDavid Vernet
204bdbda395SDavid VernetThis section will describe all of the cpumask kfuncs which mutate at least one
205bdbda395SDavid Vernetargument. :ref:`cpumasks-querying-label` below describes the read-only kfuncs.
206bdbda395SDavid Vernet
207bdbda395SDavid Vernet3.1.1 Setting and clearing CPUs
208bdbda395SDavid Vernet-------------------------------
209bdbda395SDavid Vernet
210bdbda395SDavid Vernetbpf_cpumask_set_cpu() and bpf_cpumask_clear_cpu() can be used to set and clear
211bdbda395SDavid Verneta CPU in a ``struct bpf_cpumask`` respectively:
212bdbda395SDavid Vernet
213bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
214bdbda395SDavid Vernet   :identifiers: bpf_cpumask_set_cpu bpf_cpumask_clear_cpu
215bdbda395SDavid Vernet
216bdbda395SDavid VernetThese kfuncs are pretty straightforward, and can be used, for example, as
217bdbda395SDavid Vernetfollows:
218bdbda395SDavid Vernet
219bdbda395SDavid Vernet.. code-block:: c
220bdbda395SDavid Vernet
221bdbda395SDavid Vernet        /**
222bdbda395SDavid Vernet         * A sample tracepoint showing how a cpumask can be queried.
223bdbda395SDavid Vernet         */
224bdbda395SDavid Vernet        SEC("tp_btf/task_newtask")
225bdbda395SDavid Vernet        int BPF_PROG(test_set_clear_cpu, struct task_struct *task, u64 clone_flags)
226bdbda395SDavid Vernet        {
227bdbda395SDavid Vernet                struct bpf_cpumask *cpumask;
228bdbda395SDavid Vernet
229bdbda395SDavid Vernet                cpumask = bpf_cpumask_create();
230bdbda395SDavid Vernet                if (!cpumask)
231bdbda395SDavid Vernet                        return -ENOMEM;
232bdbda395SDavid Vernet
233bdbda395SDavid Vernet                bpf_cpumask_set_cpu(0, cpumask);
234bdbda395SDavid Vernet                if (!bpf_cpumask_test_cpu(0, cast(cpumask)))
235bdbda395SDavid Vernet                        /* Should never happen. */
236bdbda395SDavid Vernet                        goto release_exit;
237bdbda395SDavid Vernet
238bdbda395SDavid Vernet                bpf_cpumask_clear_cpu(0, cpumask);
239bdbda395SDavid Vernet                if (bpf_cpumask_test_cpu(0, cast(cpumask)))
240bdbda395SDavid Vernet                        /* Should never happen. */
241bdbda395SDavid Vernet                        goto release_exit;
242bdbda395SDavid Vernet
243bdbda395SDavid Vernet                /* struct cpumask * pointers such as task->cpus_ptr can also be queried. */
244bdbda395SDavid Vernet                if (bpf_cpumask_test_cpu(0, task->cpus_ptr))
245bdbda395SDavid Vernet                        bpf_printk("task %s can use CPU %d", task->comm, 0);
246bdbda395SDavid Vernet
247bdbda395SDavid Vernet        release_exit:
248bdbda395SDavid Vernet                bpf_cpumask_release(cpumask);
249bdbda395SDavid Vernet                return 0;
250bdbda395SDavid Vernet        }
251bdbda395SDavid Vernet
252bdbda395SDavid Vernet----
253bdbda395SDavid Vernet
254bdbda395SDavid Vernetbpf_cpumask_test_and_set_cpu() and bpf_cpumask_test_and_clear_cpu() are
255bdbda395SDavid Vernetcomplementary kfuncs that allow callers to atomically test and set (or clear)
256bdbda395SDavid VernetCPUs:
257bdbda395SDavid Vernet
258bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
259bdbda395SDavid Vernet   :identifiers: bpf_cpumask_test_and_set_cpu bpf_cpumask_test_and_clear_cpu
260bdbda395SDavid Vernet
261bdbda395SDavid Vernet----
262bdbda395SDavid Vernet
263bdbda395SDavid VernetWe can also set and clear entire ``struct bpf_cpumask *`` objects in one
264bdbda395SDavid Vernetoperation using bpf_cpumask_setall() and bpf_cpumask_clear():
265bdbda395SDavid Vernet
266bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
267bdbda395SDavid Vernet   :identifiers: bpf_cpumask_setall bpf_cpumask_clear
268bdbda395SDavid Vernet
269bdbda395SDavid Vernet3.1.2 Operations between cpumasks
270bdbda395SDavid Vernet---------------------------------
271bdbda395SDavid Vernet
272bdbda395SDavid VernetIn addition to setting and clearing individual CPUs in a single cpumask,
273bdbda395SDavid Vernetcallers can also perform bitwise operations between multiple cpumasks using
274bdbda395SDavid Vernetbpf_cpumask_and(), bpf_cpumask_or(), and bpf_cpumask_xor():
275bdbda395SDavid Vernet
276bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
277bdbda395SDavid Vernet   :identifiers: bpf_cpumask_and bpf_cpumask_or bpf_cpumask_xor
278bdbda395SDavid Vernet
279bdbda395SDavid VernetThe following is an example of how they may be used. Note that some of the
280bdbda395SDavid Vernetkfuncs shown in this example will be covered in more detail below.
281bdbda395SDavid Vernet
282bdbda395SDavid Vernet.. code-block:: c
283bdbda395SDavid Vernet
284bdbda395SDavid Vernet        /**
285bdbda395SDavid Vernet         * A sample tracepoint showing how a cpumask can be mutated using
286bdbda395SDavid Vernet           bitwise operators (and queried).
287bdbda395SDavid Vernet         */
288bdbda395SDavid Vernet        SEC("tp_btf/task_newtask")
289bdbda395SDavid Vernet        int BPF_PROG(test_and_or_xor, struct task_struct *task, u64 clone_flags)
290bdbda395SDavid Vernet        {
291bdbda395SDavid Vernet                struct bpf_cpumask *mask1, *mask2, *dst1, *dst2;
292bdbda395SDavid Vernet
293bdbda395SDavid Vernet                mask1 = bpf_cpumask_create();
294bdbda395SDavid Vernet                if (!mask1)
295bdbda395SDavid Vernet                        return -ENOMEM;
296bdbda395SDavid Vernet
297bdbda395SDavid Vernet                mask2 = bpf_cpumask_create();
298bdbda395SDavid Vernet                if (!mask2) {
299bdbda395SDavid Vernet                        bpf_cpumask_release(mask1);
300bdbda395SDavid Vernet                        return -ENOMEM;
301bdbda395SDavid Vernet                }
302bdbda395SDavid Vernet
303bdbda395SDavid Vernet                // ...Safely create the other two masks... */
304bdbda395SDavid Vernet
305bdbda395SDavid Vernet                bpf_cpumask_set_cpu(0, mask1);
306bdbda395SDavid Vernet                bpf_cpumask_set_cpu(1, mask2);
307bdbda395SDavid Vernet                bpf_cpumask_and(dst1, (const struct cpumask *)mask1, (const struct cpumask *)mask2);
308bdbda395SDavid Vernet                if (!bpf_cpumask_empty((const struct cpumask *)dst1))
309bdbda395SDavid Vernet                        /* Should never happen. */
310bdbda395SDavid Vernet                        goto release_exit;
311bdbda395SDavid Vernet
312bdbda395SDavid Vernet                bpf_cpumask_or(dst1, (const struct cpumask *)mask1, (const struct cpumask *)mask2);
313bdbda395SDavid Vernet                if (!bpf_cpumask_test_cpu(0, (const struct cpumask *)dst1))
314bdbda395SDavid Vernet                        /* Should never happen. */
315bdbda395SDavid Vernet                        goto release_exit;
316bdbda395SDavid Vernet
317bdbda395SDavid Vernet                if (!bpf_cpumask_test_cpu(1, (const struct cpumask *)dst1))
318bdbda395SDavid Vernet                        /* Should never happen. */
319bdbda395SDavid Vernet                        goto release_exit;
320bdbda395SDavid Vernet
321bdbda395SDavid Vernet                bpf_cpumask_xor(dst2, (const struct cpumask *)mask1, (const struct cpumask *)mask2);
322bdbda395SDavid Vernet                if (!bpf_cpumask_equal((const struct cpumask *)dst1,
323bdbda395SDavid Vernet                                       (const struct cpumask *)dst2))
324bdbda395SDavid Vernet                        /* Should never happen. */
325bdbda395SDavid Vernet                        goto release_exit;
326bdbda395SDavid Vernet
327bdbda395SDavid Vernet         release_exit:
328bdbda395SDavid Vernet                bpf_cpumask_release(mask1);
329bdbda395SDavid Vernet                bpf_cpumask_release(mask2);
330bdbda395SDavid Vernet                bpf_cpumask_release(dst1);
331bdbda395SDavid Vernet                bpf_cpumask_release(dst2);
332bdbda395SDavid Vernet                return 0;
333bdbda395SDavid Vernet        }
334bdbda395SDavid Vernet
335bdbda395SDavid Vernet----
336bdbda395SDavid Vernet
337bdbda395SDavid VernetThe contents of an entire cpumask may be copied to another using
338bdbda395SDavid Vernetbpf_cpumask_copy():
339bdbda395SDavid Vernet
340bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
341bdbda395SDavid Vernet   :identifiers: bpf_cpumask_copy
342bdbda395SDavid Vernet
343bdbda395SDavid Vernet----
344bdbda395SDavid Vernet
345bdbda395SDavid Vernet.. _cpumasks-querying-label:
346bdbda395SDavid Vernet
347bdbda395SDavid Vernet3.2 Querying cpumasks
348bdbda395SDavid Vernet---------------------
349bdbda395SDavid Vernet
350bdbda395SDavid VernetIn addition to the above kfuncs, there is also a set of read-only kfuncs that
351bdbda395SDavid Vernetcan be used to query the contents of cpumasks.
352bdbda395SDavid Vernet
353bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
35425085b4eSDavid Vernet   :identifiers: bpf_cpumask_first bpf_cpumask_first_zero bpf_cpumask_first_and
35525085b4eSDavid Vernet                 bpf_cpumask_test_cpu
356bdbda395SDavid Vernet
357bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
358bdbda395SDavid Vernet   :identifiers: bpf_cpumask_equal bpf_cpumask_intersects bpf_cpumask_subset
359bdbda395SDavid Vernet                 bpf_cpumask_empty bpf_cpumask_full
360bdbda395SDavid Vernet
361bdbda395SDavid Vernet.. kernel-doc:: kernel/bpf/cpumask.c
36225085b4eSDavid Vernet   :identifiers: bpf_cpumask_any_distribute bpf_cpumask_any_and_distribute
363bdbda395SDavid Vernet
364bdbda395SDavid Vernet----
365bdbda395SDavid Vernet
366bdbda395SDavid VernetSome example usages of these querying kfuncs were shown above. We will not
367*d56b699dSBjorn Helgaasreplicate those examples here. Note, however, that all of the aforementioned
368bdbda395SDavid Vernetkfuncs are tested in `tools/testing/selftests/bpf/progs/cpumask_success.c`_, so
369bdbda395SDavid Vernetplease take a look there if you're looking for more examples of how they can be
370bdbda395SDavid Vernetused.
371bdbda395SDavid Vernet
372bdbda395SDavid Vernet.. _tools/testing/selftests/bpf/progs/cpumask_success.c:
373bdbda395SDavid Vernet   https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/bpf/progs/cpumask_success.c
374bdbda395SDavid Vernet
375bdbda395SDavid Vernet
376bdbda395SDavid Vernet4. Adding BPF cpumask kfuncs
377bdbda395SDavid Vernet============================
378bdbda395SDavid Vernet
379bdbda395SDavid VernetThe set of supported BPF cpumask kfuncs are not (yet) a 1-1 match with the
380bdbda395SDavid Vernetcpumask operations in include/linux/cpumask.h. Any of those cpumask operations
381bdbda395SDavid Vernetcould easily be encapsulated in a new kfunc if and when required. If you'd like
382bdbda395SDavid Vernetto support a new cpumask operation, please feel free to submit a patch. If you
383bdbda395SDavid Vernetdo add a new cpumask kfunc, please document it here, and add any relevant
384bdbda395SDavid Vernetselftest testcases to the cpumask selftest suite.
385