From: Jiri Pirko Allow devlink_alloc_ns() to be called with dev=NULL to support device-less devlink instances. When dev is NULL, the instance is identified over netlink using "devlink_index" as bus_name and the decimal index value as dev_name. Signed-off-by: Jiri Pirko --- include/uapi/linux/devlink.h | 2 ++ net/devlink/core.c | 26 +++++++++++++++++++++----- net/devlink/dev.c | 11 +++++++---- net/devlink/devl_internal.h | 4 ++-- net/devlink/port.c | 14 +++++++++----- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index 1ba3436db4ae..7de2d8cc862f 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -19,6 +19,8 @@ #define DEVLINK_GENL_VERSION 0x1 #define DEVLINK_GENL_MCGRP_CONFIG_NAME "config" +#define DEVLINK_INDEX_BUS_NAME "devlink_index" + enum devlink_command { /* don't change the order or add anything between, this is ABI! */ DEVLINK_CMD_UNSPEC, diff --git a/net/devlink/core.c b/net/devlink/core.c index 85e83a3b082a..9cdda570e584 100644 --- a/net/devlink/core.c +++ b/net/devlink/core.c @@ -330,7 +330,10 @@ static void devlink_release(struct work_struct *work) mutex_destroy(&devlink->lock); lockdep_unregister_key(&devlink->lock_key); - put_device(devlink->dev); + if (devlink->dev) + put_device(devlink->dev); + else + kfree(devlink->dev_name); kvfree(devlink); } @@ -445,7 +448,7 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops, static u32 last_id; int ret; - WARN_ON(!ops || !dev); + WARN_ON(!ops); if (!devlink_reload_actions_valid(ops)) return NULL; @@ -453,14 +456,22 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops, if (!devlink) return NULL; + if (dev) { + devlink->dev = get_device(dev); + devlink->bus_name = dev->bus->name; + devlink->dev_name = dev_name(dev); + } else { + devlink->bus_name = DEVLINK_INDEX_BUS_NAME; + devlink->dev_name = kasprintf(GFP_KERNEL, "%u", devlink->index); + if (!devlink->dev_name) + goto err_kasprintf; + } + ret = xa_alloc_cyclic(&devlinks, &devlink->index, devlink, xa_limit_31b, &last_id, GFP_KERNEL); if (ret < 0) goto err_xa_alloc; - devlink->dev = get_device(dev); - devlink->bus_name = dev->bus->name; - devlink->dev_name = dev_name(dev); devlink->ops = ops; xa_init_flags(&devlink->ports, XA_FLAGS_ALLOC); xa_init_flags(&devlink->params, XA_FLAGS_ALLOC); @@ -486,6 +497,11 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops, return devlink; err_xa_alloc: + if (devlink->dev) + put_device(devlink->dev); + else + kfree(devlink->dev_name); +err_kasprintf: kvfree(devlink); return NULL; } diff --git a/net/devlink/dev.c b/net/devlink/dev.c index e3a36de4f4ae..b63597312bbd 100644 --- a/net/devlink/dev.c +++ b/net/devlink/dev.c @@ -453,7 +453,8 @@ int devlink_reload(struct devlink *devlink, struct net *dest_net, * (e.g., PCI reset) and to close possible races between these * operations and probe/remove. */ - device_lock_assert(devlink->dev); + if (devlink->dev) + device_lock_assert(devlink->dev); memcpy(remote_reload_stats, devlink->stats.remote_reload_stats, sizeof(remote_reload_stats)); @@ -892,9 +893,11 @@ devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink, goto err_cancel_msg; } - err = devlink_nl_driver_info_get(dev->driver, &req); - if (err) - goto err_cancel_msg; + if (dev) { + err = devlink_nl_driver_info_get(dev->driver, &req); + if (err) + goto err_cancel_msg; + } genlmsg_end(msg, hdr); return 0; diff --git a/net/devlink/devl_internal.h b/net/devlink/devl_internal.h index 67425c5d8cfc..89d08fd511cb 100644 --- a/net/devlink/devl_internal.h +++ b/net/devlink/devl_internal.h @@ -107,7 +107,7 @@ static inline bool devl_is_registered(struct devlink *devlink) static inline void devl_dev_lock(struct devlink *devlink, bool dev_lock) { - if (dev_lock) + if (dev_lock && devlink->dev) device_lock(devlink->dev); devl_lock(devlink); } @@ -115,7 +115,7 @@ static inline void devl_dev_lock(struct devlink *devlink, bool dev_lock) static inline void devl_dev_unlock(struct devlink *devlink, bool dev_lock) { devl_unlock(devlink); - if (dev_lock) + if (dev_lock && devlink->dev) device_unlock(devlink->dev); } diff --git a/net/devlink/port.c b/net/devlink/port.c index 1d4a79c6d4d3..f19b690ebe7e 100644 --- a/net/devlink/port.c +++ b/net/devlink/port.c @@ -976,7 +976,9 @@ static void devlink_port_type_warn(struct work_struct *work) struct devlink_port *port = container_of(to_delayed_work(work), struct devlink_port, type_warn_dw); - dev_warn(port->devlink->dev, "Type was not set for devlink port."); + if (port->devlink->dev) + dev_warn(port->devlink->dev, + "Type was not set for devlink port."); } static bool devlink_port_type_should_warn(struct devlink_port *devlink_port) @@ -1242,9 +1244,10 @@ static void __devlink_port_type_set(struct devlink_port *devlink_port, */ void devlink_port_type_eth_set(struct devlink_port *devlink_port) { - dev_warn(devlink_port->devlink->dev, - "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n", - devlink_port->index); + if (devlink_port->devlink->dev) + dev_warn(devlink_port->devlink->dev, + "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n", + devlink_port->index); __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, NULL); } EXPORT_SYMBOL_GPL(devlink_port_type_eth_set); @@ -1272,7 +1275,8 @@ EXPORT_SYMBOL_GPL(devlink_port_type_ib_set); */ void devlink_port_type_clear(struct devlink_port *devlink_port) { - if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) + if (devlink_port->type == DEVLINK_PORT_TYPE_ETH && + devlink_port->devlink->dev) dev_warn(devlink_port->devlink->dev, "devlink port type for port %d cleared without a software interface reference, device type not supported by the kernel?\n", devlink_port->index); -- 2.51.1