]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - net/core/devlink.c
devlink: Rework devlink health reporter destructor
[mirror_ubuntu-hirsute-kernel.git] / net / core / devlink.c
index 455998a576717d222bad1ca579af7de1d23915d2..b85f2113398d87de1026ffce74f4e2c4dc1e6b8d 100644 (file)
@@ -528,8 +528,14 @@ static int devlink_nl_port_attrs_put(struct sk_buff *msg,
 {
        struct devlink_port_attrs *attrs = &devlink_port->attrs;
 
-       if (!attrs->set)
+       if (!devlink_port->attrs_set)
                return 0;
+       if (attrs->lanes) {
+               if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
+                       return -EMSGSIZE;
+       }
+       if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
+               return -EMSGSIZE;
        if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
                return -EMSGSIZE;
        switch (devlink_port->attrs.flavour) {
@@ -583,7 +589,7 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por
 
        ops = devlink->ops;
        if (ops->port_function_hw_addr_get) {
-               int uninitialized_var(hw_addr_len);
+               int hw_addr_len;
                u8 hw_addr[MAX_ADDR_LEN];
 
                err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack);
@@ -934,6 +940,7 @@ static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
                                          struct genl_info *info)
 {
        struct devlink *devlink = info->user_ptr[0];
+       struct devlink_port *devlink_port;
        u32 port_index;
        u32 count;
 
@@ -941,8 +948,27 @@ static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
            !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
                return -EINVAL;
 
+       devlink_port = devlink_port_get_from_info(devlink, info);
        port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
        count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
+
+       if (IS_ERR(devlink_port))
+               return -EINVAL;
+
+       if (!devlink_port->attrs.splittable) {
+               /* Split ports cannot be split. */
+               if (devlink_port->attrs.split)
+                       NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split further");
+               else
+                       NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split");
+               return -EINVAL;
+       }
+
+       if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
+               NL_SET_ERR_MSG_MOD(info->extack, "Invalid split count");
+               return -EINVAL;
+       }
+
        return devlink_port_split(devlink, port_index, count, info->extack);
 }
 
@@ -5295,6 +5321,31 @@ devlink_health_reporter_find_by_name(struct devlink *devlink,
        return NULL;
 }
 
+static struct devlink_health_reporter *
+__devlink_health_reporter_create(struct devlink *devlink,
+                                const struct devlink_health_reporter_ops *ops,
+                                u64 graceful_period, void *priv)
+{
+       struct devlink_health_reporter *reporter;
+
+       if (WARN_ON(graceful_period && !ops->recover))
+               return ERR_PTR(-EINVAL);
+
+       reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
+       if (!reporter)
+               return ERR_PTR(-ENOMEM);
+
+       reporter->priv = priv;
+       reporter->ops = ops;
+       reporter->devlink = devlink;
+       reporter->graceful_period = graceful_period;
+       reporter->auto_recover = !!ops->recover;
+       reporter->auto_dump = !!ops->dump;
+       mutex_init(&reporter->dump_lock);
+       refcount_set(&reporter->refcount, 1);
+       return reporter;
+}
+
 /**
  *     devlink_health_reporter_create - create devlink health reporter
  *
@@ -5316,25 +5367,11 @@ devlink_health_reporter_create(struct devlink *devlink,
                goto unlock;
        }
 
-       if (WARN_ON(graceful_period && !ops->recover)) {
-               reporter = ERR_PTR(-EINVAL);
-               goto unlock;
-       }
-
-       reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
-       if (!reporter) {
-               reporter = ERR_PTR(-ENOMEM);
+       reporter = __devlink_health_reporter_create(devlink, ops,
+                                                   graceful_period, priv);
+       if (IS_ERR(reporter))
                goto unlock;
-       }
 
-       reporter->priv = priv;
-       reporter->ops = ops;
-       reporter->devlink = devlink;
-       reporter->graceful_period = graceful_period;
-       reporter->auto_recover = !!ops->recover;
-       reporter->auto_dump = !!ops->dump;
-       mutex_init(&reporter->dump_lock);
-       refcount_set(&reporter->refcount, 1);
        list_add_tail(&reporter->list, &devlink->reporter_list);
 unlock:
        mutex_unlock(&devlink->reporters_lock);
@@ -5342,6 +5379,29 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
 
+static void
+devlink_health_reporter_free(struct devlink_health_reporter *reporter)
+{
+       mutex_destroy(&reporter->dump_lock);
+       if (reporter->dump_fmsg)
+               devlink_fmsg_free(reporter->dump_fmsg);
+       kfree(reporter);
+}
+
+static void
+devlink_health_reporter_put(struct devlink_health_reporter *reporter)
+{
+       if (refcount_dec_and_test(&reporter->refcount))
+               devlink_health_reporter_free(reporter);
+}
+
+static void
+__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
+{
+       list_del(&reporter->list);
+       devlink_health_reporter_put(reporter);
+}
+
 /**
  *     devlink_health_reporter_destroy - destroy devlink health reporter
  *
@@ -5351,14 +5411,8 @@ void
 devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
 {
        mutex_lock(&reporter->devlink->reporters_lock);
-       list_del(&reporter->list);
+       __devlink_health_reporter_destroy(reporter);
        mutex_unlock(&reporter->devlink->reporters_lock);
-       while (refcount_read(&reporter->refcount) > 1)
-               msleep(100);
-       mutex_destroy(&reporter->dump_lock);
-       if (reporter->dump_fmsg)
-               devlink_fmsg_free(reporter->dump_fmsg);
-       kfree(reporter);
 }
 EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
 
@@ -5628,12 +5682,6 @@ unlock:
        return NULL;
 }
 
-static void
-devlink_health_reporter_put(struct devlink_health_reporter *reporter)
-{
-       refcount_dec(&reporter->refcount);
-}
-
 void
 devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
                                     enum devlink_health_reporter_state state)
@@ -7510,24 +7558,20 @@ void devlink_port_type_clear(struct devlink_port *devlink_port)
 EXPORT_SYMBOL_GPL(devlink_port_type_clear);
 
 static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
-                                   enum devlink_port_flavour flavour,
-                                   const unsigned char *switch_id,
-                                   unsigned char switch_id_len)
+                                   enum devlink_port_flavour flavour)
 {
        struct devlink_port_attrs *attrs = &devlink_port->attrs;
 
        if (WARN_ON(devlink_port->registered))
                return -EEXIST;
-       attrs->set = true;
+       devlink_port->attrs_set = true;
        attrs->flavour = flavour;
-       if (switch_id) {
-               attrs->switch_port = true;
-               if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
-                       switch_id_len = MAX_PHYS_ITEM_ID_LEN;
-               memcpy(attrs->switch_id.id, switch_id, switch_id_len);
-               attrs->switch_id.id_len = switch_id_len;
+       if (attrs->switch_id.id_len) {
+               devlink_port->switch_port = true;
+               if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
+                       attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
        } else {
-               attrs->switch_port = false;
+               devlink_port->switch_port = false;
        }
        return 0;
 }
@@ -7536,33 +7580,18 @@ static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
  *     devlink_port_attrs_set - Set port attributes
  *
  *     @devlink_port: devlink port
- *     @flavour: flavour of the port
- *     @port_number: number of the port that is facing user, for example
- *                   the front panel port number
- *     @split: indicates if this is split port
- *     @split_subport_number: if the port is split, this is the number
- *                            of subport.
- *     @switch_id: if the port is part of switch, this is buffer with ID,
- *                 otwerwise this is NULL
- *     @switch_id_len: length of the switch_id buffer
+ *     @attrs: devlink port attrs
  */
 void devlink_port_attrs_set(struct devlink_port *devlink_port,
-                           enum devlink_port_flavour flavour,
-                           u32 port_number, bool split,
-                           u32 split_subport_number,
-                           const unsigned char *switch_id,
-                           unsigned char switch_id_len)
+                           struct devlink_port_attrs *attrs)
 {
-       struct devlink_port_attrs *attrs = &devlink_port->attrs;
        int ret;
 
-       ret = __devlink_port_attrs_set(devlink_port, flavour,
-                                      switch_id, switch_id_len);
+       devlink_port->attrs = *attrs;
+       ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
        if (ret)
                return;
-       attrs->split = split;
-       attrs->phys.port_number = port_number;
-       attrs->phys.split_subport_number = split_subport_number;
+       WARN_ON(attrs->splittable && attrs->split);
 }
 EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
 
@@ -7571,20 +7600,14 @@ EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
  *
  *     @devlink_port: devlink port
  *     @pf: associated PF for the devlink port instance
- *     @switch_id: if the port is part of switch, this is buffer with ID,
- *                 otherwise this is NULL
- *     @switch_id_len: length of the switch_id buffer
  */
-void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port,
-                                  const unsigned char *switch_id,
-                                  unsigned char switch_id_len, u16 pf)
+void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u16 pf)
 {
        struct devlink_port_attrs *attrs = &devlink_port->attrs;
        int ret;
 
        ret = __devlink_port_attrs_set(devlink_port,
-                                      DEVLINK_PORT_FLAVOUR_PCI_PF,
-                                      switch_id, switch_id_len);
+                                      DEVLINK_PORT_FLAVOUR_PCI_PF);
        if (ret)
                return;
 
@@ -7598,21 +7621,15 @@ EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
  *     @devlink_port: devlink port
  *     @pf: associated PF for the devlink port instance
  *     @vf: associated VF of a PF for the devlink port instance
- *     @switch_id: if the port is part of switch, this is buffer with ID,
- *                 otherwise this is NULL
- *     @switch_id_len: length of the switch_id buffer
  */
 void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port,
-                                  const unsigned char *switch_id,
-                                  unsigned char switch_id_len,
                                   u16 pf, u16 vf)
 {
        struct devlink_port_attrs *attrs = &devlink_port->attrs;
        int ret;
 
        ret = __devlink_port_attrs_set(devlink_port,
-                                      DEVLINK_PORT_FLAVOUR_PCI_VF,
-                                      switch_id, switch_id_len);
+                                      DEVLINK_PORT_FLAVOUR_PCI_VF);
        if (ret)
                return;
        attrs->pci_vf.pf = pf;
@@ -7626,7 +7643,7 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
        struct devlink_port_attrs *attrs = &devlink_port->attrs;
        int n = 0;
 
-       if (!attrs->set)
+       if (!devlink_port->attrs_set)
                return -EOPNOTSUPP;
 
        switch (attrs->flavour) {
@@ -9461,7 +9478,7 @@ int devlink_compat_switch_id_get(struct net_device *dev,
         * any devlink lock as only permanent values are accessed.
         */
        devlink_port = netdev_to_devlink_port(dev);
-       if (!devlink_port || !devlink_port->attrs.switch_port)
+       if (!devlink_port || !devlink_port->switch_port)
                return -EOPNOTSUPP;
 
        memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));