mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
net: ethtool: try to protect all callback with netdev instance lock
Protect all ethtool callbacks and PHY related state with the netdev instance lock, for drivers which want / need to have their ops instance-locked. Basically take the lock everywhere we take rtnl_lock. It was tempting to take the lock in ethnl_ops_begin(), but turns out we actually nest those calls (when generating notifications). Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com> Cc: Saeed Mahameed <saeed@kernel.org> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20250305163732.2766420-11-sdf@fomichev.me Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
97246d6d21
commit
2bcf4772e4
11 changed files with 82 additions and 26 deletions
|
@ -107,10 +107,8 @@ nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch)
|
||||||
struct netdevsim *ns = netdev_priv(dev);
|
struct netdevsim *ns = netdev_priv(dev);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
netdev_lock(dev);
|
|
||||||
err = netif_set_real_num_queues(dev, ch->combined_count,
|
err = netif_set_real_num_queues(dev, ch->combined_count,
|
||||||
ch->combined_count);
|
ch->combined_count);
|
||||||
netdev_unlock(dev);
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,9 @@ static int dsa_conduit_get_regs_len(struct net_device *dev)
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (ops->get_regs_len) {
|
if (ops->get_regs_len) {
|
||||||
|
netdev_lock_ops(dev);
|
||||||
len = ops->get_regs_len(dev);
|
len = ops->get_regs_len(dev);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
return len;
|
return len;
|
||||||
ret += len;
|
ret += len;
|
||||||
|
@ -57,11 +59,15 @@ static void dsa_conduit_get_regs(struct net_device *dev,
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (ops->get_regs_len && ops->get_regs) {
|
if (ops->get_regs_len && ops->get_regs) {
|
||||||
|
netdev_lock_ops(dev);
|
||||||
len = ops->get_regs_len(dev);
|
len = ops->get_regs_len(dev);
|
||||||
if (len < 0)
|
if (len < 0) {
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
regs->len = len;
|
regs->len = len;
|
||||||
ops->get_regs(dev, regs, data);
|
ops->get_regs(dev, regs, data);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
data += regs->len;
|
data += regs->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +97,10 @@ static void dsa_conduit_get_ethtool_stats(struct net_device *dev,
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (ops->get_sset_count && ops->get_ethtool_stats) {
|
if (ops->get_sset_count && ops->get_ethtool_stats) {
|
||||||
|
netdev_lock_ops(dev);
|
||||||
count = ops->get_sset_count(dev, ETH_SS_STATS);
|
count = ops->get_sset_count(dev, ETH_SS_STATS);
|
||||||
ops->get_ethtool_stats(dev, stats, data);
|
ops->get_ethtool_stats(dev, stats, data);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ds->ops->get_ethtool_stats)
|
if (ds->ops->get_ethtool_stats)
|
||||||
|
@ -114,8 +122,10 @@ static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev,
|
||||||
if (count >= 0)
|
if (count >= 0)
|
||||||
phy_ethtool_get_stats(dev->phydev, stats, data);
|
phy_ethtool_get_stats(dev->phydev, stats, data);
|
||||||
} else if (ops->get_sset_count && ops->get_ethtool_phy_stats) {
|
} else if (ops->get_sset_count && ops->get_ethtool_phy_stats) {
|
||||||
|
netdev_lock_ops(dev);
|
||||||
count = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
|
count = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
|
||||||
ops->get_ethtool_phy_stats(dev, stats, data);
|
ops->get_ethtool_phy_stats(dev, stats, data);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
|
@ -132,11 +142,13 @@ static int dsa_conduit_get_sset_count(struct net_device *dev, int sset)
|
||||||
struct dsa_switch *ds = cpu_dp->ds;
|
struct dsa_switch *ds = cpu_dp->ds;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
netdev_lock_ops(dev);
|
||||||
if (sset == ETH_SS_PHY_STATS && dev->phydev &&
|
if (sset == ETH_SS_PHY_STATS && dev->phydev &&
|
||||||
!ops->get_ethtool_phy_stats)
|
!ops->get_ethtool_phy_stats)
|
||||||
count = phy_ethtool_get_sset_count(dev->phydev);
|
count = phy_ethtool_get_sset_count(dev->phydev);
|
||||||
else if (ops->get_sset_count)
|
else if (ops->get_sset_count)
|
||||||
count = ops->get_sset_count(dev, sset);
|
count = ops->get_sset_count(dev, sset);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
|
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
count = 0;
|
count = 0;
|
||||||
|
@ -163,6 +175,7 @@ static void dsa_conduit_get_strings(struct net_device *dev, uint32_t stringset,
|
||||||
/* We do not want to be NULL-terminated, since this is a prefix */
|
/* We do not want to be NULL-terminated, since this is a prefix */
|
||||||
pfx[sizeof(pfx) - 1] = '_';
|
pfx[sizeof(pfx) - 1] = '_';
|
||||||
|
|
||||||
|
netdev_lock_ops(dev);
|
||||||
if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
|
if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
|
||||||
!ops->get_ethtool_phy_stats) {
|
!ops->get_ethtool_phy_stats) {
|
||||||
mcount = phy_ethtool_get_sset_count(dev->phydev);
|
mcount = phy_ethtool_get_sset_count(dev->phydev);
|
||||||
|
@ -176,6 +189,7 @@ static void dsa_conduit_get_strings(struct net_device *dev, uint32_t stringset,
|
||||||
mcount = 0;
|
mcount = 0;
|
||||||
ops->get_strings(dev, stringset, data);
|
ops->get_strings(dev, stringset, data);
|
||||||
}
|
}
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
|
|
||||||
if (ds->ops->get_strings) {
|
if (ds->ops->get_strings) {
|
||||||
ndata = data + mcount * len;
|
ndata = data + mcount * len;
|
||||||
|
|
|
@ -72,23 +72,24 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
|
||||||
dev = req_info.dev;
|
dev = req_info.dev;
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(dev);
|
||||||
phydev = ethnl_req_get_phydev(&req_info,
|
phydev = ethnl_req_get_phydev(&req_info,
|
||||||
tb[ETHTOOL_A_CABLE_TEST_HEADER],
|
tb[ETHTOOL_A_CABLE_TEST_HEADER],
|
||||||
info->extack);
|
info->extack);
|
||||||
if (IS_ERR_OR_NULL(phydev)) {
|
if (IS_ERR_OR_NULL(phydev)) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ops = ethtool_phy_ops;
|
ops = ethtool_phy_ops;
|
||||||
if (!ops || !ops->start_cable_test) {
|
if (!ops || !ops->start_cable_test) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ethnl_ops_begin(dev);
|
ret = ethnl_ops_begin(dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = ops->start_cable_test(phydev, info->extack);
|
ret = ops->start_cable_test(phydev, info->extack);
|
||||||
|
|
||||||
|
@ -97,7 +98,8 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ethnl_cable_test_started(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
|
ethnl_cable_test_started(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
|
||||||
|
|
||||||
out_rtnl:
|
out_unlock:
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
ethnl_parse_header_dev_put(&req_info);
|
ethnl_parse_header_dev_put(&req_info);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -339,23 +341,24 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
|
||||||
goto out_dev_put;
|
goto out_dev_put;
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(dev);
|
||||||
phydev = ethnl_req_get_phydev(&req_info,
|
phydev = ethnl_req_get_phydev(&req_info,
|
||||||
tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
|
tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
|
||||||
info->extack);
|
info->extack);
|
||||||
if (IS_ERR_OR_NULL(phydev)) {
|
if (IS_ERR_OR_NULL(phydev)) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ops = ethtool_phy_ops;
|
ops = ethtool_phy_ops;
|
||||||
if (!ops || !ops->start_cable_test_tdr) {
|
if (!ops || !ops->start_cable_test_tdr) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ethnl_ops_begin(dev);
|
ret = ethnl_ops_begin(dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = ops->start_cable_test_tdr(phydev, info->extack, &cfg);
|
ret = ops->start_cable_test_tdr(phydev, info->extack, &cfg);
|
||||||
|
|
||||||
|
@ -365,7 +368,8 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info)
|
||||||
ethnl_cable_test_started(phydev,
|
ethnl_cable_test_started(phydev,
|
||||||
ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
|
ETHTOOL_MSG_CABLE_TEST_TDR_NTF);
|
||||||
|
|
||||||
out_rtnl:
|
out_unlock:
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
out_dev_put:
|
out_dev_put:
|
||||||
ethnl_parse_header_dev_put(&req_info);
|
ethnl_parse_header_dev_put(&req_info);
|
||||||
|
|
|
@ -418,8 +418,13 @@ cmis_fw_update_commit_image(struct ethtool_cmis_cdb *cdb,
|
||||||
static int cmis_fw_update_reset(struct net_device *dev)
|
static int cmis_fw_update_reset(struct net_device *dev)
|
||||||
{
|
{
|
||||||
__u32 reset_data = ETH_RESET_PHY;
|
__u32 reset_data = ETH_RESET_PHY;
|
||||||
|
int ret;
|
||||||
|
|
||||||
return dev->ethtool_ops->reset(dev, &reset_data);
|
netdev_lock_ops(dev);
|
||||||
|
ret = dev->ethtool_ops->reset(dev, &reset_data);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -234,9 +234,10 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
|
||||||
dev = req_info.dev;
|
dev = req_info.dev;
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(dev);
|
||||||
ret = ethnl_ops_begin(dev);
|
ret = ethnl_ops_begin(dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
ethnl_features_to_bitmap(old_active, dev->features);
|
ethnl_features_to_bitmap(old_active, dev->features);
|
||||||
ethnl_features_to_bitmap(old_wanted, dev->wanted_features);
|
ethnl_features_to_bitmap(old_wanted, dev->wanted_features);
|
||||||
ret = ethnl_parse_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
|
ret = ethnl_parse_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
|
||||||
|
@ -286,7 +287,8 @@ int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
|
||||||
out_ops:
|
out_ops:
|
||||||
ethnl_ops_complete(dev);
|
ethnl_ops_complete(dev);
|
||||||
out_rtnl:
|
out_unlock:
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
ethnl_parse_header_dev_put(&req_info);
|
ethnl_parse_header_dev_put(&req_info);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -2317,6 +2317,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
|
||||||
*/
|
*/
|
||||||
busy = true;
|
busy = true;
|
||||||
netdev_hold(dev, &dev_tracker, GFP_KERNEL);
|
netdev_hold(dev, &dev_tracker, GFP_KERNEL);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
|
@ -2331,8 +2332,10 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(dev);
|
||||||
rc = ops->set_phys_id(dev,
|
rc = ops->set_phys_id(dev,
|
||||||
(i++ & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
|
(i++ & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
if (rc)
|
if (rc)
|
||||||
break;
|
break;
|
||||||
|
@ -2341,6 +2344,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(dev);
|
||||||
netdev_put(dev, &dev_tracker);
|
netdev_put(dev, &dev_tracker);
|
||||||
busy = false;
|
busy = false;
|
||||||
|
|
||||||
|
@ -3140,6 +3144,7 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netdev_lock_ops(dev);
|
||||||
if (dev->dev.parent)
|
if (dev->dev.parent)
|
||||||
pm_runtime_get_sync(dev->dev.parent);
|
pm_runtime_get_sync(dev->dev.parent);
|
||||||
|
|
||||||
|
@ -3373,6 +3378,7 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
|
||||||
out:
|
out:
|
||||||
if (dev->dev.parent)
|
if (dev->dev.parent)
|
||||||
pm_runtime_put(dev->dev.parent);
|
pm_runtime_put(dev->dev.parent);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,19 +419,21 @@ int ethnl_act_module_fw_flash(struct sk_buff *skb, struct genl_info *info)
|
||||||
dev = req_info.dev;
|
dev = req_info.dev;
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(dev);
|
||||||
ret = ethnl_ops_begin(dev);
|
ret = ethnl_ops_begin(dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = ethnl_module_fw_flash_validate(dev, info->extack);
|
ret = ethnl_module_fw_flash_validate(dev, info->extack);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_rtnl;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = module_flash_fw(dev, tb, skb, info);
|
ret = module_flash_fw(dev, tb, skb, info);
|
||||||
|
|
||||||
ethnl_ops_complete(dev);
|
ethnl_ops_complete(dev);
|
||||||
|
|
||||||
out_rtnl:
|
out_unlock:
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
ethnl_parse_header_dev_put(&req_info);
|
ethnl_parse_header_dev_put(&req_info);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -90,6 +90,8 @@ int ethnl_ops_begin(struct net_device *dev)
|
||||||
if (dev->dev.parent)
|
if (dev->dev.parent)
|
||||||
pm_runtime_get_sync(dev->dev.parent);
|
pm_runtime_get_sync(dev->dev.parent);
|
||||||
|
|
||||||
|
netdev_ops_assert_locked(dev);
|
||||||
|
|
||||||
if (!netif_device_present(dev) ||
|
if (!netif_device_present(dev) ||
|
||||||
dev->reg_state >= NETREG_UNREGISTERING) {
|
dev->reg_state >= NETREG_UNREGISTERING) {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
|
@ -490,7 +492,11 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
ethnl_init_reply_data(reply_data, ops, req_info->dev);
|
ethnl_init_reply_data(reply_data, ops, req_info->dev);
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
if (req_info->dev)
|
||||||
|
netdev_lock_ops(req_info->dev);
|
||||||
ret = ops->prepare_data(req_info, reply_data, info);
|
ret = ops->prepare_data(req_info, reply_data, info);
|
||||||
|
if (req_info->dev)
|
||||||
|
netdev_unlock_ops(req_info->dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_cleanup;
|
goto err_cleanup;
|
||||||
|
@ -548,7 +554,9 @@ static int ethnl_default_dump_one(struct sk_buff *skb, struct net_device *dev,
|
||||||
|
|
||||||
ethnl_init_reply_data(ctx->reply_data, ctx->ops, dev);
|
ethnl_init_reply_data(ctx->reply_data, ctx->ops, dev);
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(ctx->req_info->dev);
|
||||||
ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, info);
|
ret = ctx->ops->prepare_data(ctx->req_info, ctx->reply_data, info);
|
||||||
|
netdev_unlock_ops(ctx->req_info->dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -693,6 +701,7 @@ static int ethnl_default_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
dev = req_info.dev;
|
dev = req_info.dev;
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(dev);
|
||||||
dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
|
dev->cfg_pending = kmemdup(dev->cfg, sizeof(*dev->cfg),
|
||||||
GFP_KERNEL_ACCOUNT);
|
GFP_KERNEL_ACCOUNT);
|
||||||
if (!dev->cfg_pending) {
|
if (!dev->cfg_pending) {
|
||||||
|
@ -720,6 +729,7 @@ out_free_cfg:
|
||||||
kfree(dev->cfg_pending);
|
kfree(dev->cfg_pending);
|
||||||
out_tie_cfg:
|
out_tie_cfg:
|
||||||
dev->cfg_pending = dev->cfg;
|
dev->cfg_pending = dev->cfg;
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
out_dev:
|
out_dev:
|
||||||
ethnl_parse_header_dev_put(&req_info);
|
ethnl_parse_header_dev_put(&req_info);
|
||||||
|
@ -777,6 +787,8 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
|
||||||
req_info->dev = dev;
|
req_info->dev = dev;
|
||||||
req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
|
req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||||
|
|
||||||
|
netdev_ops_assert_locked(dev);
|
||||||
|
|
||||||
ethnl_init_reply_data(reply_data, ops, dev);
|
ethnl_init_reply_data(reply_data, ops, dev);
|
||||||
ret = ops->prepare_data(req_info, reply_data, &info);
|
ret = ops->prepare_data(req_info, reply_data, &info);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -158,18 +158,19 @@ int ethnl_phy_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
netdev_lock_ops(req_info.base.dev);
|
||||||
|
|
||||||
ret = ethnl_phy_parse_request(&req_info.base, tb, info->extack);
|
ret = ethnl_phy_parse_request(&req_info.base, tb, info->extack);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_unlock_rtnl;
|
goto err_unlock;
|
||||||
|
|
||||||
/* No PHY, return early */
|
/* No PHY, return early */
|
||||||
if (!req_info.pdn)
|
if (!req_info.pdn)
|
||||||
goto err_unlock_rtnl;
|
goto err_unlock;
|
||||||
|
|
||||||
ret = ethnl_phy_reply_size(&req_info.base, info->extack);
|
ret = ethnl_phy_reply_size(&req_info.base, info->extack);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_unlock_rtnl;
|
goto err_unlock;
|
||||||
reply_len = ret + ethnl_reply_header_size();
|
reply_len = ret + ethnl_reply_header_size();
|
||||||
|
|
||||||
rskb = ethnl_reply_init(reply_len, req_info.base.dev,
|
rskb = ethnl_reply_init(reply_len, req_info.base.dev,
|
||||||
|
@ -178,13 +179,14 @@ int ethnl_phy_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
info, &reply_payload);
|
info, &reply_payload);
|
||||||
if (!rskb) {
|
if (!rskb) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_unlock_rtnl;
|
goto err_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ethnl_phy_fill_reply(&req_info.base, rskb);
|
ret = ethnl_phy_fill_reply(&req_info.base, rskb);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_free_msg;
|
goto err_free_msg;
|
||||||
|
|
||||||
|
netdev_unlock_ops(req_info.base.dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
ethnl_parse_header_dev_put(&req_info.base);
|
ethnl_parse_header_dev_put(&req_info.base);
|
||||||
genlmsg_end(rskb, reply_payload);
|
genlmsg_end(rskb, reply_payload);
|
||||||
|
@ -193,7 +195,8 @@ int ethnl_phy_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
|
||||||
err_free_msg:
|
err_free_msg:
|
||||||
nlmsg_free(rskb);
|
nlmsg_free(rskb);
|
||||||
err_unlock_rtnl:
|
err_unlock:
|
||||||
|
netdev_unlock_ops(req_info.base.dev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
ethnl_parse_header_dev_put(&req_info.base);
|
ethnl_parse_header_dev_put(&req_info.base);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -290,10 +293,15 @@ int ethnl_phy_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
|
||||||
if (ctx->phy_req_info->base.dev) {
|
if (ctx->phy_req_info->base.dev) {
|
||||||
ret = ethnl_phy_dump_one_dev(skb, ctx->phy_req_info->base.dev, cb);
|
dev = ctx->phy_req_info->base.dev;
|
||||||
|
netdev_lock_ops(dev);
|
||||||
|
ret = ethnl_phy_dump_one_dev(skb, dev, cb);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
} else {
|
} else {
|
||||||
for_each_netdev_dump(net, dev, ctx->ifindex) {
|
for_each_netdev_dump(net, dev, ctx->ifindex) {
|
||||||
|
netdev_lock_ops(dev);
|
||||||
ret = ethnl_phy_dump_one_dev(skb, dev, cb);
|
ret = ethnl_phy_dump_one_dev(skb, dev, cb);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -345,7 +345,9 @@ int ethnl_rss_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
if (ctx->match_ifindex && ctx->match_ifindex != ctx->ifindex)
|
if (ctx->match_ifindex && ctx->match_ifindex != ctx->ifindex)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
netdev_lock_ops(dev);
|
||||||
ret = rss_dump_one_dev(skb, cb, dev);
|
ret = rss_dump_one_dev(skb, cb, dev);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -448,12 +448,15 @@ int ethnl_tsinfo_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
if (ctx->req_info->base.dev) {
|
if (ctx->req_info->base.dev) {
|
||||||
ret = ethnl_tsinfo_dump_one_net_topo(skb,
|
dev = ctx->req_info->base.dev;
|
||||||
ctx->req_info->base.dev,
|
netdev_lock_ops(dev);
|
||||||
cb);
|
ret = ethnl_tsinfo_dump_one_net_topo(skb, dev, cb);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
} else {
|
} else {
|
||||||
for_each_netdev_dump(net, dev, ctx->pos_ifindex) {
|
for_each_netdev_dump(net, dev, ctx->pos_ifindex) {
|
||||||
|
netdev_lock_ops(dev);
|
||||||
ret = ethnl_tsinfo_dump_one_net_topo(skb, dev, cb);
|
ret = ethnl_tsinfo_dump_one_net_topo(skb, dev, cb);
|
||||||
|
netdev_unlock_ops(dev);
|
||||||
if (ret < 0 && ret != -EOPNOTSUPP)
|
if (ret < 0 && ret != -EOPNOTSUPP)
|
||||||
break;
|
break;
|
||||||
ctx->pos_phyindex = 0;
|
ctx->pos_phyindex = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue