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