summaryrefslogtreecommitdiffstats
path: root/net/ethtool/ioctl.c
diff options
context:
space:
mode:
authorEdward Cree <ecree@solarflare.com>2020-09-01 19:52:32 +0200
committerDavid S. Miller <davem@davemloft.net>2020-09-03 23:59:51 +0200
commit2adc6edcaec09eea9275915e9632ff916fcd0785 (patch)
tree3b2e454129b95babe7b6a83fee1c1edbd40bef50 /net/ethtool/ioctl.c
parentselftests/net: improve descriptions for XFAIL cases in psock_snd.sh (diff)
downloadlinux-2adc6edcaec09eea9275915e9632ff916fcd0785.tar.xz
linux-2adc6edcaec09eea9275915e9632ff916fcd0785.zip
ethtool: fix error handling in ethtool_phys_id
If ops->set_phys_id() returned an error, previously we would only break out of the inner loop, which neither stopped the outer loop nor returned the error to the user (since 'rc' would be overwritten on the next pass through the loop). Thus, rewrite it to use a single loop, so that the break does the right thing. Use u64 for 'count' and 'i' to prevent overflow in case of (unreasonably) large values of id.data and n. Signed-off-by: Edward Cree <ecree@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ethtool/ioctl.c')
-rw-r--r--net/ethtool/ioctl.c25
1 files changed, 10 insertions, 15 deletions
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index d497ca064ef7..328d15cd4006 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1861,23 +1861,18 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT);
} else {
/* Driver expects to be called at twice the frequency in rc */
- int n = rc * 2, i, interval = HZ / n;
+ int n = rc * 2, interval = HZ / n;
+ u64 count = n * id.data, i = 0;
- /* Count down seconds */
do {
- /* Count down iterations per second */
- i = n;
- do {
- rtnl_lock();
- rc = ops->set_phys_id(dev,
- (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
- rtnl_unlock();
- if (rc)
- break;
- schedule_timeout_interruptible(interval);
- } while (!signal_pending(current) && --i != 0);
- } while (!signal_pending(current) &&
- (id.data == 0 || --id.data != 0));
+ rtnl_lock();
+ rc = ops->set_phys_id(dev,
+ (i++ & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON);
+ rtnl_unlock();
+ if (rc)
+ break;
+ schedule_timeout_interruptible(interval);
+ } while (!signal_pending(current) && (!id.data || i < count));
}
rtnl_lock();