Skip to content

Commit dda7704

Browse files
author
Martin KaFai Lau
committed
Merge branch 'Update and document struct_ops'
David Vernet says: ==================== The struct bpf_struct_ops structure in BPF is a framework that allows subsystems to extend themselves using BPF. In commit 68b0486 ("bpf: Create links for BPF struct_ops maps") and commit aef56f2 ("bpf: Update the struct_ops of a bpf_link"), the structure was updated to include new ->validate() and ->update() callbacks respectively in support of allowing struct_ops maps to be created with BPF_F_LINK. The intention was that struct bpf_struct_ops implementations could support map updates through the link. Because map validation and registration would take place in two separate steps for struct_ops maps managed by the link (the first in map update elem, and the latter in link create), the ->validate() callback was added, and any struct_ops implementation that wished to use BPF_F_LINK, even just for lifetime management, would then be required to define both it and ->update(). Not all struct_ops implementations can or will support update, however. For example, the sched_ext struct_ops implementation proposed in [0] will not be able to support atomic map updates because it can race with sysrq, has to cycle tasks through various states in order to safely transition, etc. It can, however, benefit from letting the BPF link automatically evict the struc_ops map when the application exits (e.g. if it crashes). This patch set therefore: 1. Updates the struct_ops implementation to support default values for ->validate() and ->update() so that struct_ops implementations can benefit from BPF_F_LINK management even if they can't support updates. 2. Documents struct bpf_struct_ops so that the semantics are clear and well defined. --- v2: https://lore.kernel.org/bpf/0f5ea3de-c6e7-490f-b5ec-b5c7cd288687@gmail.com/T/ Changes from v2 -> v3: - Add patch 2/2 that documents the struct bpf_struct_ops structure. - Add Kui-Feng's Acked-by tag to patch 1/2. v1: https://lore.kernel.org/lkml/20230811150934.GA542801@maniforge/ Changes from v1 -> v2: - Move the if (!st_map->st_ops->update) check outside of the critical section before we acquire the update_mutex. ==================== Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
2 parents ccd9a8b + bb48cf1 commit dda7704

2 files changed

Lines changed: 56 additions & 6 deletions

File tree

include/linux/bpf.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,53 @@ struct bpf_struct_ops_value;
15501550
struct btf_member;
15511551

15521552
#define BPF_STRUCT_OPS_MAX_NR_MEMBERS 64
1553+
/**
1554+
* struct bpf_struct_ops - A structure of callbacks allowing a subsystem to
1555+
* define a BPF_MAP_TYPE_STRUCT_OPS map type composed
1556+
* of BPF_PROG_TYPE_STRUCT_OPS progs.
1557+
* @verifier_ops: A structure of callbacks that are invoked by the verifier
1558+
* when determining whether the struct_ops progs in the
1559+
* struct_ops map are valid.
1560+
* @init: A callback that is invoked a single time, and before any other
1561+
* callback, to initialize the structure. A nonzero return value means
1562+
* the subsystem could not be initialized.
1563+
* @check_member: When defined, a callback invoked by the verifier to allow
1564+
* the subsystem to determine if an entry in the struct_ops map
1565+
* is valid. A nonzero return value means that the map is
1566+
* invalid and should be rejected by the verifier.
1567+
* @init_member: A callback that is invoked for each member of the struct_ops
1568+
* map to allow the subsystem to initialize the member. A nonzero
1569+
* value means the member could not be initialized. This callback
1570+
* is exclusive with the @type, @type_id, @value_type, and
1571+
* @value_id fields.
1572+
* @reg: A callback that is invoked when the struct_ops map has been
1573+
* initialized and is being attached to. Zero means the struct_ops map
1574+
* has been successfully registered and is live. A nonzero return value
1575+
* means the struct_ops map could not be registered.
1576+
* @unreg: A callback that is invoked when the struct_ops map should be
1577+
* unregistered.
1578+
* @update: A callback that is invoked when the live struct_ops map is being
1579+
* updated to contain new values. This callback is only invoked when
1580+
* the struct_ops map is loaded with BPF_F_LINK. If not defined, the
1581+
* it is assumed that the struct_ops map cannot be updated.
1582+
* @validate: A callback that is invoked after all of the members have been
1583+
* initialized. This callback should perform static checks on the
1584+
* map, meaning that it should either fail or succeed
1585+
* deterministically. A struct_ops map that has been validated may
1586+
* not necessarily succeed in being registered if the call to @reg
1587+
* fails. For example, a valid struct_ops map may be loaded, but
1588+
* then fail to be registered due to there being another active
1589+
* struct_ops map on the system in the subsystem already. For this
1590+
* reason, if this callback is not defined, the check is skipped as
1591+
* the struct_ops map will have final verification performed in
1592+
* @reg.
1593+
* @type: BTF type.
1594+
* @value_type: Value type.
1595+
* @name: The name of the struct bpf_struct_ops object.
1596+
* @func_models: Func models
1597+
* @type_id: BTF type id.
1598+
* @value_id: BTF value id.
1599+
*/
15531600
struct bpf_struct_ops {
15541601
const struct bpf_verifier_ops *verifier_ops;
15551602
int (*init)(struct btf *btf);

kernel/bpf/bpf_struct_ops.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -509,9 +509,12 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
509509
}
510510

511511
if (st_map->map.map_flags & BPF_F_LINK) {
512-
err = st_ops->validate(kdata);
513-
if (err)
514-
goto reset_unlock;
512+
err = 0;
513+
if (st_ops->validate) {
514+
err = st_ops->validate(kdata);
515+
if (err)
516+
goto reset_unlock;
517+
}
515518
set_memory_rox((long)st_map->image, 1);
516519
/* Let bpf_link handle registration & unregistration.
517520
*
@@ -663,9 +666,6 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
663666
if (attr->value_size != vt->size)
664667
return ERR_PTR(-EINVAL);
665668

666-
if (attr->map_flags & BPF_F_LINK && (!st_ops->validate || !st_ops->update))
667-
return ERR_PTR(-EOPNOTSUPP);
668-
669669
t = st_ops->type;
670670

671671
st_map_size = sizeof(*st_map) +
@@ -823,6 +823,9 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map
823823
if (!bpf_struct_ops_valid_to_reg(new_map))
824824
return -EINVAL;
825825

826+
if (!st_map->st_ops->update)
827+
return -EOPNOTSUPP;
828+
826829
mutex_lock(&update_mutex);
827830

828831
old_map = rcu_dereference_protected(st_link->map, lockdep_is_held(&update_mutex));

0 commit comments

Comments
 (0)