// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2023 Meta, Inc */
#include <linux/bpf.h>
#include <linux/bpf_mem_alloc.h>
#include <linux/btf.h>
#include <linux/btf_ids.h>
#include <linux/cpumask.h>
/**
* struct bpf_cpumask - refcounted BPF cpumask wrapper structure
* @ cpumask : The actual cpumask embedded in the struct .
* @ usage : Object reference counter . When the refcount goes to 0 , the
* memory is released back to the BPF allocator , which provides
* RCU safety .
*
* Note that we explicitly embed a cpumask_t rather than a cpumask_var_t . This
* is done to avoid confusing the verifier due to the typedef of cpumask_var_t
* changing depending on whether CONFIG_CPUMASK_OFFSTACK is defined or not . See
* the details in < linux / cpumask . h > . The consequence is that this structure is
* likely a bit larger than it needs to be when CONFIG_CPUMASK_OFFSTACK is
* defined due to embedding the whole NR_CPUS - size bitmap , but the extra memory
* overhead is minimal . For the more typical case of CONFIG_CPUMASK_OFFSTACK
* not being defined , the structure is the same size regardless .
*/
struct bpf_cpumask {
cpumask_t cpumask;
refcount_t usage;
};
static struct bpf_mem_alloc bpf_cpumask_ma;
static bool cpu_valid(u32 cpu)
{
return cpu < nr_cpu_ids;
}
__bpf_kfunc_start_defs();
/**
* bpf_cpumask_create ( ) - Create a mutable BPF cpumask .
*
* Allocates a cpumask that can be queried , mutated , acquired , and released by
* a BPF program . The cpumask returned by this function must either be embedded
* in a map as a kptr , or freed with bpf_cpumask_release ( ) .
*
* bpf_cpumask_create ( ) allocates memory using the BPF memory allocator , and
* will not block . It may return NULL if no memory is available .
*
* Return :
* * A pointer to a new struct bpf_cpumask instance on success .
* * NULL if the BPF memory allocator is out of memory .
*/
__bpf_kfunc struct bpf_cpumask *bpf_cpumask_create(void )
{
struct bpf_cpumask *cpumask;
/* cpumask must be the first element so struct bpf_cpumask be cast to struct cpumask. */
BUILD_BUG_ON(offsetof(struct bpf_cpumask, cpumask) != 0 );
cpumask = bpf_mem_cache_alloc(&bpf_cpumask_ma);
if (!cpumask)
return NULL;
memset(cpumask, 0 , sizeof (*cpumask));
refcount_set(&cpumask->usage, 1 );
return cpumask;
}
/**
* bpf_cpumask_acquire ( ) - Acquire a reference to a BPF cpumask .
* @ cpumask : The BPF cpumask being acquired . The cpumask must be a trusted
* pointer .
*
* Acquires a reference to a BPF cpumask . The cpumask returned by this function
* must either be embedded in a map as a kptr , or freed with
* bpf_cpumask_release ( ) .
*
* Return :
* * The struct bpf_cpumask pointer passed to the function .
*
*/
__bpf_kfunc struct bpf_cpumask *bpf_cpumask_acquire(struct bpf_cpumask *cpumask)
{
refcount_inc(&cpumask->usage);
return cpumask;
}
/**
* bpf_cpumask_release ( ) - Release a previously acquired BPF cpumask .
* @ cpumask : The cpumask being released .
*
* Releases a previously acquired reference to a BPF cpumask . When the final
* reference of the BPF cpumask has been released , it is subsequently freed in
* an RCU callback in the BPF memory allocator .
*/
__bpf_kfunc void bpf_cpumask_release(struct bpf_cpumask *cpumask)
{
if (!refcount_dec_and_test(&cpumask->usage))
return ;
bpf_mem_cache_free_rcu(&bpf_cpumask_ma, cpumask);
}
__bpf_kfunc void bpf_cpumask_release_dtor(void *cpumask)
{
bpf_cpumask_release(cpumask);
}
CFI_NOSEAL(bpf_cpumask_release_dtor);
/**
* bpf_cpumask_first ( ) - Get the index of the first nonzero bit in the cpumask .
* @ cpumask : The cpumask being queried .
*
* Find the index of the first nonzero bit of the cpumask . A struct bpf_cpumask
* pointer may be safely passed to this function .
*
* Return :
* * The index of the first nonzero bit in the struct cpumask .
*/
__bpf_kfunc u32 bpf_cpumask_first(const struct cpumask *cpumask)
{
return cpumask_first(cpumask);
}
/**
* bpf_cpumask_first_zero ( ) - Get the index of the first unset bit in the
* cpumask .
* @ cpumask : The cpumask being queried .
*
* Find the index of the first unset bit of the cpumask . A struct bpf_cpumask
* pointer may be safely passed to this function .
*
* Return :
* * The index of the first zero bit in the struct cpumask .
*/
__bpf_kfunc u32 bpf_cpumask_first_zero(const struct cpumask *cpumask)
{
return cpumask_first_zero(cpumask);
}
/**
* bpf_cpumask_first_and ( ) - Return the index of the first nonzero bit from the
* AND of two cpumasks .
* @ src1 : The first cpumask .
* @ src2 : The second cpumask .
*
* Find the index of the first nonzero bit of the AND of two cpumasks .
* struct bpf_cpumask pointers may be safely passed to @ src1 and @ src2 .
*
* Return :
* * The index of the first bit that is nonzero in both cpumask instances .
*/
__bpf_kfunc u32 bpf_cpumask_first_and(const struct cpumask *src1,
const struct cpumask *src2)
{
return cpumask_first_and(src1, src2);
}
/**
* bpf_cpumask_set_cpu ( ) - Set a bit for a CPU in a BPF cpumask .
* @ cpu : The CPU to be set in the cpumask .
* @ cpumask : The BPF cpumask in which a bit is being set .
*/
__bpf_kfunc void bpf_cpumask_set_cpu(u32 cpu, struct bpf_cpumask *cpumask)
{
if (!cpu_valid(cpu))
return ;
cpumask_set_cpu(cpu, (struct cpumask *)cpumask);
}
/**
* bpf_cpumask_clear_cpu ( ) - Clear a bit for a CPU in a BPF cpumask .
* @ cpu : The CPU to be cleared from the cpumask .
* @ cpumask : The BPF cpumask in which a bit is being cleared .
*/
__bpf_kfunc void bpf_cpumask_clear_cpu(u32 cpu, struct bpf_cpumask *cpumask)
{
if (!cpu_valid(cpu))
return ;
cpumask_clear_cpu(cpu, (struct cpumask *)cpumask);
}
/**
* bpf_cpumask_test_cpu ( ) - Test whether a CPU is set in a cpumask .
* @ cpu : The CPU being queried for .
* @ cpumask : The cpumask being queried for containing a CPU .
*
* Return :
* * true - @ cpu is set in the cpumask
* * false - @ cpu was not set in the cpumask , or @ cpu is an invalid cpu .
*/
__bpf_kfunc bool bpf_cpumask_test_cpu(u32 cpu, const struct cpumask *cpumask)
{
if (!cpu_valid(cpu))
return false ;
return cpumask_test_cpu(cpu, (struct cpumask *)cpumask);
}
/**
* bpf_cpumask_test_and_set_cpu ( ) - Atomically test and set a CPU in a BPF cpumask .
* @ cpu : The CPU being set and queried for .
* @ cpumask : The BPF cpumask being set and queried for containing a CPU .
*
* Return :
* * true - @ cpu is set in the cpumask
* * false - @ cpu was not set in the cpumask , or @ cpu is invalid .
*/
__bpf_kfunc bool bpf_cpumask_test_and_set_cpu(u32 cpu, struct bpf_cpumask *cpumask)
{
if (!cpu_valid(cpu))
return false ;
return cpumask_test_and_set_cpu(cpu, (struct cpumask *)cpumask);
}
/**
* bpf_cpumask_test_and_clear_cpu ( ) - Atomically test and clear a CPU in a BPF
* cpumask .
* @ cpu : The CPU being cleared and queried for .
* @ cpumask : The BPF cpumask being cleared and queried for containing a CPU .
*
* Return :
* * true - @ cpu is set in the cpumask
* * false - @ cpu was not set in the cpumask , or @ cpu is invalid .
*/
__bpf_kfunc bool bpf_cpumask_test_and_clear_cpu(u32 cpu, struct bpf_cpumask *cpumask)
{
if (!cpu_valid(cpu))
return false ;
return cpumask_test_and_clear_cpu(cpu, (struct cpumask *)cpumask);
}
/**
* bpf_cpumask_setall ( ) - Set all of the bits in a BPF cpumask .
* @ cpumask : The BPF cpumask having all of its bits set .
*/
__bpf_kfunc void bpf_cpumask_setall(struct bpf_cpumask *cpumask)
{
cpumask_setall((struct cpumask *)cpumask);
}
/**
* bpf_cpumask_clear ( ) - Clear all of the bits in a BPF cpumask .
* @ cpumask : The BPF cpumask being cleared .
*/
__bpf_kfunc void bpf_cpumask_clear(struct bpf_cpumask *cpumask)
{
cpumask_clear((struct cpumask *)cpumask);
}
/**
* bpf_cpumask_and ( ) - AND two cpumasks and store the result .
* @ dst : The BPF cpumask where the result is being stored .
* @ src1 : The first input .
* @ src2 : The second input .
*
* Return :
* * true - @ dst has at least one bit set following the operation
* * false - @ dst is empty following the operation
*
* struct bpf_cpumask pointers may be safely passed to @ src1 and @ src2 .
*/
__bpf_kfunc bool bpf_cpumask_and(struct bpf_cpumask *dst,
const struct cpumask *src1,
const struct cpumask *src2)
{
return cpumask_and((struct cpumask *)dst, src1, src2);
}
/**
* bpf_cpumask_or ( ) - OR two cpumasks and store the result .
* @ dst : The BPF cpumask where the result is being stored .
* @ src1 : The first input .
* @ src2 : The second input .
*
* struct bpf_cpumask pointers may be safely passed to @ src1 and @ src2 .
*/
__bpf_kfunc void bpf_cpumask_or(struct bpf_cpumask *dst,
const struct cpumask *src1,
const struct cpumask *src2)
{
cpumask_or((struct cpumask *)dst, src1, src2);
}
/**
* bpf_cpumask_xor ( ) - XOR two cpumasks and store the result .
* @ dst : The BPF cpumask where the result is being stored .
* @ src1 : The first input .
* @ src2 : The second input .
*
* struct bpf_cpumask pointers may be safely passed to @ src1 and @ src2 .
*/
__bpf_kfunc void bpf_cpumask_xor(struct bpf_cpumask *dst,
const struct cpumask *src1,
const struct cpumask *src2)
{
cpumask_xor((struct cpumask *)dst, src1, src2);
}
/**
* bpf_cpumask_equal ( ) - Check two cpumasks for equality .
* @ src1 : The first input .
* @ src2 : The second input .
*
* Return :
* * true - @ src1 and @ src2 have the same bits set .
* * false - @ src1 and @ src2 differ in at least one bit .
*
* struct bpf_cpumask pointers may be safely passed to @ src1 and @ src2 .
*/
__bpf_kfunc bool bpf_cpumask_equal(const struct cpumask *src1, const struct cpumask *src2)
{
return cpumask_equal(src1, src2);
}
/**
* bpf_cpumask_intersects ( ) - Check two cpumasks for overlap .
* @ src1 : The first input .
* @ src2 : The second input .
*
* Return :
* * true - @ src1 and @ src2 have at least one of the same bits set .
* * false - @ src1 and @ src2 don ' t have any of the same bits set .
*
* struct bpf_cpumask pointers may be safely passed to @ src1 and @ src2 .
*/
__bpf_kfunc bool bpf_cpumask_intersects(const struct cpumask *src1, const struct cpumask *src2)
{
return cpumask_intersects(src1, src2);
}
/**
* bpf_cpumask_subset ( ) - Check if a cpumask is a subset of another .
* @ src1 : The first cpumask being checked as a subset .
* @ src2 : The second cpumask being checked as a superset .
*
* Return :
* * true - All of the bits of @ src1 are set in @ src2 .
* * false - At least one bit in @ src1 is not set in @ src2 .
*
* struct bpf_cpumask pointers may be safely passed to @ src1 and @ src2 .
*/
__bpf_kfunc bool bpf_cpumask_subset(const struct cpumask *src1, const struct cpumask *src2)
{
return cpumask_subset(src1, src2);
}
/**
* bpf_cpumask_empty ( ) - Check if a cpumask is empty .
* @ cpumask : The cpumask being checked .
*
* Return :
* * true - None of the bits in @ cpumask are set .
* * false - At least one bit in @ cpumask is set .
*
* A struct bpf_cpumask pointer may be safely passed to @ cpumask .
*/
__bpf_kfunc bool bpf_cpumask_empty(const struct cpumask *cpumask)
{
return cpumask_empty(cpumask);
}
/**
* bpf_cpumask_full ( ) - Check if a cpumask has all bits set .
* @ cpumask : The cpumask being checked .
*
* Return :
* * true - All of the bits in @ cpumask are set .
* * false - At least one bit in @ cpumask is cleared .
*
* A struct bpf_cpumask pointer may be safely passed to @ cpumask .
*/
__bpf_kfunc bool bpf_cpumask_full(const struct cpumask *cpumask)
{
return cpumask_full(cpumask);
}
/**
* bpf_cpumask_copy ( ) - Copy the contents of a cpumask into a BPF cpumask .
* @ dst : The BPF cpumask being copied into .
* @ src : The cpumask being copied .
*
* A struct bpf_cpumask pointer may be safely passed to @ src .
*/
__bpf_kfunc void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src)
{
cpumask_copy((struct cpumask *)dst, src);
}
/**
* bpf_cpumask_any_distribute ( ) - Return a random set CPU from a cpumask .
* @ cpumask : The cpumask being queried .
*
* Return :
* * A random set bit within [ 0 , num_cpus ) if at least one bit is set .
* * > = num_cpus if no bit is set .
*
* A struct bpf_cpumask pointer may be safely passed to @ src .
*/
__bpf_kfunc u32 bpf_cpumask_any_distribute(const struct cpumask *cpumask)
{
return cpumask_any_distribute(cpumask);
}
/**
* bpf_cpumask_any_and_distribute ( ) - Return a random set CPU from the AND of
* two cpumasks .
* @ src1 : The first cpumask .
* @ src2 : The second cpumask .
*
* Return :
* * A random set bit within [ 0 , num_cpus ) from the AND of two cpumasks , if at
* least one bit is set .
* * > = num_cpus if no bit is set .
*
* struct bpf_cpumask pointers may be safely passed to @ src1 and @ src2 .
*/
__bpf_kfunc u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1,
const struct cpumask *src2)
{
return cpumask_any_and_distribute(src1, src2);
}
/**
* bpf_cpumask_weight ( ) - Return the number of bits in @ cpumask .
* @ cpumask : The cpumask being queried .
*
* Count the number of set bits in the given cpumask .
*
* Return :
* * The number of bits set in the mask .
*/
__bpf_kfunc u32 bpf_cpumask_weight(const struct cpumask *cpumask)
{
return cpumask_weight(cpumask);
}
/**
* bpf_cpumask_populate ( ) - Populate the CPU mask from the contents of
* a BPF memory region .
*
* @ cpumask : The cpumask being populated .
* @ src : The BPF memory holding the bit pattern .
* @ src__sz : Length of the BPF memory region in bytes .
*
* Return :
* * 0 if the struct cpumask * instance was populated successfully .
* * - EACCES if the memory region is too small to populate the cpumask .
* * - EINVAL if the memory region is not aligned to the size of a long
* and the architecture does not support efficient unaligned accesses .
*/
__bpf_kfunc int bpf_cpumask_populate(struct cpumask *cpumask, void *src, size_t src__sz)
{
unsigned long source = (unsigned long )src;
/* The memory region must be large enough to populate the entire CPU mask. */
if (src__sz < bitmap_size(nr_cpu_ids))
return -EACCES;
/* If avoiding unaligned accesses, the input region must be aligned to the nearest long. */
if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
!IS_ALIGNED(source, sizeof (long )))
return -EINVAL;
bitmap_copy(cpumask_bits(cpumask), src, nr_cpu_ids);
return 0 ;
}
__bpf_kfunc_end_defs();
BTF_KFUNCS_START(cpumask_kfunc_btf_ids)
BTF_ID_FLAGS(func, bpf_cpumask_create, KF_ACQUIRE | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_cpumask_release, KF_RELEASE)
BTF_ID_FLAGS(func, bpf_cpumask_acquire, KF_ACQUIRE | KF_TRUSTED_ARGS)
BTF_ID_FLAGS(func, bpf_cpumask_first, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_first_zero, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_first_and, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_set_cpu, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_clear_cpu, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_test_cpu, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_test_and_set_cpu, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_test_and_clear_cpu, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_setall, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_clear, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_and, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_or, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_xor, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_equal, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_intersects, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_subset, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_empty, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_full, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_copy, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_any_distribute, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_any_and_distribute, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_weight, KF_RCU)
BTF_ID_FLAGS(func, bpf_cpumask_populate, KF_RCU)
BTF_KFUNCS_END(cpumask_kfunc_btf_ids)
static const struct btf_kfunc_id_set cpumask_kfunc_set = {
.owner = THIS_MODULE,
.set = &cpumask_kfunc_btf_ids,
};
BTF_ID_LIST(cpumask_dtor_ids)
BTF_ID(struct , bpf_cpumask)
BTF_ID(func, bpf_cpumask_release_dtor)
static int __init cpumask_kfunc_init(void )
{
int ret;
const struct btf_id_dtor_kfunc cpumask_dtors[] = {
{
.btf_id = cpumask_dtor_ids[0 ],
.kfunc_btf_id = cpumask_dtor_ids[1 ]
},
};
ret = bpf_mem_alloc_init(&bpf_cpumask_ma, sizeof (struct bpf_cpumask), false );
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &cpumask_kfunc_set);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &cpumask_kfunc_set);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &cpumask_kfunc_set);
return ret ?: register_btf_id_dtor_kfuncs(cpumask_dtors,
ARRAY_SIZE(cpumask_dtors),
THIS_MODULE);
}
late_initcall(cpumask_kfunc_init);
Messung V0.5 in Prozent C=95 H=100 G=97
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland