net: make dev_set_mtu() honor notification return code
authorVeaceslav Falico <vfalico@redhat.com>
Fri, 10 Jan 2014 15:56:25 +0000 (16:56 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 13 Jan 2014 23:19:26 +0000 (15:19 -0800)
Currently, after changing the MTU for a device, dev_set_mtu() calls
NETDEV_CHANGEMTU notification, however doesn't verify it's return code -
which can be NOTIFY_BAD - i.e. some of the net notifier blocks refused this
change, and continues nevertheless.

To fix this, verify the return code, and if it's an error - then revert the
MTU to the original one, notify again and pass the error code.

CC: Jiri Pirko <jiri@resnulli.us>
CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
CC: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
Reviewed-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/dev.c

index a8280154c42a21a1c2f5b2f50ce923a84a5f856a..87312dcf0aa848412f200e00f5bab26433b8b080 100644 (file)
@@ -5300,6 +5300,17 @@ int dev_change_flags(struct net_device *dev, unsigned int flags)
 }
 EXPORT_SYMBOL(dev_change_flags);
 
+static int __dev_set_mtu(struct net_device *dev, int new_mtu)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+
+       if (ops->ndo_change_mtu)
+               return ops->ndo_change_mtu(dev, new_mtu);
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
 /**
  *     dev_set_mtu - Change maximum transfer unit
  *     @dev: device
@@ -5309,8 +5320,7 @@ EXPORT_SYMBOL(dev_change_flags);
  */
 int dev_set_mtu(struct net_device *dev, int new_mtu)
 {
-       const struct net_device_ops *ops = dev->netdev_ops;
-       int err;
+       int err, orig_mtu;
 
        if (new_mtu == dev->mtu)
                return 0;
@@ -5322,14 +5332,20 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
        if (!netif_device_present(dev))
                return -ENODEV;
 
-       err = 0;
-       if (ops->ndo_change_mtu)
-               err = ops->ndo_change_mtu(dev, new_mtu);
-       else
-               dev->mtu = new_mtu;
+       orig_mtu = dev->mtu;
+       err = __dev_set_mtu(dev, new_mtu);
 
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
+       if (!err) {
+               err = call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
+               err = notifier_to_errno(err);
+               if (err) {
+                       /* setting mtu back and notifying everyone again,
+                        * so that they have a chance to revert changes.
+                        */
+                       __dev_set_mtu(dev, orig_mtu);
+                       call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
+               }
+       }
        return err;
 }
 EXPORT_SYMBOL(dev_set_mtu);