ethtool: runtime-resume netdev parent in ethnl_ops_begin

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2047636

commit d43c65b05b848e0b2db1a6c78b02c189da3a95b5
Author: Heiner Kallweit <hkallweit1@gmail.com>
Date:   Sun Aug 1 12:41:31 2021 +0200

    ethtool: runtime-resume netdev parent in ethnl_ops_begin

    If a network device is runtime-suspended then:
    - network device may be flagged as detached and all ethtool ops (even if not
      accessing the device) will fail because netif_device_present() returns
      false
    - ethtool ops may fail because device is not accessible (e.g. because being
      in D3 in case of a PCI device)

    It may not be desirable that userspace can't use even simple ethtool ops
    that not access the device if interface or link is down. To be more friendly
    to userspace let's ensure that device is runtime-resumed when executing the
    respective ethtool op in kernel.

    Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
This commit is contained in:
Ivan Vecera 2022-01-28 15:52:08 +01:00
parent 9017cfe4e1
commit 39ff8aaf30
1 changed files with 25 additions and 6 deletions

View File

@ -2,6 +2,7 @@
#include <net/sock.h>
#include <linux/ethtool_netlink.h>
#include <linux/pm_runtime.h>
#include "netlink.h"
static struct genl_family ethtool_genl_family;
@ -31,22 +32,40 @@ const struct nla_policy ethnl_header_policy_stats[] = {
int ethnl_ops_begin(struct net_device *dev)
{
int ret;
if (!dev)
return 0;
if (!netif_device_present(dev))
return -ENODEV;
if (dev->dev.parent)
pm_runtime_get_sync(dev->dev.parent);
if (dev->ethtool_ops->begin)
return dev->ethtool_ops->begin(dev);
else
return 0;
if (!netif_device_present(dev)) {
ret = -ENODEV;
goto err;
}
if (dev->ethtool_ops->begin) {
ret = dev->ethtool_ops->begin(dev);
if (ret)
goto err;
}
return 0;
err:
if (dev->dev.parent)
pm_runtime_put(dev->dev.parent);
return ret;
}
void ethnl_ops_complete(struct net_device *dev)
{
if (dev && dev->ethtool_ops->complete)
dev->ethtool_ops->complete(dev);
if (dev->dev.parent)
pm_runtime_put(dev->dev.parent);
}
/**