Hi all,
Today's linux-next merge of the bpf-next tree got a conflict in:
kernel/bpf/offload.c
between commit:
ef01f4e25c17 ("bpf: restore the ebpf program ID for BPF_AUDIT_UNLOAD and PERF_BPF_EVENT_PROG_UNLOAD")
from Linus' tree and commit:
89bbc53a4dbb ("bpf: Reshuffle some parts of bpf/offload.c")
from the bpf-next tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
--
Cheers,
Stephen Rothwell
diff --cc kernel/bpf/offload.c
index 190d9f9dc987,e87cab2ed710..000000000000
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@@ -75,20 -74,124 +74,121 @@@ bpf_offload_find_netdev(struct net_devi
return rhashtable_lookup_fast(&offdevs, &netdev, offdevs_params);
}
- int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
+ static int __bpf_offload_dev_netdev_register(struct bpf_offload_dev *offdev,
+ struct net_device *netdev)
{
struct bpf_offload_netdev *ondev;
- struct bpf_prog_offload *offload;
int err;
- if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS &&
- attr->prog_type != BPF_PROG_TYPE_XDP)
- return -EINVAL;
+ ondev = kzalloc(sizeof(*ondev), GFP_KERNEL);
+ if (!ondev)
+ return -ENOMEM;
- if (attr->prog_flags)
- return -EINVAL;
+ ondev->netdev = netdev;
+ ondev->offdev = offdev;
+ INIT_LIST_HEAD(&ondev->progs);
+ INIT_LIST_HEAD(&ondev->maps);
+
+ err = rhashtable_insert_fast(&offdevs, &ondev->l, offdevs_params);
+ if (err) {
+ netdev_warn(netdev, "failed to register for BPF offload\n");
+ goto err_free;
+ }
+
+ if (offdev)
+ list_add(&ondev->offdev_netdevs, &offdev->netdevs);
+ return 0;
+
+ err_free:
+ kfree(ondev);
+ return err;
+ }
+
+ static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
+ {
+ struct bpf_prog_offload *offload = prog->aux->offload;
+
+ if (offload->dev_state)
+ offload->offdev->ops->destroy(prog);
+
- /* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */
- bpf_prog_free_id(prog, true);
-
+ list_del_init(&offload->offloads);
+ kfree(offload);
+ prog->aux->offload = NULL;
+ }
+
+ static int bpf_map_offload_ndo(struct bpf_offloaded_map *offmap,
+ enum bpf_netdev_command cmd)
+ {
+ struct netdev_bpf data = {};
+ struct net_device *netdev;
+
+ ASSERT_RTNL();
+
+ data.command = cmd;
+ data.offmap = offmap;
+ /* Caller must make sure netdev is valid */
+ netdev = offmap->netdev;
+
+ return netdev->netdev_ops->ndo_bpf(netdev, &data);
+ }
+
+ static void __bpf_map_offload_destroy(struct bpf_offloaded_map *offmap)
+ {
+ WARN_ON(bpf_map_offload_ndo(offmap, BPF_OFFLOAD_MAP_FREE));
+ /* Make sure BPF_MAP_GET_NEXT_ID can't find this dead map */
+ bpf_map_free_id(&offmap->map, true);
+ list_del_init(&offmap->offloads);
+ offmap->netdev = NULL;
+ }
+
+ static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
+ struct net_device *netdev)
+ {
+ struct bpf_offload_netdev *ondev, *altdev = NULL;
+ struct bpf_offloaded_map *offmap, *mtmp;
+ struct bpf_prog_offload *offload, *ptmp;
+
+ ASSERT_RTNL();
+
+ ondev = rhashtable_lookup_fast(&offdevs, &netdev, offdevs_params);
+ if (WARN_ON(!ondev))
+ return;
+
+ WARN_ON(rhashtable_remove_fast(&offdevs, &ondev->l, offdevs_params));
+
+ /* Try to move the objects to another netdev of the device */
+ if (offdev) {
+ list_del(&ondev->offdev_netdevs);
+ altdev = list_first_entry_or_null(&offdev->netdevs,
+ struct bpf_offload_netdev,
+ offdev_netdevs);
+ }
+
+ if (altdev) {
+ list_for_each_entry(offload, &ondev->progs, offloads)
+ offload->netdev = altdev->netdev;
+ list_splice_init(&ondev->progs, &altdev->progs);
+
+ list_for_each_entry(offmap, &ondev->maps, offloads)
+ offmap->netdev = altdev->netdev;
+ list_splice_init(&ondev->maps, &altdev->maps);
+ } else {
+ list_for_each_entry_safe(offload, ptmp, &ondev->progs, offloads)
+ __bpf_prog_offload_destroy(offload->prog);
+ list_for_each_entry_safe(offmap, mtmp, &ondev->maps, offloads)
+ __bpf_map_offload_destroy(offmap);
+ }
+
+ WARN_ON(!list_empty(&ondev->progs));
+ WARN_ON(!list_empty(&ondev->maps));
+ kfree(ondev);
+ }
+
+ static int __bpf_prog_dev_bound_init(struct bpf_prog *prog, struct net_device *netdev)
+ {
+ struct bpf_offload_netdev *ondev;
+ struct bpf_prog_offload *offload;
+ int err;
offload = kzalloc(sizeof(*offload), GFP_USER);
if (!offload)
On Mon, Jan 23, 2023 at 2:44 PM Stephen Rothwell <[email protected]> wrote:
>
> Hi all,
>
> Today's linux-next merge of the bpf-next tree got a conflict in:
>
> kernel/bpf/offload.c
>
> between commit:
>
> ef01f4e25c17 ("bpf: restore the ebpf program ID for BPF_AUDIT_UNLOAD and PERF_BPF_EVENT_PROG_UNLOAD")
>
> from Linus' tree and commit:
>
> 89bbc53a4dbb ("bpf: Reshuffle some parts of bpf/offload.c")
>
> from the bpf-next tree.
>
> I fixed it up (see below) and can carry the fix as necessary. This
> is now fixed as far as linux-next is concerned, but any non trivial
> conflicts should be mentioned to your upstream maintainer when your tree
> is submitted for merging. You may also want to consider cooperating
> with the maintainer of the conflicting tree to minimise any particularly
> complex conflicts.
Yeah, that looks like a correct resolution, thank you!
Not sure what would've been the correct way to handle it in bpf-next
(except waiting for bpf tree to be merged)?
> --
> Cheers,
> Stephen Rothwell
>
> diff --cc kernel/bpf/offload.c
> index 190d9f9dc987,e87cab2ed710..000000000000
> --- a/kernel/bpf/offload.c
> +++ b/kernel/bpf/offload.c
> @@@ -75,20 -74,124 +74,121 @@@ bpf_offload_find_netdev(struct net_devi
> return rhashtable_lookup_fast(&offdevs, &netdev, offdevs_params);
> }
>
> - int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
> + static int __bpf_offload_dev_netdev_register(struct bpf_offload_dev *offdev,
> + struct net_device *netdev)
> {
> struct bpf_offload_netdev *ondev;
> - struct bpf_prog_offload *offload;
> int err;
>
> - if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS &&
> - attr->prog_type != BPF_PROG_TYPE_XDP)
> - return -EINVAL;
> + ondev = kzalloc(sizeof(*ondev), GFP_KERNEL);
> + if (!ondev)
> + return -ENOMEM;
>
> - if (attr->prog_flags)
> - return -EINVAL;
> + ondev->netdev = netdev;
> + ondev->offdev = offdev;
> + INIT_LIST_HEAD(&ondev->progs);
> + INIT_LIST_HEAD(&ondev->maps);
> +
> + err = rhashtable_insert_fast(&offdevs, &ondev->l, offdevs_params);
> + if (err) {
> + netdev_warn(netdev, "failed to register for BPF offload\n");
> + goto err_free;
> + }
> +
> + if (offdev)
> + list_add(&ondev->offdev_netdevs, &offdev->netdevs);
> + return 0;
> +
> + err_free:
> + kfree(ondev);
> + return err;
> + }
> +
> + static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
> + {
> + struct bpf_prog_offload *offload = prog->aux->offload;
> +
> + if (offload->dev_state)
> + offload->offdev->ops->destroy(prog);
> +
> - /* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */
> - bpf_prog_free_id(prog, true);
> -
> + list_del_init(&offload->offloads);
> + kfree(offload);
> + prog->aux->offload = NULL;
> + }
> +
> + static int bpf_map_offload_ndo(struct bpf_offloaded_map *offmap,
> + enum bpf_netdev_command cmd)
> + {
> + struct netdev_bpf data = {};
> + struct net_device *netdev;
> +
> + ASSERT_RTNL();
> +
> + data.command = cmd;
> + data.offmap = offmap;
> + /* Caller must make sure netdev is valid */
> + netdev = offmap->netdev;
> +
> + return netdev->netdev_ops->ndo_bpf(netdev, &data);
> + }
> +
> + static void __bpf_map_offload_destroy(struct bpf_offloaded_map *offmap)
> + {
> + WARN_ON(bpf_map_offload_ndo(offmap, BPF_OFFLOAD_MAP_FREE));
> + /* Make sure BPF_MAP_GET_NEXT_ID can't find this dead map */
> + bpf_map_free_id(&offmap->map, true);
> + list_del_init(&offmap->offloads);
> + offmap->netdev = NULL;
> + }
> +
> + static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
> + struct net_device *netdev)
> + {
> + struct bpf_offload_netdev *ondev, *altdev = NULL;
> + struct bpf_offloaded_map *offmap, *mtmp;
> + struct bpf_prog_offload *offload, *ptmp;
> +
> + ASSERT_RTNL();
> +
> + ondev = rhashtable_lookup_fast(&offdevs, &netdev, offdevs_params);
> + if (WARN_ON(!ondev))
> + return;
> +
> + WARN_ON(rhashtable_remove_fast(&offdevs, &ondev->l, offdevs_params));
> +
> + /* Try to move the objects to another netdev of the device */
> + if (offdev) {
> + list_del(&ondev->offdev_netdevs);
> + altdev = list_first_entry_or_null(&offdev->netdevs,
> + struct bpf_offload_netdev,
> + offdev_netdevs);
> + }
> +
> + if (altdev) {
> + list_for_each_entry(offload, &ondev->progs, offloads)
> + offload->netdev = altdev->netdev;
> + list_splice_init(&ondev->progs, &altdev->progs);
> +
> + list_for_each_entry(offmap, &ondev->maps, offloads)
> + offmap->netdev = altdev->netdev;
> + list_splice_init(&ondev->maps, &altdev->maps);
> + } else {
> + list_for_each_entry_safe(offload, ptmp, &ondev->progs, offloads)
> + __bpf_prog_offload_destroy(offload->prog);
> + list_for_each_entry_safe(offmap, mtmp, &ondev->maps, offloads)
> + __bpf_map_offload_destroy(offmap);
> + }
> +
> + WARN_ON(!list_empty(&ondev->progs));
> + WARN_ON(!list_empty(&ondev->maps));
> + kfree(ondev);
> + }
> +
> + static int __bpf_prog_dev_bound_init(struct bpf_prog *prog, struct net_device *netdev)
> + {
> + struct bpf_offload_netdev *ondev;
> + struct bpf_prog_offload *offload;
> + int err;
>
> offload = kzalloc(sizeof(*offload), GFP_USER);
> if (!offload)