hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9GZAQ CVE: NA
--------------------------------
Introduce the helper to process a series nodemask operations, such as 'nodes_empty', 'node_isset' etc.
Signed-off-by: Hui Tang tanghui20@huawei.com --- include/linux/sched.h | 22 +++++++ include/uapi/linux/bpf.h | 29 +++++++++ kernel/sched/bpf_sched.c | 71 ++++++++++++++++++++++ scripts/bpf_helpers_doc.py | 2 + tools/include/uapi/linux/bpf.h | 29 +++++++++ tools/lib/bpf/libbpf_sched.h | 107 +++++++++++++++++++++++++++++++++ 6 files changed, 260 insertions(+)
diff --git a/include/linux/sched.h b/include/linux/sched.h index 7ef4efd8cddb..3d5553f70401 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2378,6 +2378,28 @@ enum cpumask_op_type { CPUMASK_CPULIST_PARSE };
+enum nodemask_op_type { + NODEMASK_EMPTY, + NODEMASK_NODE_ISSET, + NODEMASK_NODES_CLEAR, + NODEMASK_NODE_SET, + NODEMASK_NODE_CLEAR, + NODEMASK_NODELIST_PARSE, + NODEMASK_TO_CPUMASK, + NODEMASK_NODES_ANDNOT, + NODEMASK_NODES_AND, + NODEMASK_NODES_OR, + NODEMASK_WEIGHT, + NODEMASK_ONLINE +}; + +struct nodemask_op_args { + enum nodemask_op_type op_type; + void *arg1; + void *arg2; + void *arg3; +}; + struct sched_migrate_ctx { struct task_struct *task; struct cpumask *select_idle_mask; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 2b11202c3439..e608b32d4c5a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -3874,6 +3874,34 @@ union bpf_attr { * check src_cpu whether share cache with dst_cpu. * Return * yes 1, no 0. + * + * int bpf_nodemask_op(struct nodemask_op_args *op, int len) + * Description + * A series of nodemask-related operations. Perform different + * operations base on *op*->type. User also need fill other + * *op* field base on *op*->type. *op*->type is one of them + * + * **NODEMASK_EMPTY** + * nodes_empty(op->arg1) returned. + * **NODEMASK_NODE_ISSET** + * node_isset(op->arg1, op->arg2) returned + * **NODEMASK_NODES_CLEAR** + * 0 returned + * **NODEMASK_NODE_CLEAR** + * unset op->arg1 from op->arg2, 0 returned + * **NODEMASK_NODE_SET** + * set op->arg1 to op->arg2, 0 returned + * **NODEMASK_WEIGHT** + * nodes_weight(op->arg1) returned + * **NODEMASK_NODELIST_PARSE** + * str *op->arg1* to nodemask_t *op->arg2*, + * 0 on success, or a negative error in case of failure. + * **NODEMASK_TO_CPUMASK** + * nodemask_t *arg1* to cpumask_t *op->arg2*, 0 returned. + * **NODEMASK_ONLINE** + * set online nodes to nodemask_t *op->arg1*, 0 returned. + * Return + * View above. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4046,6 +4074,7 @@ union bpf_attr { FN(sched_entity_to_tg), \ FN(cpumask_op), \ FN(cpus_share_cache), \ + FN(nodemask_op), \ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/sched/bpf_sched.c b/kernel/sched/bpf_sched.c index 220ba83fc5f4..a1e72533d5b6 100644 --- a/kernel/sched/bpf_sched.c +++ b/kernel/sched/bpf_sched.c @@ -260,6 +260,75 @@ static const struct bpf_func_proto bpf_cpumask_op_proto = { .arg2_type = ARG_CONST_SIZE, };
+BPF_CALL_2(bpf_nodemask_op, struct nodemask_op_args *, op, int, len) +{ + struct cpumask *cpumask; + nodemask_t mask; + int nid; + + if (len != sizeof(*op) || !op->arg1) + return -EINVAL; + + switch (op->op_type) { + case NODEMASK_EMPTY: + mask = *(nodemask_t *)op->arg1; + return nodes_empty(mask); + case NODEMASK_NODE_ISSET: + mask = *(nodemask_t *)op->arg2; + return node_isset(*(int *)op->arg1, mask); + case NODEMASK_NODES_CLEAR: + __nodes_clear((nodemask_t *)op->arg1, MAX_NUMNODES); + break; + case NODEMASK_NODE_CLEAR: + __node_clear(*(int *)op->arg1, (nodemask_t *)op->arg2); + break; + case NODEMASK_NODE_SET: + __node_set(*(int *)op->arg1, (nodemask_t *)op->arg2); + break; + case NODEMASK_NODES_AND: + __nodes_and((nodemask_t *)op->arg1, (nodemask_t *)op->arg2, + (nodemask_t *)op->arg3, MAX_NUMNODES); + break; + case NODEMASK_NODES_ANDNOT: + __nodes_andnot((nodemask_t *)op->arg1, (nodemask_t *)op->arg2, + (nodemask_t *)op->arg3, MAX_NUMNODES); + break; + case NODEMASK_NODES_OR: + __nodes_or((nodemask_t *)op->arg1, (nodemask_t *)op->arg2, + (nodemask_t *)op->arg3, MAX_NUMNODES); + break; + case NODEMASK_WEIGHT: + mask = *(nodemask_t *)op->arg1; + return nodes_weight(mask); + case NODEMASK_NODELIST_PARSE: + return __nodelist_parse((const char *)op->arg1, + (nodemask_t *)op->arg2, MAX_NUMNODES); + case NODEMASK_TO_CPUMASK: + mask = *(nodemask_t *)op->arg1; + cpumask = (struct cpumask *)op->arg2; + cpumask_clear(cpumask); + for_each_node_mask(nid, mask) { + cpumask_or(cpumask, cpumask, cpumask_of_node(nid)); + } + break; + case NODEMASK_ONLINE: + *(nodemask_t *)op->arg1 = node_online_map; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct bpf_func_proto bpf_nodemask_op_proto = { + .func = bpf_nodemask_op, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_MEM, + .arg2_type = ARG_CONST_SIZE, +}; + BPF_CALL_2(bpf_cpus_share_cache, int, src_cpu, int, dst_cpu) { if ((unsigned int)src_cpu >= nr_cpu_ids || @@ -299,6 +368,8 @@ bpf_sched_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_cpumask_op_proto; case BPF_FUNC_cpus_share_cache: return &bpf_cpus_share_cache_proto; + case BPF_FUNC_nodemask_op: + return &bpf_nodemask_op_proto; default: return bpf_base_func_proto(func_id); } diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py index 6001bcf66d5e..929a3031b4d6 100755 --- a/scripts/bpf_helpers_doc.py +++ b/scripts/bpf_helpers_doc.py @@ -445,6 +445,7 @@ class PrinterHelpers(Printer): 'struct sched_migrate_ctx', 'struct sched_affine_ctx', 'struct sched_migrate_node', + 'struct nodemask_op_args', ] known_types = { '...', @@ -498,6 +499,7 @@ class PrinterHelpers(Printer): 'struct sched_migrate_ctx', 'struct sched_affine_ctx', 'struct sched_migrate_node', + 'struct nodemask_op_args', } mapped_types = { 'u8': '__u8', diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e241f8d4becd..809723603ba8 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -3874,6 +3874,34 @@ union bpf_attr { * check src_cpu whether share cache with dst_cpu. * Return * true yes, false no. + * + * int bpf_nodemask_op(struct nodemask_op_args *op, int len) + * Description + * A series of nodemask-related operations. Perform different + * operations base on *op*->type. User also need fill other + * *op* field base on *op*->type. *op*->type is one of them + * + * **NODEMASK_EMPTY** + * nodes_empty(op->arg1) returned. + * **NODEMASK_NODE_ISSET** + * node_isset(op->arg1, op->arg2) returned + * **NODEMASK_NODES_CLEAR** + * 0 returned + * **NODEMASK_NODE_CLEAR** + * unset op->arg1 from op->arg2, 0 returned + * **NODEMASK_NODE_SET** + * set op->arg1 to op->arg2, 0 returned + * **NODEMASK_WEIGHT** + * nodes_weight(op->arg1) returned + * **NODEMASK_NODELIST_PARSE** + * str *op->arg1* to nodemask_t *op->arg2*, + * 0 on success, or a negative error in case of failure. + * **NODEMASK_TO_CPUMASK** + * nodemask_t *arg1* to cpumask_t *op->arg2*, 0 returned. + * **NODEMASK_ONLINE** + * set online nodes to nodemask_t *op->arg1*, 0 returned. + * Return + * View above. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4046,6 +4074,7 @@ union bpf_attr { FN(sched_entity_to_tg), \ FN(cpumask_op), \ FN(cpus_share_cache), \ + FN(nodemask_op), \ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/tools/lib/bpf/libbpf_sched.h b/tools/lib/bpf/libbpf_sched.h index 04b43c145fcd..7fa5f03e6ba4 100644 --- a/tools/lib/bpf/libbpf_sched.h +++ b/tools/lib/bpf/libbpf_sched.h @@ -16,6 +16,7 @@ #define __LIBBPF_LIBSCHED_H
#include <linux/bpf_topology.h> +#include <linux/numa.h> #include <linux/version.h> #include <uapi/linux/bpf.h> #include <bpf/bpf_helpers.h> @@ -78,6 +79,112 @@ struct { __uint(max_entries, 1); } map_cpumask_info SEC(".maps");
+static __always_inline void +libbpf_nodes_and(nodemask_t *dst, nodemask_t *src1, nodemask_t *src2) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_NODES_AND; + op.arg1 = dst; + op.arg2 = src1; + op.arg3 = src2; + bpf_nodemask_op(&op, sizeof(op)); +} + +static __always_inline void +libbpf_nodes_andnot(nodemask_t *dst, nodemask_t *src1, nodemask_t *src2) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_NODES_ANDNOT; + op.arg1 = dst; + op.arg2 = src1; + op.arg3 = src2; + bpf_nodemask_op(&op, sizeof(op)); +} + +static __always_inline void +libbpf_nodes_or(nodemask_t *dst, nodemask_t *src1, nodemask_t *src2) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_NODES_OR; + op.arg1 = dst; + op.arg2 = src1; + op.arg3 = src2; + bpf_nodemask_op(&op, sizeof(op)); +} + +static __always_inline void libbpf_node_set(int nid, + nodemask_t *nodes) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_NODE_SET; + op.arg1 = &nid; + op.arg2 = nodes; + op.arg3 = INVALID_PTR; + bpf_nodemask_op(&op, sizeof(op)); +} + +static __always_inline void libbpf_node_clear(int nid, + nodemask_t *nodes) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_NODE_CLEAR; + op.arg1 = &nid; + op.arg2 = nodes; + op.arg3 = INVALID_PTR; + bpf_nodemask_op(&op, sizeof(op)); +} + +static __always_inline long libbpf_node_isset(int nid, + nodemask_t *nodes) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_NODE_ISSET; + op.arg1 = &nid; + op.arg2 = nodes; + op.arg3 = INVALID_PTR; + return bpf_nodemask_op(&op, sizeof(op)); +} + +static __always_inline long libbpf_nodemask_empty(nodemask_t *nodes) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_EMPTY; + op.arg1 = nodes; + op.arg2 = INVALID_PTR; + op.arg3 = INVALID_PTR; + return bpf_nodemask_op(&op, sizeof(op)); +} + +static __always_inline long libbpf_nodemask_to_cpumask(nodemask_t *nodes, + struct cpumask *cpus) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_TO_CPUMASK; + op.arg1 = nodes; + op.arg2 = cpus; + op.arg3 = INVALID_PTR; + return bpf_nodemask_op(&op, sizeof(op)); +} + +static __always_inline long libbpf_nodes_online(nodemask_t *nodes) +{ + struct nodemask_op_args op = {0}; + + op.op_type = NODEMASK_ONLINE; + op.arg1 = nodes; + op.arg2 = INVALID_PTR; + op.arg3 = INVALID_PTR; + return bpf_nodemask_op(&op, sizeof(op)); +} + static __always_inline long libbpf_cpumask_copy(struct cpumask *dst, struct cpumask *src) {