diff options
-rw-r--r-- | drivers/net/bonding/bond_main.c | 2 | ||||
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | include/net/sock.h | 53 | ||||
-rw-r--r-- | net/core/dev.c | 12 | ||||
-rw-r--r-- | net/core/ethtool.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 7 |
6 files changed, 73 insertions, 6 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 16d6fe954695..b51e021354b5 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -1407,7 +1407,7 @@ static int bond_compute_features(struct bonding *bond) | |||
1407 | int i; | 1407 | int i; |
1408 | 1408 | ||
1409 | features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); | 1409 | features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); |
1410 | features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM; | 1410 | features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_NOCACHE_COPY; |
1411 | 1411 | ||
1412 | if (!bond->first_slave) | 1412 | if (!bond->first_slave) |
1413 | goto done; | 1413 | goto done; |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a4664cc68e2b..09d262415769 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1066,6 +1066,7 @@ struct net_device { | |||
1066 | #define NETIF_F_NTUPLE (1 << 27) /* N-tuple filters supported */ | 1066 | #define NETIF_F_NTUPLE (1 << 27) /* N-tuple filters supported */ |
1067 | #define NETIF_F_RXHASH (1 << 28) /* Receive hashing offload */ | 1067 | #define NETIF_F_RXHASH (1 << 28) /* Receive hashing offload */ |
1068 | #define NETIF_F_RXCSUM (1 << 29) /* Receive checksumming offload */ | 1068 | #define NETIF_F_RXCSUM (1 << 29) /* Receive checksumming offload */ |
1069 | #define NETIF_F_NOCACHE_COPY (1 << 30) /* Use no-cache copyfromuser */ | ||
1069 | 1070 | ||
1070 | /* Segmentation offload features */ | 1071 | /* Segmentation offload features */ |
1071 | #define NETIF_F_GSO_SHIFT 16 | 1072 | #define NETIF_F_GSO_SHIFT 16 |
@@ -1081,7 +1082,7 @@ struct net_device { | |||
1081 | /* = all defined minus driver/device-class-related */ | 1082 | /* = all defined minus driver/device-class-related */ |
1082 | #define NETIF_F_NEVER_CHANGE (NETIF_F_HIGHDMA | NETIF_F_VLAN_CHALLENGED | \ | 1083 | #define NETIF_F_NEVER_CHANGE (NETIF_F_HIGHDMA | NETIF_F_VLAN_CHALLENGED | \ |
1083 | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL) | 1084 | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL) |
1084 | #define NETIF_F_ETHTOOL_BITS (0x3f3fffff & ~NETIF_F_NEVER_CHANGE) | 1085 | #define NETIF_F_ETHTOOL_BITS (0x7f3fffff & ~NETIF_F_NEVER_CHANGE) |
1085 | 1086 | ||
1086 | /* List of features with software fallbacks. */ | 1087 | /* List of features with software fallbacks. */ |
1087 | #define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | \ | 1088 | #define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | \ |
diff --git a/include/net/sock.h b/include/net/sock.h index da0534d3401c..43bd515e92fd 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/mm.h> | 52 | #include <linux/mm.h> |
53 | #include <linux/security.h> | 53 | #include <linux/security.h> |
54 | #include <linux/slab.h> | 54 | #include <linux/slab.h> |
55 | #include <linux/uaccess.h> | ||
55 | 56 | ||
56 | #include <linux/filter.h> | 57 | #include <linux/filter.h> |
57 | #include <linux/rculist_nulls.h> | 58 | #include <linux/rculist_nulls.h> |
@@ -1389,6 +1390,58 @@ static inline void sk_nocaps_add(struct sock *sk, int flags) | |||
1389 | sk->sk_route_caps &= ~flags; | 1390 | sk->sk_route_caps &= ~flags; |
1390 | } | 1391 | } |
1391 | 1392 | ||
1393 | static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, | ||
1394 | char __user *from, char *to, | ||
1395 | int copy) | ||
1396 | { | ||
1397 | if (skb->ip_summed == CHECKSUM_NONE) { | ||
1398 | int err = 0; | ||
1399 | __wsum csum = csum_and_copy_from_user(from, to, copy, 0, &err); | ||
1400 | if (err) | ||
1401 | return err; | ||
1402 | skb->csum = csum_block_add(skb->csum, csum, skb->len); | ||
1403 | } else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) { | ||
1404 | if (!access_ok(VERIFY_READ, from, copy) || | ||
1405 | __copy_from_user_nocache(to, from, copy)) | ||
1406 | return -EFAULT; | ||
1407 | } else if (copy_from_user(to, from, copy)) | ||
1408 | return -EFAULT; | ||
1409 | |||
1410 | return 0; | ||
1411 | } | ||
1412 | |||
1413 | static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb, | ||
1414 | char __user *from, int copy) | ||
1415 | { | ||
1416 | int err; | ||
1417 | |||
1418 | err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), copy); | ||
1419 | if (err) | ||
1420 | __skb_trim(skb, skb->len); | ||
1421 | |||
1422 | return err; | ||
1423 | } | ||
1424 | |||
1425 | static inline int skb_copy_to_page_nocache(struct sock *sk, char __user *from, | ||
1426 | struct sk_buff *skb, | ||
1427 | struct page *page, | ||
1428 | int off, int copy) | ||
1429 | { | ||
1430 | int err; | ||
1431 | |||
1432 | err = skb_do_copy_data_nocache(sk, skb, from, | ||
1433 | page_address(page) + off, copy); | ||
1434 | if (err) | ||
1435 | return err; | ||
1436 | |||
1437 | skb->len += copy; | ||
1438 | skb->data_len += copy; | ||
1439 | skb->truesize += copy; | ||
1440 | sk->sk_wmem_queued += copy; | ||
1441 | sk_mem_charge(sk, copy); | ||
1442 | return 0; | ||
1443 | } | ||
1444 | |||
1392 | static inline int skb_copy_to_page(struct sock *sk, char __user *from, | 1445 | static inline int skb_copy_to_page(struct sock *sk, char __user *from, |
1393 | struct sk_buff *skb, struct page *page, | 1446 | struct sk_buff *skb, struct page *page, |
1394 | int off, int copy) | 1447 | int off, int copy) |
diff --git a/net/core/dev.c b/net/core/dev.c index 02f56376fe99..5d0b4f6f1a72 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -5425,6 +5425,14 @@ int register_netdevice(struct net_device *dev) | |||
5425 | dev->features &= ~NETIF_F_GSO; | 5425 | dev->features &= ~NETIF_F_GSO; |
5426 | } | 5426 | } |
5427 | 5427 | ||
5428 | /* Turn on no cache copy if HW is doing checksum */ | ||
5429 | dev->hw_features |= NETIF_F_NOCACHE_COPY; | ||
5430 | if ((dev->features & NETIF_F_ALL_CSUM) && | ||
5431 | !(dev->features & NETIF_F_NO_CSUM)) { | ||
5432 | dev->wanted_features |= NETIF_F_NOCACHE_COPY; | ||
5433 | dev->features |= NETIF_F_NOCACHE_COPY; | ||
5434 | } | ||
5435 | |||
5428 | /* Enable GRO and NETIF_F_HIGHDMA for vlans by default, | 5436 | /* Enable GRO and NETIF_F_HIGHDMA for vlans by default, |
5429 | * vlan_dev_init() will do the dev->features check, so these features | 5437 | * vlan_dev_init() will do the dev->features check, so these features |
5430 | * are enabled only if supported by underlying device. | 5438 | * are enabled only if supported by underlying device. |
@@ -6182,6 +6190,10 @@ u32 netdev_increment_features(u32 all, u32 one, u32 mask) | |||
6182 | } | 6190 | } |
6183 | } | 6191 | } |
6184 | 6192 | ||
6193 | /* If device can't no cache copy, don't do for all */ | ||
6194 | if (!(one & NETIF_F_NOCACHE_COPY)) | ||
6195 | all &= ~NETIF_F_NOCACHE_COPY; | ||
6196 | |||
6185 | one |= NETIF_F_ALL_CSUM; | 6197 | one |= NETIF_F_ALL_CSUM; |
6186 | 6198 | ||
6187 | one |= all & NETIF_F_ONE_FOR_ALL; | 6199 | one |= all & NETIF_F_ONE_FOR_ALL; |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 439e4b0e1312..719670ae199c 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -359,7 +359,7 @@ static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GS | |||
359 | /* NETIF_F_NTUPLE */ "rx-ntuple-filter", | 359 | /* NETIF_F_NTUPLE */ "rx-ntuple-filter", |
360 | /* NETIF_F_RXHASH */ "rx-hashing", | 360 | /* NETIF_F_RXHASH */ "rx-hashing", |
361 | /* NETIF_F_RXCSUM */ "rx-checksum", | 361 | /* NETIF_F_RXCSUM */ "rx-checksum", |
362 | "", | 362 | /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy" |
363 | "", | 363 | "", |
364 | }; | 364 | }; |
365 | 365 | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index b22d45010545..054a59d21eb0 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -999,7 +999,8 @@ new_segment: | |||
999 | /* We have some space in skb head. Superb! */ | 999 | /* We have some space in skb head. Superb! */ |
1000 | if (copy > skb_tailroom(skb)) | 1000 | if (copy > skb_tailroom(skb)) |
1001 | copy = skb_tailroom(skb); | 1001 | copy = skb_tailroom(skb); |
1002 | if ((err = skb_add_data(skb, from, copy)) != 0) | 1002 | err = skb_add_data_nocache(sk, skb, from, copy); |
1003 | if (err) | ||
1003 | goto do_fault; | 1004 | goto do_fault; |
1004 | } else { | 1005 | } else { |
1005 | int merge = 0; | 1006 | int merge = 0; |
@@ -1042,8 +1043,8 @@ new_segment: | |||
1042 | 1043 | ||
1043 | /* Time to copy data. We are close to | 1044 | /* Time to copy data. We are close to |
1044 | * the end! */ | 1045 | * the end! */ |
1045 | err = skb_copy_to_page(sk, from, skb, page, | 1046 | err = skb_copy_to_page_nocache(sk, from, skb, |
1046 | off, copy); | 1047 | page, off, copy); |
1047 | if (err) { | 1048 | if (err) { |
1048 | /* If this page was new, give it to the | 1049 | /* If this page was new, give it to the |
1049 | * socket so it does not get leaked. | 1050 | * socket so it does not get leaked. |