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