Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Edward Cree and committed by
David S. Miller
2adc6edc 30ae8017

+10 -15
+10 -15
net/ethtool/ioctl.c
··· 1861 1861 id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT); 1862 1862 } else { 1863 1863 /* Driver expects to be called at twice the frequency in rc */ 1864 - int n = rc * 2, i, interval = HZ / n; 1864 + int n = rc * 2, interval = HZ / n; 1865 + u64 count = n * id.data, i = 0; 1865 1866 1866 - /* Count down seconds */ 1867 1867 do { 1868 - /* Count down iterations per second */ 1869 - i = n; 1870 - do { 1871 - rtnl_lock(); 1872 - rc = ops->set_phys_id(dev, 1873 - (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON); 1874 - rtnl_unlock(); 1875 - if (rc) 1876 - break; 1877 - schedule_timeout_interruptible(interval); 1878 - } while (!signal_pending(current) && --i != 0); 1879 - } while (!signal_pending(current) && 1880 - (id.data == 0 || --id.data != 0)); 1868 + rtnl_lock(); 1869 + rc = ops->set_phys_id(dev, 1870 + (i++ & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON); 1871 + rtnl_unlock(); 1872 + if (rc) 1873 + break; 1874 + schedule_timeout_interruptible(interval); 1875 + } while (!signal_pending(current) && (!id.data || i < count)); 1881 1876 } 1882 1877 1883 1878 rtnl_lock();