summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/netdevice.h5
-rw-r--r--include/net/ip.h5
-rw-r--r--net/core/dev.c3
-rw-r--r--net/ipv4/devinet.c5
-rw-r--r--net/ipv4/ip_output.c14
5 files changed, 21 insertions, 11 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5d74c847efec..6fac5b8a42c2 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1345,6 +1345,11 @@ struct net_device {
unsigned char if_port; /* Selectable AUI, TP,..*/
unsigned char dma; /* DMA channel */
+ /* Note : dev->mtu is often read without holding a lock.
+ * Writers usually hold RTNL.
+ * It is recommended to use ACCESS_ONCE() to annotate the reads
+ * and writes.
+ */
unsigned int mtu; /* interface MTU value */
unsigned short type; /* interface hardware type */
unsigned short hard_header_len; /* hardware hdr length */
diff --git a/include/net/ip.h b/include/net/ip.h
index 8ec53320c902..333f1159d0f8 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -522,4 +522,9 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport,
int ip_misc_proc_init(void);
#endif
+static inline bool inetdev_valid_mtu(unsigned int mtu)
+{
+ return likely(mtu >= 68);
+}
+
#endif /* _IP_H */
diff --git a/net/core/dev.c b/net/core/dev.c
index 4c821b721713..7e499da4a06f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5680,7 +5680,8 @@ static int __dev_set_mtu(struct net_device *dev, int new_mtu)
if (ops->ndo_change_mtu)
return ops->ndo_change_mtu(dev, new_mtu);
- dev->mtu = new_mtu;
+ /* Pairs with all the lockless reads of dev->mtu in the stack */
+ ACCESS_ONCE(dev->mtu) = new_mtu;
return 0;
}
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 710fe64fb2f7..026f69106ec2 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1318,11 +1318,6 @@ skip:
}
}
-static bool inetdev_valid_mtu(unsigned int mtu)
-{
- return mtu >= 68;
-}
-
static void inetdev_send_gratuitous_arp(struct net_device *dev,
struct in_device *in_dev)
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 2a05dfc9a35e..260e50e77d55 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1106,13 +1106,17 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
rt = *rtp;
if (unlikely(!rt))
return -EFAULT;
- /*
- * We steal reference to this route, caller should not release it
- */
- *rtp = NULL;
+
cork->fragsize = ip_sk_use_pmtu(sk) ?
- dst_mtu(&rt->dst) : rt->dst.dev->mtu;
+ dst_mtu(&rt->dst) : ACCESS_ONCE(rt->dst.dev->mtu);
+
+ if (!inetdev_valid_mtu(cork->fragsize))
+ return -ENETUNREACH;
+
cork->dst = &rt->dst;
+ /* We stole this route, caller should not release it. */
+ *rtp = NULL;
+
cork->length = 0;
cork->ttl = ipc->ttl;
cork->tos = ipc->tos;