From e56c57d0d3fdbbdf583d3af96bfb803b8dfa713e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 8 Nov 2011 17:07:07 -0500 Subject: net: rename sk_clone to sk_clone_lock Make clear that sk_clone() and inet_csk_clone() return a locked socket. Add _lock() prefix and kerneldoc. Suggested-by: Linus Torvalds Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/net/sock.h') diff --git a/include/net/sock.h b/include/net/sock.h index abb6e0f0c3c3..67cd4581b6da 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1089,8 +1089,8 @@ extern struct sock *sk_alloc(struct net *net, int family, struct proto *prot); extern void sk_free(struct sock *sk); extern void sk_release_kernel(struct sock *sk); -extern struct sock *sk_clone(const struct sock *sk, - const gfp_t priority); +extern struct sock *sk_clone_lock(const struct sock *sk, + const gfp_t priority); extern struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, -- cgit From 6e3e939f3b1bf8534b32ad09ff199d88800835a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Nov 2011 10:15:42 +0100 Subject: net: add wireless TX status socket option The 802.1X EAPOL handshake hostapd does requires knowing whether the frame was ack'ed by the peer. Currently, we fudge this pretty badly by not even transmitting the frame as a normal data frame but injecting it with radiotap and getting the status out of radiotap monitor as well. This is rather complex, confuses users (mon.wlan0 presence) and doesn't work with all hardware. To get rid of that hack, introduce a real wifi TX status option for data frame transmissions. This works similar to the existing TX timestamping in that it reflects the SKB back to the socket's error queue with a SCM_WIFI_STATUS cmsg that has an int indicating ACK status (0/1). Since it is possible that at some point we will want to have TX timestamping and wifi status in a single errqueue SKB (there's little point in not doing that), redefine SO_EE_ORIGIN_TIMESTAMPING to SO_EE_ORIGIN_TXSTATUS which can collect more than just the timestamp; keep the old constant as an alias of course. Currently the internal APIs don't make that possible, but it wouldn't be hard to split them up in a way that makes it possible. Thanks to Neil Horman for helping me figure out the functions that add the control messages. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- arch/alpha/include/asm/socket.h | 3 +++ arch/arm/include/asm/socket.h | 3 +++ arch/avr32/include/asm/socket.h | 3 +++ arch/cris/include/asm/socket.h | 3 +++ arch/frv/include/asm/socket.h | 3 +++ arch/h8300/include/asm/socket.h | 3 +++ arch/ia64/include/asm/socket.h | 3 +++ arch/m32r/include/asm/socket.h | 3 +++ arch/m68k/include/asm/socket.h | 3 +++ arch/mips/include/asm/socket.h | 3 +++ arch/mn10300/include/asm/socket.h | 3 +++ arch/parisc/include/asm/socket.h | 3 +++ arch/powerpc/include/asm/socket.h | 3 +++ arch/s390/include/asm/socket.h | 3 +++ arch/sparc/include/asm/socket.h | 3 +++ arch/xtensa/include/asm/socket.h | 3 +++ include/asm-generic/socket.h | 3 +++ include/linux/errqueue.h | 3 ++- include/linux/skbuff.h | 19 +++++++++++++++++-- include/net/sock.h | 6 ++++++ net/core/skbuff.c | 20 ++++++++++++++++++++ net/core/sock.c | 9 +++++++++ net/socket.c | 18 ++++++++++++++++++ 23 files changed, 123 insertions(+), 3 deletions(-) (limited to 'include/net/sock.h') diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 06edfefc3373..082355f159e6 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -69,6 +69,9 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index 90ffd04b8e74..dec6f9afb3cf 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index c8d1fae49476..247b88c760be 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index 1a4a61909ca8..e269264df7c4 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -64,6 +64,9 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index a6b26880c1ec..ce80fdadcce5 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -62,5 +62,8 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index 04c0f4596eb5..cf1daab6f27e 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index 51427eaa51ba..4b03664e3fb5 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -71,4 +71,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index 469787c30098..e8b8c5bb053c 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index 9bf49c87d954..d4708ce466e0 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index 9de5190f2487..ad5c0a7a02a7 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -82,6 +82,9 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #ifdef __KERNEL__ /** sock_type - Socket types diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index 4e60c4281288..876356d78522 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index 225b7d6a1a0a..d28c51b61067 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -61,6 +61,9 @@ #define SO_RXQ_OVFL 0x4021 +#define SO_WIFI_STATUS 0x4022 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index 866f7606da68..2fc2af8fbf59 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -69,4 +69,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index fdff1e995c73..67b5c1b14b51 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -70,4 +70,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 9d3fefcff2f5..8af1b64168b3 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -58,6 +58,9 @@ #define SO_RXQ_OVFL 0x0024 +#define SO_WIFI_STATUS 0x0025 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index cbdf2ffaacff..bb06968be227 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -73,4 +73,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _XTENSA_SOCKET_H */ diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h index 9a6115e7cf63..49c1704173e7 100644 --- a/include/asm-generic/socket.h +++ b/include/asm-generic/socket.h @@ -64,4 +64,7 @@ #define SO_DOMAIN 39 #define SO_RXQ_OVFL 40 + +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS #endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/include/linux/errqueue.h b/include/linux/errqueue.h index 034072cea853..c9f522bd17e4 100644 --- a/include/linux/errqueue.h +++ b/include/linux/errqueue.h @@ -17,7 +17,8 @@ struct sock_extended_err { #define SO_EE_ORIGIN_LOCAL 1 #define SO_EE_ORIGIN_ICMP 2 #define SO_EE_ORIGIN_ICMP6 3 -#define SO_EE_ORIGIN_TIMESTAMPING 4 +#define SO_EE_ORIGIN_TXSTATUS 4 +#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS #define SO_EE_OFFENDER(ee) ((struct sockaddr*)((ee)+1)) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6a6b352326d7..ff7e1306a2d2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -218,6 +218,9 @@ enum { /* device driver supports TX zero-copy buffers */ SKBTX_DEV_ZEROCOPY = 1 << 4, + + /* generate wifi status information (where possible) */ + SKBTX_WIFI_STATUS = 1 << 5, }; /* @@ -352,6 +355,8 @@ typedef unsigned char *sk_buff_data_t; * @ooo_okay: allow the mapping of a socket to a queue to be changed * @l4_rxhash: indicate rxhash is a canonical 4-tuple hash over transport * ports. + * @wifi_acked_valid: wifi_acked was set + * @wifi_acked: whether frame was acked on wifi or not * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions * @secmark: security marking @@ -445,10 +450,11 @@ struct sk_buff { #endif __u8 ooo_okay:1; __u8 l4_rxhash:1; + __u8 wifi_acked_valid:1; + __u8 wifi_acked:1; + /* 10/12 bit hole (depending on ndisc_nodetype presence) */ kmemcheck_bitfield_end(flags2); - /* 0/13 bit hole */ - #ifdef CONFIG_NET_DMA dma_cookie_t dma_cookie; #endif @@ -2263,6 +2269,15 @@ static inline void skb_tx_timestamp(struct sk_buff *skb) sw_tx_timestamp(skb); } +/** + * skb_complete_wifi_ack - deliver skb with wifi status + * + * @skb: the original outgoing packet + * @acked: ack status + * + */ +void skb_complete_wifi_ack(struct sk_buff *skb, bool acked); + extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len); extern __sum16 __skb_checksum_complete(struct sk_buff *skb); diff --git a/include/net/sock.h b/include/net/sock.h index 5ac682f73d63..fa6f5381c5d6 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -564,6 +564,7 @@ enum sock_flags { SOCK_FASYNC, /* fasync() active */ SOCK_RXQ_OVFL, SOCK_ZEROCOPY, /* buffers from userspace */ + SOCK_WIFI_STATUS, /* push wifi status to userspace */ }; static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) @@ -1714,6 +1715,8 @@ static inline int sock_intr_errno(long timeo) extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb); +extern void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb); static __inline__ void sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) @@ -1741,6 +1744,9 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) __sock_recv_timestamp(msg, sk, skb); else sk->sk_stamp = kt; + + if (sock_flag(sk, SOCK_WIFI_STATUS) && skb->wifi_acked_valid) + __sock_recv_wifi_status(msg, sk, skb); } extern void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ca4db40e75b8..2f6babd5a570 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3168,6 +3168,26 @@ void skb_tstamp_tx(struct sk_buff *orig_skb, } EXPORT_SYMBOL_GPL(skb_tstamp_tx); +void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) +{ + struct sock *sk = skb->sk; + struct sock_exterr_skb *serr; + int err; + + skb->wifi_acked_valid = 1; + skb->wifi_acked = acked; + + serr = SKB_EXT_ERR(skb); + memset(serr, 0, sizeof(*serr)); + serr->ee.ee_errno = ENOMSG; + serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS; + + err = sock_queue_err_skb(sk, skb); + if (err) + kfree_skb(skb); +} +EXPORT_SYMBOL_GPL(skb_complete_wifi_ack); + /** * skb_partial_csum_set - set up and verify partial csum values for packet diff --git a/net/core/sock.c b/net/core/sock.c index 4ed7b1d12f5e..cbdf51c0d5ac 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -740,6 +740,11 @@ set_rcvbuf: case SO_RXQ_OVFL: sock_valbool_flag(sk, SOCK_RXQ_OVFL, valbool); break; + + case SO_WIFI_STATUS: + sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool); + break; + default: ret = -ENOPROTOOPT; break; @@ -961,6 +966,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = !!sock_flag(sk, SOCK_RXQ_OVFL); break; + case SO_WIFI_STATUS: + v.val = !!sock_flag(sk, SOCK_WIFI_STATUS); + break; + default: return -ENOPROTOOPT; } diff --git a/net/socket.c b/net/socket.c index 2877647f347b..425ef4270460 100644 --- a/net/socket.c +++ b/net/socket.c @@ -538,6 +538,8 @@ int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) *tx_flags |= SKBTX_HW_TSTAMP; if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) *tx_flags |= SKBTX_SW_TSTAMP; + if (sock_flag(sk, SOCK_WIFI_STATUS)) + *tx_flags |= SKBTX_WIFI_STATUS; return 0; } EXPORT_SYMBOL(sock_tx_timestamp); @@ -674,6 +676,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, } EXPORT_SYMBOL_GPL(__sock_recv_timestamp); +void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, + struct sk_buff *skb) +{ + int ack; + + if (!sock_flag(sk, SOCK_WIFI_STATUS)) + return; + if (!skb->wifi_acked_valid) + return; + + ack = skb->wifi_acked; + + put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack); +} +EXPORT_SYMBOL_GPL(__sock_recv_wifi_status); + static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) { -- cgit From c8f44affb7244f2ac3e703cab13d55ede27621bb Mon Sep 17 00:00:00 2001 From: Michał Mirosław Date: Tue, 15 Nov 2011 15:29:55 +0000 Subject: net: introduce and use netdev_features_t for device features sets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: add couple missing conversions in drivers split unexporting netdev_fix_features() implemented %pNF convert sock::sk_route_(no?)caps Signed-off-by: Michał Mirosław Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 9 ++--- drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 13 ++++--- drivers/net/ethernet/atheros/atl1e/atl1e_main.c | 13 ++++--- drivers/net/ethernet/atheros/atlx/atl2.c | 13 ++++--- drivers/net/ethernet/atheros/atlx/atlx.c | 13 ++++--- drivers/net/ethernet/broadcom/bnx2.c | 6 ++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 5 +-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 5 +-- drivers/net/ethernet/broadcom/tg3.c | 11 +++--- drivers/net/ethernet/chelsio/cxgb/cxgb2.c | 7 ++-- drivers/net/ethernet/chelsio/cxgb/sge.c | 2 +- drivers/net/ethernet/chelsio/cxgb/sge.h | 2 +- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 9 ++--- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 12 ++++--- .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c | 8 +++-- drivers/net/ethernet/davicom/dm9000.c | 5 +-- drivers/net/ethernet/freescale/gianfar.c | 2 +- drivers/net/ethernet/freescale/gianfar.h | 4 +-- drivers/net/ethernet/freescale/gianfar_ethtool.c | 4 +-- drivers/net/ethernet/ibm/ibmveth.c | 6 ++-- drivers/net/ethernet/intel/e1000/e1000_main.c | 14 +++++--- drivers/net/ethernet/intel/e1000e/netdev.c | 5 +-- drivers/net/ethernet/intel/igb/igb_main.c | 12 ++++--- drivers/net/ethernet/intel/igbvf/netdev.c | 3 +- drivers/net/ethernet/intel/ixgb/ixgb_main.c | 8 ++--- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 ++-- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 3 +- drivers/net/ethernet/jme.c | 8 ++--- drivers/net/ethernet/marvell/mv643xx_eth.c | 4 +-- drivers/net/ethernet/marvell/sky2.c | 13 +++---- drivers/net/ethernet/micrel/ksz884x.c | 3 +- drivers/net/ethernet/myricom/myri10ge/myri10ge.c | 5 +-- drivers/net/ethernet/neterion/s2io.c | 4 +-- drivers/net/ethernet/neterion/vxge/vxge-main.c | 9 ++--- drivers/net/ethernet/nvidia/forcedeth.c | 11 +++--- .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 5 +-- .../net/ethernet/qlogic/netxen/netxen_nic_main.c | 6 ++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 5 +-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 9 ++--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 2 +- drivers/net/ethernet/qlogic/qlge/qlge_main.c | 10 +++--- drivers/net/ethernet/realtek/8139cp.c | 2 +- drivers/net/ethernet/realtek/r8169.c | 6 ++-- drivers/net/ethernet/sfc/efx.c | 2 +- drivers/net/ethernet/sfc/net_driver.h | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +- drivers/net/tun.c | 7 ++-- drivers/net/usb/smsc75xx.c | 3 +- drivers/net/usb/smsc95xx.c | 3 +- drivers/net/vmxnet3/vmxnet3_ethtool.c | 4 +-- drivers/net/vmxnet3/vmxnet3_int.h | 2 +- drivers/net/xen-netback/interface.c | 3 +- drivers/net/xen-netfront.c | 8 +++-- drivers/s390/net/qeth_l3_main.c | 6 ++-- include/linux/netdev_features.h | 4 +++ include/linux/netdevice.h | 41 ++++++++++++---------- include/linux/skbuff.h | 4 ++- include/net/protocol.h | 4 +-- include/net/sock.h | 6 ++-- include/net/tcp.h | 3 +- include/net/udp.h | 3 +- lib/vsprintf.c | 19 ++++++++++ net/8021q/vlan_dev.c | 3 +- net/bridge/br_device.c | 3 +- net/bridge/br_if.c | 5 +-- net/bridge/br_private.h | 3 +- net/core/dev.c | 38 +++++++++++--------- net/core/ethtool.c | 9 +++-- net/core/skbuff.c | 2 +- net/ipv4/af_inet.c | 3 +- net/ipv4/tcp.c | 3 +- net/ipv4/udp.c | 3 +- net/ipv6/af_inet6.c | 3 +- net/ipv6/udp.c | 3 +- 74 files changed, 305 insertions(+), 202 deletions(-) (limited to 'include/net/sock.h') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b0c577256487..ac5337a04639 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1325,11 +1325,12 @@ static int bond_sethwaddr(struct net_device *bond_dev, return 0; } -static u32 bond_fix_features(struct net_device *dev, u32 features) +static netdev_features_t bond_fix_features(struct net_device *dev, + netdev_features_t features) { struct slave *slave; struct bonding *bond = netdev_priv(dev); - u32 mask; + netdev_features_t mask; int i; read_lock(&bond->lock); @@ -1363,7 +1364,7 @@ static void bond_compute_features(struct bonding *bond) { struct slave *slave; struct net_device *bond_dev = bond->dev; - u32 vlan_features = BOND_VLAN_FEATURES; + netdev_features_t vlan_features = BOND_VLAN_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; int i; @@ -1897,7 +1898,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr addr; - u32 old_features = bond_dev->features; + netdev_features_t old_features = bond_dev->features; /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 02c7ed8d9eca..b8591246eb4c 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -411,7 +411,7 @@ static void atl1c_set_multi(struct net_device *netdev) } } -static void __atl1c_vlan_mode(u32 features, u32 *mac_ctrl_data) +static void __atl1c_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data) { if (features & NETIF_F_HW_VLAN_RX) { /* enable VLAN tag insert/strip */ @@ -422,7 +422,8 @@ static void __atl1c_vlan_mode(u32 features, u32 *mac_ctrl_data) } } -static void atl1c_vlan_mode(struct net_device *netdev, u32 features) +static void atl1c_vlan_mode(struct net_device *netdev, + netdev_features_t features) { struct atl1c_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev = adapter->pdev; @@ -482,7 +483,8 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; } -static u32 atl1c_fix_features(struct net_device *netdev, u32 features) +static netdev_features_t atl1c_fix_features(struct net_device *netdev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -499,9 +501,10 @@ static u32 atl1c_fix_features(struct net_device *netdev, u32 features) return features; } -static int atl1c_set_features(struct net_device *netdev, u32 features) +static int atl1c_set_features(struct net_device *netdev, + netdev_features_t features) { - u32 changed = netdev->features ^ features; + netdev_features_t changed = netdev->features ^ features; if (changed & NETIF_F_HW_VLAN_RX) atl1c_vlan_mode(netdev, features); diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index 95483bcac1d0..c915c0873810 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -313,7 +313,7 @@ static void atl1e_set_multi(struct net_device *netdev) } } -static void __atl1e_vlan_mode(u32 features, u32 *mac_ctrl_data) +static void __atl1e_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data) { if (features & NETIF_F_HW_VLAN_RX) { /* enable VLAN tag insert/strip */ @@ -324,7 +324,8 @@ static void __atl1e_vlan_mode(u32 features, u32 *mac_ctrl_data) } } -static void atl1e_vlan_mode(struct net_device *netdev, u32 features) +static void atl1e_vlan_mode(struct net_device *netdev, + netdev_features_t features) { struct atl1e_adapter *adapter = netdev_priv(netdev); u32 mac_ctrl_data = 0; @@ -370,7 +371,8 @@ static int atl1e_set_mac_addr(struct net_device *netdev, void *p) return 0; } -static u32 atl1e_fix_features(struct net_device *netdev, u32 features) +static netdev_features_t atl1e_fix_features(struct net_device *netdev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -384,9 +386,10 @@ static u32 atl1e_fix_features(struct net_device *netdev, u32 features) return features; } -static int atl1e_set_features(struct net_device *netdev, u32 features) +static int atl1e_set_features(struct net_device *netdev, + netdev_features_t features) { - u32 changed = netdev->features ^ features; + netdev_features_t changed = netdev->features ^ features; if (changed & NETIF_F_HW_VLAN_RX) atl1e_vlan_mode(netdev, features); diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c index db3f43046d32..071f4c858969 100644 --- a/drivers/net/ethernet/atheros/atlx/atl2.c +++ b/drivers/net/ethernet/atheros/atlx/atl2.c @@ -361,7 +361,7 @@ static inline void atl2_irq_disable(struct atl2_adapter *adapter) synchronize_irq(adapter->pdev->irq); } -static void __atl2_vlan_mode(u32 features, u32 *ctrl) +static void __atl2_vlan_mode(netdev_features_t features, u32 *ctrl) { if (features & NETIF_F_HW_VLAN_RX) { /* enable VLAN tag insert/strip */ @@ -372,7 +372,8 @@ static void __atl2_vlan_mode(u32 features, u32 *ctrl) } } -static void atl2_vlan_mode(struct net_device *netdev, u32 features) +static void atl2_vlan_mode(struct net_device *netdev, + netdev_features_t features) { struct atl2_adapter *adapter = netdev_priv(netdev); u32 ctrl; @@ -391,7 +392,8 @@ static void atl2_restore_vlan(struct atl2_adapter *adapter) atl2_vlan_mode(adapter->netdev, adapter->netdev->features); } -static u32 atl2_fix_features(struct net_device *netdev, u32 features) +static netdev_features_t atl2_fix_features(struct net_device *netdev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -405,9 +407,10 @@ static u32 atl2_fix_features(struct net_device *netdev, u32 features) return features; } -static int atl2_set_features(struct net_device *netdev, u32 features) +static int atl2_set_features(struct net_device *netdev, + netdev_features_t features) { - u32 changed = netdev->features ^ features; + netdev_features_t changed = netdev->features ^ features; if (changed & NETIF_F_HW_VLAN_RX) atl2_vlan_mode(netdev, features); diff --git a/drivers/net/ethernet/atheros/atlx/atlx.c b/drivers/net/ethernet/atheros/atlx/atlx.c index aabcf4b5745a..8ff7411094d5 100644 --- a/drivers/net/ethernet/atheros/atlx/atlx.c +++ b/drivers/net/ethernet/atheros/atlx/atlx.c @@ -211,7 +211,7 @@ static void atlx_link_chg_task(struct work_struct *work) spin_unlock_irqrestore(&adapter->lock, flags); } -static void __atlx_vlan_mode(u32 features, u32 *ctrl) +static void __atlx_vlan_mode(netdev_features_t features, u32 *ctrl) { if (features & NETIF_F_HW_VLAN_RX) { /* enable VLAN tag insert/strip */ @@ -222,7 +222,8 @@ static void __atlx_vlan_mode(u32 features, u32 *ctrl) } } -static void atlx_vlan_mode(struct net_device *netdev, u32 features) +static void atlx_vlan_mode(struct net_device *netdev, + netdev_features_t features) { struct atlx_adapter *adapter = netdev_priv(netdev); unsigned long flags; @@ -242,7 +243,8 @@ static void atlx_restore_vlan(struct atlx_adapter *adapter) atlx_vlan_mode(adapter->netdev, adapter->netdev->features); } -static u32 atlx_fix_features(struct net_device *netdev, u32 features) +static netdev_features_t atlx_fix_features(struct net_device *netdev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -256,9 +258,10 @@ static u32 atlx_fix_features(struct net_device *netdev, u32 features) return features; } -static int atlx_set_features(struct net_device *netdev, u32 features) +static int atlx_set_features(struct net_device *netdev, + netdev_features_t features) { - u32 changed = netdev->features ^ features; + netdev_features_t changed = netdev->features ^ features; if (changed & NETIF_F_HW_VLAN_RX) atlx_vlan_mode(netdev, features); diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 32d1f92a2479..7203f37d2ef3 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -7571,8 +7571,8 @@ bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) return 0; } -static u32 -bnx2_fix_features(struct net_device *dev, u32 features) +static netdev_features_t +bnx2_fix_features(struct net_device *dev, netdev_features_t features) { struct bnx2 *bp = netdev_priv(dev); @@ -7583,7 +7583,7 @@ bnx2_fix_features(struct net_device *dev, u32 features) } static int -bnx2_set_features(struct net_device *dev, u32 features) +bnx2_set_features(struct net_device *dev, netdev_features_t features) { struct bnx2 *bp = netdev_priv(dev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 0d60b9e633ad..8336c784db49 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3398,7 +3398,8 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) return bnx2x_reload_if_running(dev); } -u32 bnx2x_fix_features(struct net_device *dev, u32 features) +netdev_features_t bnx2x_fix_features(struct net_device *dev, + netdev_features_t features) { struct bnx2x *bp = netdev_priv(dev); @@ -3409,7 +3410,7 @@ u32 bnx2x_fix_features(struct net_device *dev, u32 features) return features; } -int bnx2x_set_features(struct net_device *dev, u32 features) +int bnx2x_set_features(struct net_device *dev, netdev_features_t features) { struct bnx2x *bp = netdev_priv(dev); u32 flags = bp->flags; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 41eb17e7720f..80c5ed08e419 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -533,8 +533,9 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu); */ int bnx2x_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type); #endif -u32 bnx2x_fix_features(struct net_device *dev, u32 features); -int bnx2x_set_features(struct net_device *dev, u32 features); +netdev_features_t bnx2x_fix_features(struct net_device *dev, + netdev_features_t features); +int bnx2x_set_features(struct net_device *dev, netdev_features_t features); /** * bnx2x_tx_timeout - tx timeout netdev callback diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index cd3623416a4e..365cd47e2298 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -6968,7 +6968,7 @@ static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk) return 0; } -static void tg3_set_loopback(struct net_device *dev, u32 features) +static void tg3_set_loopback(struct net_device *dev, netdev_features_t features) { struct tg3 *tp = netdev_priv(dev); @@ -6994,7 +6994,8 @@ static void tg3_set_loopback(struct net_device *dev, u32 features) } } -static u32 tg3_fix_features(struct net_device *dev, u32 features) +static netdev_features_t tg3_fix_features(struct net_device *dev, + netdev_features_t features) { struct tg3 *tp = netdev_priv(dev); @@ -7004,9 +7005,9 @@ static u32 tg3_fix_features(struct net_device *dev, u32 features) return features; } -static int tg3_set_features(struct net_device *dev, u32 features) +static int tg3_set_features(struct net_device *dev, netdev_features_t features) { - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; if ((changed & NETIF_F_LOOPBACK) && netif_running(dev)) tg3_set_loopback(dev, features); @@ -15313,7 +15314,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, u32 sndmbx, rcvmbx, intmbx; char str[40]; u64 dma_mask, persist_dma_mask; - u32 features = 0; + netdev_features_t features = 0; printk_once(KERN_INFO "%s\n", version); diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c index 26d0fd2d9c9d..a971796b2262 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c +++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c @@ -850,7 +850,8 @@ static int t1_set_mac_addr(struct net_device *dev, void *p) return 0; } -static u32 t1_fix_features(struct net_device *dev, u32 features) +static netdev_features_t t1_fix_features(struct net_device *dev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -864,9 +865,9 @@ static u32 t1_fix_features(struct net_device *dev, u32 features) return features; } -static int t1_set_features(struct net_device *dev, u32 features) +static int t1_set_features(struct net_device *dev, netdev_features_t features) { - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; struct adapter *adapter = dev->ml_priv; if (changed & NETIF_F_HW_VLAN_RX) diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c index f9b602300040..47a84359d4e4 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -742,7 +742,7 @@ static inline void setup_ring_params(struct adapter *adapter, u64 addr, /* * Enable/disable VLAN acceleration. */ -void t1_vlan_mode(struct adapter *adapter, u32 features) +void t1_vlan_mode(struct adapter *adapter, netdev_features_t features) { struct sge *sge = adapter->sge; diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.h b/drivers/net/ethernet/chelsio/cxgb/sge.h index e03980bcdd65..b9bf16b385f7 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.h +++ b/drivers/net/ethernet/chelsio/cxgb/sge.h @@ -79,7 +79,7 @@ irqreturn_t t1_interrupt(int irq, void *cookie); int t1_poll(struct napi_struct *, int); netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev); -void t1_vlan_mode(struct adapter *adapter, u32 features); +void t1_vlan_mode(struct adapter *adapter, netdev_features_t features); void t1_sge_start(struct sge *); void t1_sge_stop(struct sge *); int t1_sge_intr_error_handler(struct sge *); diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 053560da6347..63ffaa7e255f 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -2532,7 +2532,7 @@ static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p) } } -static void cxgb_vlan_mode(struct net_device *dev, u32 features) +static void cxgb_vlan_mode(struct net_device *dev, netdev_features_t features) { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; @@ -2553,7 +2553,8 @@ static void cxgb_vlan_mode(struct net_device *dev, u32 features) t3_synchronize_rx(adapter, pi); } -static u32 cxgb_fix_features(struct net_device *dev, u32 features) +static netdev_features_t cxgb_fix_features(struct net_device *dev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -2567,9 +2568,9 @@ static u32 cxgb_fix_features(struct net_device *dev, u32 features) return features; } -static int cxgb_set_features(struct net_device *dev, u32 features) +static int cxgb_set_features(struct net_device *dev, netdev_features_t features) { - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; if (changed & NETIF_F_HW_VLAN_RX) cxgb_vlan_mode(dev, features); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 48ffe11d9aa9..fd6d460ea475 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1856,10 +1856,10 @@ static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return err; } -static int cxgb_set_features(struct net_device *dev, u32 features) +static int cxgb_set_features(struct net_device *dev, netdev_features_t features) { const struct port_info *pi = netdev_priv(dev); - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; int err; if (!(changed & NETIF_F_HW_VLAN_RX)) @@ -3538,7 +3538,7 @@ static int __devinit init_one(struct pci_dev *pdev, { int func, i, err; struct port_info *pi; - unsigned int highdma = 0; + bool highdma = false; struct adapter *adapter = NULL; printk_once(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); @@ -3564,7 +3564,7 @@ static int __devinit init_one(struct pci_dev *pdev, } if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - highdma = NETIF_F_HIGHDMA; + highdma = true; err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); if (err) { dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " @@ -3638,7 +3638,9 @@ static int __devinit init_one(struct pci_dev *pdev, NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | NETIF_F_RXHASH | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->features |= netdev->hw_features | highdma; + if (highdma) + netdev->hw_features |= NETIF_F_HIGHDMA; + netdev->features |= netdev->hw_features; netdev->vlan_features = netdev->features & VLAN_FEAT; netdev->priv_flags |= IFF_UNICAST_FLT; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index ee81d8e798ea..8155cfecae19 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -1092,7 +1092,8 @@ static int cxgb4vf_change_mtu(struct net_device *dev, int new_mtu) return ret; } -static u32 cxgb4vf_fix_features(struct net_device *dev, u32 features) +static netdev_features_t cxgb4vf_fix_features(struct net_device *dev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -1106,10 +1107,11 @@ static u32 cxgb4vf_fix_features(struct net_device *dev, u32 features) return features; } -static int cxgb4vf_set_features(struct net_device *dev, u32 features) +static int cxgb4vf_set_features(struct net_device *dev, + netdev_features_t features) { struct port_info *pi = netdev_priv(dev); - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; if (changed & NETIF_F_HW_VLAN_RX) t4vf_set_rxmode(pi->adapter, pi->viid, -1, -1, -1, -1, diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 438f4580bf66..26be1dfc1577 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -474,10 +474,11 @@ static int dm9000_nway_reset(struct net_device *dev) return mii_nway_restart(&dm->mii); } -static int dm9000_set_features(struct net_device *dev, u32 features) +static int dm9000_set_features(struct net_device *dev, + netdev_features_t features) { board_info_t *dm = to_dm9000_board(dev); - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; unsigned long flags; if (!(changed & NETIF_F_RXCSUM)) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 83199fd0d62b..ff3e8b0f0da3 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2306,7 +2306,7 @@ void gfar_check_rx_parser_mode(struct gfar_private *priv) } /* Enables and disables VLAN insertion/extraction */ -void gfar_vlan_mode(struct net_device *dev, u32 features) +void gfar_vlan_mode(struct net_device *dev, netdev_features_t features) { struct gfar_private *priv = netdev_priv(dev); struct gfar __iomem *regs = NULL; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 9aa43773e8e3..cda6cb2eb1d2 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1179,9 +1179,9 @@ extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, extern void gfar_configure_coalescing(struct gfar_private *priv, unsigned long tx_mask, unsigned long rx_mask); void gfar_init_sysfs(struct net_device *dev); -int gfar_set_features(struct net_device *dev, u32 features); +int gfar_set_features(struct net_device *dev, netdev_features_t features); extern void gfar_check_rx_parser_mode(struct gfar_private *priv); -extern void gfar_vlan_mode(struct net_device *dev, u32 features); +extern void gfar_vlan_mode(struct net_device *dev, netdev_features_t features); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 212736bab6bb..1ea0eb9ee643 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -519,12 +519,12 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva return err; } -int gfar_set_features(struct net_device *dev, u32 features) +int gfar_set_features(struct net_device *dev, netdev_features_t features) { struct gfar_private *priv = netdev_priv(dev); unsigned long flags; int err = 0, i = 0; - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) gfar_vlan_mode(dev, features); diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index b1cd41b9c61c..e877371680a9 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -735,7 +735,8 @@ static void netdev_get_drvinfo(struct net_device *dev, sizeof(info->version) - 1); } -static u32 ibmveth_fix_features(struct net_device *dev, u32 features) +static netdev_features_t ibmveth_fix_features(struct net_device *dev, + netdev_features_t features) { /* * Since the ibmveth firmware interface does not have the @@ -838,7 +839,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) return rc1 ? rc1 : rc2; } -static int ibmveth_set_features(struct net_device *dev, u32 features) +static int ibmveth_set_features(struct net_device *dev, + netdev_features_t features) { struct ibmveth_adapter *adapter = netdev_priv(dev); int rx_csum = !!(features & NETIF_F_RXCSUM); diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index cf480b554622..82f4ef142259 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -167,7 +167,8 @@ static int e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb); static bool e1000_vlan_used(struct e1000_adapter *adapter); -static void e1000_vlan_mode(struct net_device *netdev, u32 features); +static void e1000_vlan_mode(struct net_device *netdev, + netdev_features_t features); static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid); static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid); static void e1000_restore_vlan(struct e1000_adapter *adapter); @@ -806,7 +807,8 @@ static int e1000_is_need_ioport(struct pci_dev *pdev) } } -static u32 e1000_fix_features(struct net_device *netdev, u32 features) +static netdev_features_t e1000_fix_features(struct net_device *netdev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -820,10 +822,11 @@ static u32 e1000_fix_features(struct net_device *netdev, u32 features) return features; } -static int e1000_set_features(struct net_device *netdev, u32 features) +static int e1000_set_features(struct net_device *netdev, + netdev_features_t features) { struct e1000_adapter *adapter = netdev_priv(netdev); - u32 changed = features ^ netdev->features; + netdev_features_t changed = features ^ netdev->features; if (changed & NETIF_F_HW_VLAN_RX) e1000_vlan_mode(netdev, features); @@ -4577,7 +4580,8 @@ static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter, e1000_irq_enable(adapter); } -static void e1000_vlan_mode(struct net_device *netdev, u32 features) +static void e1000_vlan_mode(struct net_device *netdev, + netdev_features_t features) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index a855db1ad249..d85fac626a80 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -5859,10 +5859,11 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter) } } -static int e1000_set_features(struct net_device *netdev, u32 features) +static int e1000_set_features(struct net_device *netdev, + netdev_features_t features) { struct e1000_adapter *adapter = netdev_priv(netdev); - u32 changed = features ^ netdev->features; + netdev_features_t changed = features ^ netdev->features; if (changed & (NETIF_F_TSO | NETIF_F_TSO6)) adapter->flags |= FLAG_TSO_FORCE; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ced544499f1b..1fcba22c6403 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -145,7 +145,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *, int); static int igb_ioctl(struct net_device *, struct ifreq *, int cmd); static void igb_tx_timeout(struct net_device *); static void igb_reset_task(struct work_struct *); -static void igb_vlan_mode(struct net_device *netdev, u32 features); +static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features); static void igb_vlan_rx_add_vid(struct net_device *, u16); static void igb_vlan_rx_kill_vid(struct net_device *, u16); static void igb_restore_vlan(struct igb_adapter *); @@ -1742,7 +1742,8 @@ void igb_reset(struct igb_adapter *adapter) igb_get_phy_info(hw); } -static u32 igb_fix_features(struct net_device *netdev, u32 features) +static netdev_features_t igb_fix_features(struct net_device *netdev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -1756,9 +1757,10 @@ static u32 igb_fix_features(struct net_device *netdev, u32 features) return features; } -static int igb_set_features(struct net_device *netdev, u32 features) +static int igb_set_features(struct net_device *netdev, + netdev_features_t features) { - u32 changed = netdev->features ^ features; + netdev_features_t changed = netdev->features ^ features; if (changed & NETIF_F_HW_VLAN_RX) igb_vlan_mode(netdev, features); @@ -6467,7 +6469,7 @@ s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) return 0; } -static void igb_vlan_mode(struct net_device *netdev, u32 features) +static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index cca78124be31..2a05658938bd 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -2532,7 +2532,8 @@ static void igbvf_print_device_info(struct igbvf_adapter *adapter) dev_info(&pdev->dev, "Address: %pM\n", netdev->dev_addr); } -static int igbvf_set_features(struct net_device *netdev, u32 features) +static int igbvf_set_features(struct net_device *netdev, + netdev_features_t features) { struct igbvf_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index e21148f8b160..247cf9219e03 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -325,8 +325,8 @@ ixgb_reset(struct ixgb_adapter *adapter) } } -static u32 -ixgb_fix_features(struct net_device *netdev, u32 features) +static netdev_features_t +ixgb_fix_features(struct net_device *netdev, netdev_features_t features) { /* * Tx VLAN insertion does not work per HW design when Rx stripping is @@ -339,10 +339,10 @@ ixgb_fix_features(struct net_device *netdev, u32 features) } static int -ixgb_set_features(struct net_device *netdev, u32 features) +ixgb_set_features(struct net_device *netdev, netdev_features_t features) { struct ixgb_adapter *adapter = netdev_priv(netdev); - u32 changed = features ^ netdev->features; + netdev_features_t changed = features ^ netdev->features; if (!(changed & (NETIF_F_RXCSUM|NETIF_F_HW_VLAN_RX))) return 0; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 8ef92d1a6aa1..820fc040c241 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7174,7 +7174,8 @@ void ixgbe_do_reset(struct net_device *netdev) ixgbe_reset(adapter); } -static u32 ixgbe_fix_features(struct net_device *netdev, u32 data) +static netdev_features_t ixgbe_fix_features(struct net_device *netdev, + netdev_features_t data) { struct ixgbe_adapter *adapter = netdev_priv(netdev); @@ -7204,7 +7205,8 @@ static u32 ixgbe_fix_features(struct net_device *netdev, u32 data) return data; } -static int ixgbe_set_features(struct net_device *netdev, u32 data) +static int ixgbe_set_features(struct net_device *netdev, + netdev_features_t data) { struct ixgbe_adapter *adapter = netdev_priv(netdev); bool need_reset = false; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 4c8e19951d57..3e6ec088c50d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3249,7 +3249,8 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev, return stats; } -static int ixgbevf_set_features(struct net_device *netdev, u32 features) +static int ixgbevf_set_features(struct net_device *netdev, + netdev_features_t features) { struct ixgbevf_adapter *adapter = netdev_priv(netdev); diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 7d88c7c28a7c..df3ab831b1ad 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -1917,7 +1917,7 @@ jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx) struct jme_ring *txring = &(jme->txring[0]); struct txdesc *txdesc = txring->desc, *ctxdesc; struct jme_buffer_info *txbi = txring->bufinf, *ctxbi; - u8 hidma = jme->dev->features & NETIF_F_HIGHDMA; + u8 hidma = !!(jme->dev->features & NETIF_F_HIGHDMA); int i, nr_frags = skb_shinfo(skb)->nr_frags; int mask = jme->tx_ring_mask; const struct skb_frag_struct *frag; @@ -2620,8 +2620,8 @@ jme_set_msglevel(struct net_device *netdev, u32 value) jme->msg_enable = value; } -static u32 -jme_fix_features(struct net_device *netdev, u32 features) +static netdev_features_t +jme_fix_features(struct net_device *netdev, netdev_features_t features) { if (netdev->mtu > 1900) features &= ~(NETIF_F_ALL_TSO | NETIF_F_ALL_CSUM); @@ -2629,7 +2629,7 @@ jme_fix_features(struct net_device *netdev, u32 features) } static int -jme_set_features(struct net_device *netdev, u32 features) +jme_set_features(struct net_device *netdev, netdev_features_t features) { struct jme_adapter *jme = netdev_priv(netdev); diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index f6b4304ca459..157c5c17fdcc 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -1579,10 +1579,10 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er) static int -mv643xx_eth_set_features(struct net_device *dev, u32 features) +mv643xx_eth_set_features(struct net_device *dev, netdev_features_t features) { struct mv643xx_eth_private *mp = netdev_priv(dev); - u32 rx_csum = features & NETIF_F_RXCSUM; + int rx_csum = !!(features & NETIF_F_RXCSUM); wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000); diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 553d1a315b3a..c79dc5447658 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -1275,7 +1275,7 @@ static void rx_set_checksum(struct sky2_port *sky2) } /* Enable/disable receive hash calculation (RSS) */ -static void rx_set_rss(struct net_device *dev, u32 features) +static void rx_set_rss(struct net_device *dev, netdev_features_t features) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; @@ -1396,7 +1396,7 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) #define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO) -static void sky2_vlan_mode(struct net_device *dev, u32 features) +static void sky2_vlan_mode(struct net_device *dev, netdev_features_t features) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; @@ -4282,7 +4282,8 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len); } -static u32 sky2_fix_features(struct net_device *dev, u32 features) +static netdev_features_t sky2_fix_features(struct net_device *dev, + netdev_features_t features) { const struct sky2_port *sky2 = netdev_priv(dev); const struct sky2_hw *hw = sky2->hw; @@ -4306,13 +4307,13 @@ static u32 sky2_fix_features(struct net_device *dev, u32 features) return features; } -static int sky2_set_features(struct net_device *dev, u32 features) +static int sky2_set_features(struct net_device *dev, netdev_features_t features) { struct sky2_port *sky2 = netdev_priv(dev); - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; if (changed & NETIF_F_RXCSUM) { - u32 on = features & NETIF_F_RXCSUM; + int on = !!(features & NETIF_F_RXCSUM); sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 3b67fe65404a..8d846bd09711 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -6588,7 +6588,8 @@ static void netdev_get_ethtool_stats(struct net_device *dev, * * Return 0 if successful; otherwise an error code. */ -static int netdev_set_features(struct net_device *dev, u32 features) +static int netdev_set_features(struct net_device *dev, + netdev_features_t features) { struct dev_priv *priv = netdev_priv(dev); struct dev_info *hw_priv = priv->adapter; diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 0778edcf7b9a..20b72ecb020a 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -1491,7 +1491,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) * access to avoid theoretical race condition with functions that * change NETIF_F_LRO flag at runtime. */ - bool lro_enabled = ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO; + bool lro_enabled = !!(ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO); while (rx_done->entry[idx].length != 0 && work_done < budget) { length = ntohs(rx_done->entry[idx].length); @@ -3149,7 +3149,8 @@ static int myri10ge_set_mac_address(struct net_device *dev, void *addr) return 0; } -static u32 myri10ge_fix_features(struct net_device *dev, u32 features) +static netdev_features_t myri10ge_fix_features(struct net_device *dev, + netdev_features_t features) { if (!(features & NETIF_F_RXCSUM)) features &= ~NETIF_F_LRO; diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index e6c90a5ac5d4..76ae47627200 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -6616,10 +6616,10 @@ static void s2io_ethtool_get_strings(struct net_device *dev, } } -static int s2io_set_features(struct net_device *dev, u32 features) +static int s2io_set_features(struct net_device *dev, netdev_features_t features) { struct s2io_nic *sp = netdev_priv(dev); - u32 changed = (features ^ dev->features) & NETIF_F_LRO; + netdev_features_t changed = (features ^ dev->features) & NETIF_F_LRO; if (changed && netif_running(dev)) { int rc; diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index a83197d757c1..16d4d8e913c3 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -2662,9 +2662,10 @@ static void vxge_poll_vp_lockup(unsigned long data) mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000); } -static u32 vxge_fix_features(struct net_device *dev, u32 features) +static netdev_features_t vxge_fix_features(struct net_device *dev, + netdev_features_t features) { - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; /* Enabling RTH requires some of the logic in vxge_device_register and a * vpath reset. Due to these restrictions, only allow modification @@ -2676,10 +2677,10 @@ static u32 vxge_fix_features(struct net_device *dev, u32 features) return features; } -static int vxge_set_features(struct net_device *dev, u32 features) +static int vxge_set_features(struct net_device *dev, netdev_features_t features) { struct vxgedev *vdev = netdev_priv(dev); - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; if (!(changed & NETIF_F_RXHASH)) return 0; diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index e8a5ae356407..01bb7bfe14e6 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -4536,7 +4536,7 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* return 0; } -static int nv_set_loopback(struct net_device *dev, u32 features) +static int nv_set_loopback(struct net_device *dev, netdev_features_t features) { struct fe_priv *np = netdev_priv(dev); unsigned long flags; @@ -4591,7 +4591,8 @@ static int nv_set_loopback(struct net_device *dev, u32 features) return retval; } -static u32 nv_fix_features(struct net_device *dev, u32 features) +static netdev_features_t nv_fix_features(struct net_device *dev, + netdev_features_t features) { /* vlan is dependent on rx checksum offload */ if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) @@ -4600,7 +4601,7 @@ static u32 nv_fix_features(struct net_device *dev, u32 features) return features; } -static void nv_vlan_mode(struct net_device *dev, u32 features) +static void nv_vlan_mode(struct net_device *dev, netdev_features_t features) { struct fe_priv *np = get_nvpriv(dev); @@ -4621,11 +4622,11 @@ static void nv_vlan_mode(struct net_device *dev, u32 features) spin_unlock_irq(&np->lock); } -static int nv_set_features(struct net_device *dev, u32 features) +static int nv_set_features(struct net_device *dev, netdev_features_t features) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - u32 changed = dev->features ^ features; + netdev_features_t changed = dev->features ^ features; int retval; if ((changed & NETIF_F_LOOPBACK) && netif_running(dev)) { diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c index 48406ca382f1..964e9c0948bc 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c @@ -2109,10 +2109,11 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu) * Returns * 0: HW state updated successfully */ -static int pch_gbe_set_features(struct net_device *netdev, u32 features) +static int pch_gbe_set_features(struct net_device *netdev, + netdev_features_t features) { struct pch_gbe_adapter *adapter = netdev_priv(netdev); - u32 changed = features ^ netdev->features; + netdev_features_t changed = features ^ netdev->features; if (!(changed & NETIF_F_RXCSUM)) return 0; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 8cf3173ba488..7dd9a4b107e6 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -544,7 +544,8 @@ static void netxen_set_multicast_list(struct net_device *dev) adapter->set_multi(dev); } -static u32 netxen_fix_features(struct net_device *dev, u32 features) +static netdev_features_t netxen_fix_features(struct net_device *dev, + netdev_features_t features) { if (!(features & NETIF_F_RXCSUM)) { netdev_info(dev, "disabling LRO as RXCSUM is off\n"); @@ -555,7 +556,8 @@ static u32 netxen_fix_features(struct net_device *dev, u32 features) return features; } -static int netxen_set_features(struct net_device *dev, u32 features) +static int netxen_set_features(struct net_device *dev, + netdev_features_t features) { struct netxen_adapter *adapter = netdev_priv(dev); int hw_lro; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 7ed53dbb8646..60976fc4ccc6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -1466,8 +1466,9 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup); int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu); int qlcnic_change_mtu(struct net_device *netdev, int new_mtu); -u32 qlcnic_fix_features(struct net_device *netdev, u32 features); -int qlcnic_set_features(struct net_device *netdev, u32 features); +netdev_features_t qlcnic_fix_features(struct net_device *netdev, + netdev_features_t features); +int qlcnic_set_features(struct net_device *netdev, netdev_features_t features); int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable); int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable); int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index bcb81e47543a..b528e52a8ee1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -817,12 +817,13 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu) } -u32 qlcnic_fix_features(struct net_device *netdev, u32 features) +netdev_features_t qlcnic_fix_features(struct net_device *netdev, + netdev_features_t features) { struct qlcnic_adapter *adapter = netdev_priv(netdev); if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) { - u32 changed = features ^ netdev->features; + netdev_features_t changed = features ^ netdev->features; features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); } @@ -833,10 +834,10 @@ u32 qlcnic_fix_features(struct net_device *netdev, u32 features) } -int qlcnic_set_features(struct net_device *netdev, u32 features) +int qlcnic_set_features(struct net_device *netdev, netdev_features_t features) { struct qlcnic_adapter *adapter = netdev_priv(netdev); - u32 changed = netdev->features ^ features; + netdev_features_t changed = netdev->features ^ features; int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0; if (!(changed & NETIF_F_LRO)) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 0bd163828e33..823f845ddc04 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -792,7 +792,7 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter, struct qlcnic_esw_func_cfg *esw_cfg) { struct net_device *netdev = adapter->netdev; - unsigned long features, vlan_features; + netdev_features_t features, vlan_features; features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO); diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index c92afcd912e2..1ce4e08037b8 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -2307,7 +2307,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) return work_done; } -static void qlge_vlan_mode(struct net_device *ndev, u32 features) +static void qlge_vlan_mode(struct net_device *ndev, netdev_features_t features) { struct ql_adapter *qdev = netdev_priv(ndev); @@ -2323,7 +2323,8 @@ static void qlge_vlan_mode(struct net_device *ndev, u32 features) } } -static u32 qlge_fix_features(struct net_device *ndev, u32 features) +static netdev_features_t qlge_fix_features(struct net_device *ndev, + netdev_features_t features) { /* * Since there is no support for separate rx/tx vlan accel @@ -2337,9 +2338,10 @@ static u32 qlge_fix_features(struct net_device *ndev, u32 features) return features; } -static int qlge_set_features(struct net_device *ndev, u32 features) +static int qlge_set_features(struct net_device *ndev, + netdev_features_t features) { - u32 changed = ndev->features ^ features; + netdev_features_t changed = ndev->features ^ features; if (changed & NETIF_F_HW_VLAN_RX) qlge_vlan_mode(ndev, features); diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 6cfc5dc0f76e..87cff10f7be7 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -1392,7 +1392,7 @@ static void cp_set_msglevel(struct net_device *dev, u32 value) cp->msg_enable = value; } -static int cp_set_features(struct net_device *dev, u32 features) +static int cp_set_features(struct net_device *dev, netdev_features_t features) { struct cp_private *cp = netdev_priv(dev); unsigned long flags; diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index cdf66d68d849..2dfb0c0ea01b 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -1553,7 +1553,8 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return ret; } -static u32 rtl8169_fix_features(struct net_device *dev, u32 features) +static netdev_features_t rtl8169_fix_features(struct net_device *dev, + netdev_features_t features) { struct rtl8169_private *tp = netdev_priv(dev); @@ -1567,7 +1568,8 @@ static u32 rtl8169_fix_features(struct net_device *dev, u32 features) return features; } -static int rtl8169_set_features(struct net_device *dev, u32 features) +static int rtl8169_set_features(struct net_device *dev, + netdev_features_t features) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index d5731f1fe6d6..14e134d3b4d7 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1900,7 +1900,7 @@ static void efx_set_multicast_list(struct net_device *net_dev) /* Otherwise efx_start_port() will do this */ } -static int efx_set_features(struct net_device *net_dev, u32 data) +static int efx_set_features(struct net_device *net_dev, netdev_features_t data) { struct efx_nic *efx = netdev_priv(net_dev); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index b8e251a1ee48..c49502bab6a3 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -908,7 +908,7 @@ struct efx_nic_type { unsigned int phys_addr_channels; unsigned int tx_dc_base; unsigned int rx_dc_base; - u32 offload_features; + netdev_features_t offload_features; }; /************************************************************************** diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 20546bbbb8db..643ca97a2d9a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1419,7 +1419,8 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static u32 stmmac_fix_features(struct net_device *dev, u32 features) +static netdev_features_t stmmac_fix_features(struct net_device *dev, + netdev_features_t features) { struct stmmac_priv *priv = netdev_priv(dev); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8592523b0bb5..3dd13d606d00 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -123,7 +123,7 @@ struct tun_struct { gid_t group; struct net_device *dev; - u32 set_features; + netdev_features_t set_features; #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ NETIF_F_TSO6|NETIF_F_UFO) struct fasync_struct *fasync; @@ -454,7 +454,8 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu) return 0; } -static u32 tun_net_fix_features(struct net_device *dev, u32 features) +static netdev_features_t tun_net_fix_features(struct net_device *dev, + netdev_features_t features) { struct tun_struct *tun = netdev_priv(dev); @@ -1196,7 +1197,7 @@ static int tun_get_iff(struct net *net, struct tun_struct *tun, * privs required. */ static int set_offload(struct tun_struct *tun, unsigned long arg) { - u32 features = 0; + netdev_features_t features = 0; if (arg & TUN_F_CSUM) { features |= NETIF_F_HW_CSUM; diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index a5b9b12ef268..7d62c39f65cf 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -728,7 +728,8 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) } /* Enable or disable Rx checksum offload engine */ -static int smsc75xx_set_features(struct net_device *netdev, u32 features) +static int smsc75xx_set_features(struct net_device *netdev, + netdev_features_t features) { struct usbnet *dev = netdev_priv(netdev); struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index eff67678c5a6..56f3894d701a 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -516,7 +516,8 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) } /* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_features(struct net_device *netdev, u32 features) +static int smsc95xx_set_features(struct net_device *netdev, + netdev_features_t features) { struct usbnet *dev = netdev_priv(netdev); u32 read_buf; diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index e662cbc8bfbd..77f723415c9c 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -262,11 +262,11 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) } } -int vmxnet3_set_features(struct net_device *netdev, u32 features) +int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features) { struct vmxnet3_adapter *adapter = netdev_priv(netdev); unsigned long flags; - u32 changed = features ^ netdev->features; + netdev_features_t changed = features ^ netdev->features; if (changed & (NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_RX)) { if (features & NETIF_F_RXCSUM) diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index b18eac1dccaa..ed54797db191 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -401,7 +401,7 @@ void vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter); int -vmxnet3_set_features(struct net_device *netdev, u32 features); +vmxnet3_set_features(struct net_device *netdev, netdev_features_t features); int vmxnet3_create_queues(struct vmxnet3_adapter *adapter, diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 182562952c79..0b5c18feb303 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -165,7 +165,8 @@ static int xenvif_change_mtu(struct net_device *dev, int mtu) return 0; } -static u32 xenvif_fix_features(struct net_device *dev, u32 features) +static netdev_features_t xenvif_fix_features(struct net_device *dev, + netdev_features_t features) { struct xenvif *vif = netdev_priv(dev); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 226faab23603..a6e379fbf377 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -203,7 +203,7 @@ static void xennet_sysfs_delif(struct net_device *netdev); static int xennet_can_sg(struct net_device *dev) { - return dev->features & NETIF_F_SG; + return !!(dev->features & NETIF_F_SG); } @@ -1190,7 +1190,8 @@ static void xennet_uninit(struct net_device *dev) gnttab_free_grant_references(np->gref_rx_head); } -static u32 xennet_fix_features(struct net_device *dev, u32 features) +static netdev_features_t xennet_fix_features(struct net_device *dev, + netdev_features_t features) { struct netfront_info *np = netdev_priv(dev); int val; @@ -1216,7 +1217,8 @@ static u32 xennet_fix_features(struct net_device *dev, u32 features) return features; } -static int xennet_set_features(struct net_device *dev, u32 features) +static int xennet_set_features(struct net_device *dev, + netdev_features_t features) { if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) { netdev_info(dev, "Reducing MTU because no SG offload"); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index e4c1176ee25b..a64f9e789b0a 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3202,7 +3202,8 @@ static int qeth_l3_stop(struct net_device *dev) return 0; } -static u32 qeth_l3_fix_features(struct net_device *dev, u32 features) +static netdev_features_t qeth_l3_fix_features(struct net_device *dev, + netdev_features_t features) { struct qeth_card *card = dev->ml_priv; @@ -3216,7 +3217,8 @@ static u32 qeth_l3_fix_features(struct net_device *dev, u32 features) return features; } -static int qeth_l3_set_features(struct net_device *dev, u32 features) +static int qeth_l3_set_features(struct net_device *dev, + netdev_features_t features) { struct qeth_card *card = dev->ml_priv; u32 changed = dev->features ^ features; diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index 32640edf4d78..af5238121826 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -10,6 +10,10 @@ #ifndef _LINUX_NETDEV_FEATURES_H #define _LINUX_NETDEV_FEATURES_H +#include + +typedef u32 netdev_features_t; + /* Net device feature bits; if you change something, * also update netdev_features_strings[] in ethtool.c */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9cf6e90b171d..b35ffd735ecc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -847,12 +847,13 @@ struct netdev_tc_txq { * Called to release previously enslaved netdev. * * Feature/offload setting functions. - * u32 (*ndo_fix_features)(struct net_device *dev, u32 features); + * netdev_features_t (*ndo_fix_features)(struct net_device *dev, + * netdev_features_t features); * Adjusts the requested feature flags according to device-specific * constraints, and returns the resulting flags. Must not modify * the device state. * - * int (*ndo_set_features)(struct net_device *dev, u32 features); + * int (*ndo_set_features)(struct net_device *dev, netdev_features_t features); * Called to update device configuration to new features. Passed * feature set might be less than what was returned by ndo_fix_features()). * Must return >0 or -errno if it changed dev->features itself. @@ -946,10 +947,10 @@ struct net_device_ops { struct net_device *slave_dev); int (*ndo_del_slave)(struct net_device *dev, struct net_device *slave_dev); - u32 (*ndo_fix_features)(struct net_device *dev, - u32 features); + netdev_features_t (*ndo_fix_features)(struct net_device *dev, + netdev_features_t features); int (*ndo_set_features)(struct net_device *dev, - u32 features); + netdev_features_t features); }; /* @@ -999,13 +1000,13 @@ struct net_device { struct list_head unreg_list; /* currently active device features */ - u32 features; + netdev_features_t features; /* user-changeable features */ - u32 hw_features; + netdev_features_t hw_features; /* user-requested features */ - u32 wanted_features; + netdev_features_t wanted_features; /* mask of features inheritable by VLAN devices */ - u32 vlan_features; + netdev_features_t vlan_features; /* Interface index. Unique device identifier */ int ifindex; @@ -1439,7 +1440,7 @@ struct packet_type { struct packet_type *, struct net_device *); struct sk_buff *(*gso_segment)(struct sk_buff *skb, - u32 features); + netdev_features_t features); int (*gso_send_check)(struct sk_buff *skb); struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); @@ -2444,7 +2445,8 @@ extern int netdev_set_master(struct net_device *dev, struct net_device *master) extern int netdev_set_bond_master(struct net_device *dev, struct net_device *master); extern int skb_checksum_help(struct sk_buff *skb); -extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features); +extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, + netdev_features_t features); #ifdef CONFIG_BUG extern void netdev_rx_csum_fault(struct net_device *dev); #else @@ -2471,11 +2473,13 @@ extern const char *netdev_drivername(const struct net_device *dev); extern void linkwatch_run_queue(void); -static inline u32 netdev_get_wanted_features(struct net_device *dev) +static inline netdev_features_t netdev_get_wanted_features( + struct net_device *dev) { return (dev->features & ~dev->hw_features) | dev->wanted_features; } -u32 netdev_increment_features(u32 all, u32 one, u32 mask); +netdev_features_t netdev_increment_features(netdev_features_t all, + netdev_features_t one, netdev_features_t mask); int __netdev_update_features(struct net_device *dev); void netdev_update_features(struct net_device *dev); void netdev_change_features(struct net_device *dev); @@ -2483,21 +2487,22 @@ void netdev_change_features(struct net_device *dev); void netif_stacked_transfer_operstate(const struct net_device *rootdev, struct net_device *dev); -u32 netif_skb_features(struct sk_buff *skb); +netdev_features_t netif_skb_features(struct sk_buff *skb); -static inline int net_gso_ok(u32 features, int gso_type) +static inline int net_gso_ok(netdev_features_t features, int gso_type) { - int feature = gso_type << NETIF_F_GSO_SHIFT; + netdev_features_t feature = gso_type << NETIF_F_GSO_SHIFT; return (features & feature) == feature; } -static inline int skb_gso_ok(struct sk_buff *skb, u32 features) +static inline int skb_gso_ok(struct sk_buff *skb, netdev_features_t features) { return net_gso_ok(features, skb_shinfo(skb)->gso_type) && (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST)); } -static inline int netif_needs_gso(struct sk_buff *skb, int features) +static inline int netif_needs_gso(struct sk_buff *skb, + netdev_features_t features) { return skb_is_gso(skb) && (!skb_gso_ok(skb, features) || unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index abad8a0941e8..a10e487c0864 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -30,6 +30,7 @@ #include #include #include +#include /* Don't change this without changing skb_csum_unnecessary! */ #define CHECKSUM_NONE 0 @@ -2106,7 +2107,8 @@ extern void skb_split(struct sk_buff *skb, extern int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); -extern struct sk_buff *skb_segment(struct sk_buff *skb, u32 features); +extern struct sk_buff *skb_segment(struct sk_buff *skb, + netdev_features_t features); static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) diff --git a/include/net/protocol.h b/include/net/protocol.h index 6f7eb800974a..e182e13d6391 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -38,7 +38,7 @@ struct net_protocol { void (*err_handler)(struct sk_buff *skb, u32 info); int (*gso_send_check)(struct sk_buff *skb); struct sk_buff *(*gso_segment)(struct sk_buff *skb, - u32 features); + netdev_features_t features); struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); int (*gro_complete)(struct sk_buff *skb); @@ -57,7 +57,7 @@ struct inet6_protocol { int (*gso_send_check)(struct sk_buff *skb); struct sk_buff *(*gso_segment)(struct sk_buff *skb, - u32 features); + netdev_features_t features); struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); int (*gro_complete)(struct sk_buff *skb); diff --git a/include/net/sock.h b/include/net/sock.h index 67cd4581b6da..1331008ad885 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -306,8 +306,8 @@ struct sock { kmemcheck_bitfield_end(flags); int sk_wmem_queued; gfp_t sk_allocation; - int sk_route_caps; - int sk_route_nocaps; + netdev_features_t sk_route_caps; + netdev_features_t sk_route_nocaps; int sk_gso_type; unsigned int sk_gso_max_size; int sk_rcvlowat; @@ -1393,7 +1393,7 @@ static inline int sk_can_gso(const struct sock *sk) extern void sk_setup_caps(struct sock *sk, struct dst_entry *dst); -static inline void sk_nocaps_add(struct sock *sk, int flags) +static inline void sk_nocaps_add(struct sock *sk, netdev_features_t flags) { sk->sk_route_nocaps |= flags; sk->sk_route_caps &= ~flags; diff --git a/include/net/tcp.h b/include/net/tcp.h index bb18c4d69aba..113160b84588 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1430,7 +1430,8 @@ extern struct request_sock_ops tcp6_request_sock_ops; extern void tcp_v4_destroy_sock(struct sock *sk); extern int tcp_v4_gso_send_check(struct sk_buff *skb); -extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, u32 features); +extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, + netdev_features_t features); extern struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb); extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head, diff --git a/include/net/udp.h b/include/net/udp.h index 3b285f402f48..f54a5156b248 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -258,5 +258,6 @@ extern void udp4_proc_exit(void); extern void udp_init(void); extern int udp4_ufo_send_check(struct sk_buff *skb); -extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, u32 features); +extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, + netdev_features_t features); #endif /* _UDP_H */ diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 993599e66e5a..8e75003d62f6 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -777,6 +777,18 @@ char *uuid_string(char *buf, char *end, const u8 *addr, return string(buf, end, uuid, spec); } +static +char *netdev_feature_string(char *buf, char *end, const u8 *addr, + struct printf_spec spec) +{ + spec.flags |= SPECIAL | SMALL | ZEROPAD; + if (spec.field_width == -1) + spec.field_width = 2 + 2 * sizeof(netdev_features_t); + spec.base = 16; + + return number(buf, end, *(const netdev_features_t *)addr, spec); +} + int kptr_restrict __read_mostly; /* @@ -824,6 +836,7 @@ int kptr_restrict __read_mostly; * Do not use this feature without some mechanism to verify the * correctness of the format string and va_list arguments. * - 'K' For a kernel pointer that should be hidden from unprivileged users + * - 'NF' For a netdev_features_t * * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 * function pointers are really function descriptors, which contain a @@ -896,6 +909,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, has_capability_noaudit(current, CAP_SYSLOG)))) ptr = NULL; break; + case 'N': + switch (fmt[1]) { + case 'F': + return netdev_feature_string(buf, end, ptr, spec); + } + break; } spec.flags |= SMALL; if (spec.field_width == -1) { diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 6a4e0cb897b7..2b5fcde1f629 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -591,7 +591,8 @@ static void vlan_dev_uninit(struct net_device *dev) } } -static u32 vlan_dev_fix_features(struct net_device *dev, u32 features) +static netdev_features_t vlan_dev_fix_features(struct net_device *dev, + netdev_features_t features) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; u32 old_features = features; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index feb77ea7b58e..772bad34794c 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -186,7 +186,8 @@ static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) strcpy(info->bus_info, "N/A"); } -static u32 br_fix_features(struct net_device *dev, u32 features) +static netdev_features_t br_fix_features(struct net_device *dev, + netdev_features_t features) { struct net_bridge *br = netdev_priv(dev); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f603e5b0b930..0a942fbccc9a 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -296,10 +296,11 @@ int br_min_mtu(const struct net_bridge *br) /* * Recomputes features using slave's features */ -u32 br_features_recompute(struct net_bridge *br, u32 features) +netdev_features_t br_features_recompute(struct net_bridge *br, + netdev_features_t features) { struct net_bridge_port *p; - u32 mask; + netdev_features_t mask; if (list_empty(&br->port_list)) return features; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d7d6fb05411f..4027029aa5e4 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -387,7 +387,8 @@ extern int br_add_if(struct net_bridge *br, extern int br_del_if(struct net_bridge *br, struct net_device *dev); extern int br_min_mtu(const struct net_bridge *br); -extern u32 br_features_recompute(struct net_bridge *br, u32 features); +extern netdev_features_t br_features_recompute(struct net_bridge *br, + netdev_features_t features); /* br_input.c */ extern int br_handle_frame_finish(struct sk_buff *skb); diff --git a/net/core/dev.c b/net/core/dev.c index 185e246d61fd..f1cca59c4638 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1914,7 +1914,8 @@ EXPORT_SYMBOL(skb_checksum_help); * It may return NULL if the skb requires no segmentation. This is * only possible when GSO is used for verifying header integrity. */ -struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features) +struct sk_buff *skb_gso_segment(struct sk_buff *skb, + netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); struct packet_type *ptype; @@ -1944,9 +1945,9 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features) if (dev && dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) dev->ethtool_ops->get_drvinfo(dev, &info); - WARN(1, "%s: caps=(0x%lx, 0x%lx) len=%d data_len=%d ip_summed=%d\n", - info.driver, dev ? dev->features : 0L, - skb->sk ? skb->sk->sk_route_caps : 0L, + WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d ip_summed=%d\n", + info.driver, dev ? &dev->features : NULL, + skb->sk ? &skb->sk->sk_route_caps : NULL, skb->len, skb->data_len, skb->ip_summed); if (skb_header_cloned(skb) && @@ -2055,7 +2056,7 @@ static void dev_gso_skb_destructor(struct sk_buff *skb) * This function segments the given skb and stores the list of segments * in skb->next. */ -static int dev_gso_segment(struct sk_buff *skb, int features) +static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features) { struct sk_buff *segs; @@ -2094,7 +2095,7 @@ static inline void skb_orphan_try(struct sk_buff *skb) } } -static bool can_checksum_protocol(unsigned long features, __be16 protocol) +static bool can_checksum_protocol(netdev_features_t features, __be16 protocol) { return ((features & NETIF_F_GEN_CSUM) || ((features & NETIF_F_V4_CSUM) && @@ -2105,7 +2106,8 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol) protocol == htons(ETH_P_FCOE))); } -static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 features) +static netdev_features_t harmonize_features(struct sk_buff *skb, + __be16 protocol, netdev_features_t features) { if (!can_checksum_protocol(features, protocol)) { features &= ~NETIF_F_ALL_CSUM; @@ -2117,10 +2119,10 @@ static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 features return features; } -u32 netif_skb_features(struct sk_buff *skb) +netdev_features_t netif_skb_features(struct sk_buff *skb) { __be16 protocol = skb->protocol; - u32 features = skb->dev->features; + netdev_features_t features = skb->dev->features; if (protocol == htons(ETH_P_8021Q)) { struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; @@ -2166,7 +2168,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, unsigned int skb_len; if (likely(!skb->next)) { - u32 features; + netdev_features_t features; /* * If device doesn't need skb->dst, release it right now while @@ -5350,7 +5352,8 @@ static void rollback_registered(struct net_device *dev) list_del(&single); } -static u32 netdev_fix_features(struct net_device *dev, u32 features) +static netdev_features_t netdev_fix_features(struct net_device *dev, + netdev_features_t features) { /* Fix illegal checksum combinations */ if ((features & NETIF_F_HW_CSUM) && @@ -5412,7 +5415,7 @@ static u32 netdev_fix_features(struct net_device *dev, u32 features) int __netdev_update_features(struct net_device *dev) { - u32 features; + netdev_features_t features; int err = 0; ASSERT_RTNL(); @@ -5428,16 +5431,16 @@ int __netdev_update_features(struct net_device *dev) if (dev->features == features) return 0; - netdev_dbg(dev, "Features changed: 0x%08x -> 0x%08x\n", - dev->features, features); + netdev_dbg(dev, "Features changed: %pNF -> %pNF\n", + &dev->features, &features); if (dev->netdev_ops->ndo_set_features) err = dev->netdev_ops->ndo_set_features(dev, features); if (unlikely(err < 0)) { netdev_err(dev, - "set_features() failed (%d); wanted 0x%08x, left 0x%08x\n", - err, features, dev->features); + "set_features() failed (%d); wanted %pNF, left %pNF\n", + err, &features, &dev->features); return -1; } @@ -6361,7 +6364,8 @@ static int dev_cpu_callback(struct notifier_block *nfb, * @one to the master device with current feature set @all. Will not * enable anything that is off in @mask. Returns the new feature set. */ -u32 netdev_increment_features(u32 all, u32 one, u32 mask) +netdev_features_t netdev_increment_features(netdev_features_t all, + netdev_features_t one, netdev_features_t mask) { if (mask & NETIF_F_GEN_CSUM) mask |= NETIF_F_ALL_CSUM; diff --git a/net/core/ethtool.c b/net/core/ethtool.c index a354919a32ac..f135f1c92c9d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -171,7 +171,7 @@ static void __ethtool_get_strings(struct net_device *dev, ops->get_strings(dev, stringset, data); } -static u32 ethtool_get_feature_mask(u32 eth_cmd) +static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd) { /* feature masks of legacy discrete ethtool ops */ @@ -205,7 +205,7 @@ static u32 ethtool_get_feature_mask(u32 eth_cmd) static int ethtool_get_one_feature(struct net_device *dev, char __user *useraddr, u32 ethcmd) { - u32 mask = ethtool_get_feature_mask(ethcmd); + netdev_features_t mask = ethtool_get_feature_mask(ethcmd); struct ethtool_value edata = { .cmd = ethcmd, .data = !!(dev->features & mask), @@ -220,7 +220,7 @@ static int ethtool_set_one_feature(struct net_device *dev, void __user *useraddr, u32 ethcmd) { struct ethtool_value edata; - u32 mask; + netdev_features_t mask; if (copy_from_user(&edata, useraddr, sizeof(edata))) return -EFAULT; @@ -260,8 +260,7 @@ static u32 __ethtool_get_flags(struct net_device *dev) static int __ethtool_set_flags(struct net_device *dev, u32 data) { - u32 features = 0; - u32 changed; + netdev_features_t features = 0, changed; if (data & ~ETH_ALL_FLAGS) return -EINVAL; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 8d2c5b32f172..cbc003b2914a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2670,7 +2670,7 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum); * a pointer to the first in a list of new skbs for the segments. * In case of error it returns ERR_PTR(err). */ -struct sk_buff *skb_segment(struct sk_buff *skb, u32 features) +struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) { struct sk_buff *segs = NULL; struct sk_buff *tail = NULL; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index b2bbcd0ebd19..15dc4c4828de 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1250,7 +1250,8 @@ out: return err; } -static struct sk_buff *inet_gso_segment(struct sk_buff *skb, u32 features) +static struct sk_buff *inet_gso_segment(struct sk_buff *skb, + netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct iphdr *iph; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 34f5db1e1c8b..50c359645665 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2653,7 +2653,8 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL(compat_tcp_getsockopt); #endif -struct sk_buff *tcp_tso_segment(struct sk_buff *skb, u32 features) +struct sk_buff *tcp_tso_segment(struct sk_buff *skb, + netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct tcphdr *th; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6854f581313f..b867ea23ece9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2247,7 +2247,8 @@ int udp4_ufo_send_check(struct sk_buff *skb) return 0; } -struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, u32 features) +struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, + netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EINVAL); unsigned int mss; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 282dc7a91f32..ee3319487c4f 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -769,7 +769,8 @@ out: return err; } -static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features) +static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, + netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct ipv6hdr *ipv6h; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index b4a4a15fa96f..ccfb0451b1c3 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1300,7 +1300,8 @@ static int udp6_ufo_send_check(struct sk_buff *skb) return 0; } -static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features) +static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, + netdev_features_t features) { struct sk_buff *segs = ERR_PTR(-EINVAL); unsigned int mss; -- cgit From 5bc1421e34ecfe0bd4b26dc3232b7d5e25179144 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 22 Nov 2011 05:10:51 +0000 Subject: net: add network priority cgroup infrastructure (v4) This patch adds in the infrastructure code to create the network priority cgroup. The cgroup, in addition to the standard processes file creates two control files: 1) prioidx - This is a read-only file that exports the index of this cgroup. This is a value that is both arbitrary and unique to a cgroup in this subsystem, and is used to index the per-device priority map 2) priomap - This is a writeable file. On read it reports a table of 2-tuples where name is the name of a network interface and priority is indicates the priority assigned to frames egresessing on the named interface and originating from a pid in this cgroup This cgroup allows for skb priority to be set prior to a root qdisc getting selected. This is benenficial for DCB enabled systems, in that it allows for any application to use dcb configured priorities so without application modification Signed-off-by: Neil Horman Signed-off-by: John Fastabend CC: Robert Love CC: "David S. Miller" Signed-off-by: David S. Miller --- include/linux/cgroup_subsys.h | 8 + include/linux/netdevice.h | 4 + include/net/netprio_cgroup.h | 65 ++++++++ include/net/sock.h | 3 + net/Kconfig | 7 + net/core/Makefile | 1 + net/core/dev.c | 14 ++ net/core/netprio_cgroup.c | 344 ++++++++++++++++++++++++++++++++++++++++++ net/core/sock.c | 22 ++- net/socket.c | 2 + 10 files changed, 469 insertions(+), 1 deletion(-) create mode 100644 include/net/netprio_cgroup.h create mode 100644 net/core/netprio_cgroup.c (limited to 'include/net/sock.h') diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index ac663c18776c..0bd390ce98b2 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -59,8 +59,16 @@ SUBSYS(net_cls) SUBSYS(blkio) #endif +/* */ + #ifdef CONFIG_CGROUP_PERF SUBSYS(perf) #endif /* */ + +#ifdef CONFIG_NETPRIO_CGROUP +SUBSYS(net_prio) +#endif + +/* */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3eb383a9b5ed..999bb264fe27 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -50,6 +50,7 @@ #ifdef CONFIG_DCB #include #endif +#include #include @@ -1244,6 +1245,9 @@ struct net_device { #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) /* max exchange id for FCoE LRO by ddp */ unsigned int fcoe_ddp_xid; +#endif +#if IS_ENABLED(CONFIG_NETPRIO_CGROUP) + struct netprio_map __rcu *priomap; #endif /* phy device may attach itself for hardware timestamping */ struct phy_device *phydev; diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h new file mode 100644 index 000000000000..c432e99942af --- /dev/null +++ b/include/net/netprio_cgroup.h @@ -0,0 +1,65 @@ +/* + * netprio_cgroup.h Control Group Priority set + * + * + * Authors: Neil Horman + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _NETPRIO_CGROUP_H +#define _NETPRIO_CGROUP_H +#include +#include +#include +#include + +struct cgroup_netprio_state +{ + struct cgroup_subsys_state css; + u32 prioidx; +}; + +struct netprio_map { + struct rcu_head rcu; + u32 priomap_len; + u32 priomap[]; +}; + +#ifdef CONFIG_CGROUPS + +#ifndef CONFIG_NETPRIO_CGROUP +extern int net_prio_subsys_id; +#endif + +extern void sock_update_netprioidx(struct sock *sk); + +static inline struct cgroup_netprio_state + *task_netprio_state(struct task_struct *p) +{ +#if IS_ENABLED(CONFIG_NETPRIO_CGROUP) + return container_of(task_subsys_state(p, net_prio_subsys_id), + struct cgroup_netprio_state, css); +#else + return NULL; +#endif +} + +#else + +#define sock_update_netprioidx(sk) +#define skb_update_prio(skb) + +static inline struct cgroup_netprio_state + *task_netprio_state(struct task_struct *p) +{ + return NULL; +} + +#endif + +#endif /* _NET_CLS_CGROUP_H */ diff --git a/include/net/sock.h b/include/net/sock.h index 1c28f394d8ec..8ac338cb39ce 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -320,6 +320,9 @@ struct sock { unsigned short sk_ack_backlog; unsigned short sk_max_ack_backlog; __u32 sk_priority; +#ifdef CONFIG_CGROUPS + __u32 sk_cgrp_prioidx; +#endif struct pid *sk_peer_pid; const struct cred *sk_peer_cred; long sk_rcvtimeo; diff --git a/net/Kconfig b/net/Kconfig index a07314844238..63d2c5dc36ff 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -232,6 +232,13 @@ config XPS depends on SMP && SYSFS && USE_GENERIC_SMP_HELPERS default y +config NETPRIO_CGROUP + tristate "Network priority cgroup" + depends on CGROUPS + ---help--- + Cgroup subsystem for use in assigning processes to network priorities on + a per-interface basis + config HAVE_BPF_JIT bool diff --git a/net/core/Makefile b/net/core/Makefile index 0d357b1c4e57..3606d40aae62 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_FIB_RULES) += fib_rules.o obj-$(CONFIG_TRACEPOINTS) += net-traces.o obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o +obj-$(CONFIG_NETPRIO_CGROUP) += netprio_cgroup.o diff --git a/net/core/dev.c b/net/core/dev.c index f78959996148..8afb244b205f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2449,6 +2449,18 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, return rc; } +#if IS_ENABLED(CONFIG_NETPRIO_CGROUP) +static void skb_update_prio(struct sk_buff *skb) +{ + struct netprio_map *map = rcu_dereference(skb->dev->priomap); + + if ((!skb->priority) && (skb->sk) && map) + skb->priority = map->priomap[skb->sk->sk_cgrp_prioidx]; +} +#else +#define skb_update_prio(skb) +#endif + static DEFINE_PER_CPU(int, xmit_recursion); #define RECURSION_LIMIT 10 @@ -2489,6 +2501,8 @@ int dev_queue_xmit(struct sk_buff *skb) */ rcu_read_lock_bh(); + skb_update_prio(skb); + txq = dev_pick_tx(dev, skb); q = rcu_dereference_bh(txq->qdisc); diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c new file mode 100644 index 000000000000..72ad0bc6841e --- /dev/null +++ b/net/core/netprio_cgroup.c @@ -0,0 +1,344 @@ +/* + * net/core/netprio_cgroup.c Priority Control Group + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Neil Horman + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, + struct cgroup *cgrp); +static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); +static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp); + +struct cgroup_subsys net_prio_subsys = { + .name = "net_prio", + .create = cgrp_create, + .destroy = cgrp_destroy, + .populate = cgrp_populate, +#ifdef CONFIG_NETPRIO_CGROUP + .subsys_id = net_prio_subsys_id, +#endif + .module = THIS_MODULE +}; + +#define PRIOIDX_SZ 128 + +static unsigned long prioidx_map[PRIOIDX_SZ]; +static DEFINE_SPINLOCK(prioidx_map_lock); +static atomic_t max_prioidx = ATOMIC_INIT(0); + +static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgrp) +{ + return container_of(cgroup_subsys_state(cgrp, net_prio_subsys_id), + struct cgroup_netprio_state, css); +} + +static int get_prioidx(u32 *prio) +{ + unsigned long flags; + u32 prioidx; + + spin_lock_irqsave(&prioidx_map_lock, flags); + prioidx = find_first_zero_bit(prioidx_map, sizeof(unsigned long) * PRIOIDX_SZ); + set_bit(prioidx, prioidx_map); + spin_unlock_irqrestore(&prioidx_map_lock, flags); + if (prioidx == sizeof(unsigned long) * PRIOIDX_SZ) + return -ENOSPC; + + atomic_set(&max_prioidx, prioidx); + *prio = prioidx; + return 0; +} + +static void put_prioidx(u32 idx) +{ + unsigned long flags; + + spin_lock_irqsave(&prioidx_map_lock, flags); + clear_bit(idx, prioidx_map); + spin_unlock_irqrestore(&prioidx_map_lock, flags); +} + +static void extend_netdev_table(struct net_device *dev, u32 new_len) +{ + size_t new_size = sizeof(struct netprio_map) + + ((sizeof(u32) * new_len)); + struct netprio_map *new_priomap = kzalloc(new_size, GFP_KERNEL); + struct netprio_map *old_priomap; + int i; + + old_priomap = rtnl_dereference(dev->priomap); + + if (!new_priomap) { + printk(KERN_WARNING "Unable to alloc new priomap!\n"); + return; + } + + for (i = 0; + old_priomap && (i < old_priomap->priomap_len); + i++) + new_priomap->priomap[i] = old_priomap->priomap[i]; + + new_priomap->priomap_len = new_len; + + rcu_assign_pointer(dev->priomap, new_priomap); + if (old_priomap) + kfree_rcu(old_priomap, rcu); +} + +static void update_netdev_tables(void) +{ + struct net_device *dev; + u32 max_len = atomic_read(&max_prioidx); + struct netprio_map *map; + + rtnl_lock(); + for_each_netdev(&init_net, dev) { + map = rtnl_dereference(dev->priomap); + if ((!map) || + (map->priomap_len < max_len)) + extend_netdev_table(dev, max_len); + } + rtnl_unlock(); +} + +static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, + struct cgroup *cgrp) +{ + struct cgroup_netprio_state *cs; + int ret; + + cs = kzalloc(sizeof(*cs), GFP_KERNEL); + if (!cs) + return ERR_PTR(-ENOMEM); + + if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx) { + kfree(cs); + return ERR_PTR(-EINVAL); + } + + ret = get_prioidx(&cs->prioidx); + if (ret != 0) { + printk(KERN_WARNING "No space in priority index array\n"); + kfree(cs); + return ERR_PTR(ret); + } + + return &cs->css; +} + +static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) +{ + struct cgroup_netprio_state *cs; + struct net_device *dev; + struct netprio_map *map; + + cs = cgrp_netprio_state(cgrp); + rtnl_lock(); + for_each_netdev(&init_net, dev) { + map = rtnl_dereference(dev->priomap); + if (map) + map->priomap[cs->prioidx] = 0; + } + rtnl_unlock(); + put_prioidx(cs->prioidx); + kfree(cs); +} + +static u64 read_prioidx(struct cgroup *cgrp, struct cftype *cft) +{ + return (u64)cgrp_netprio_state(cgrp)->prioidx; +} + +static int read_priomap(struct cgroup *cont, struct cftype *cft, + struct cgroup_map_cb *cb) +{ + struct net_device *dev; + u32 prioidx = cgrp_netprio_state(cont)->prioidx; + u32 priority; + struct netprio_map *map; + + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { + map = rcu_dereference(dev->priomap); + priority = map ? map->priomap[prioidx] : 0; + cb->fill(cb, dev->name, priority); + } + rcu_read_unlock(); + return 0; +} + +static int write_priomap(struct cgroup *cgrp, struct cftype *cft, + const char *buffer) +{ + char *devname = kstrdup(buffer, GFP_KERNEL); + int ret = -EINVAL; + u32 prioidx = cgrp_netprio_state(cgrp)->prioidx; + unsigned long priority; + char *priostr; + struct net_device *dev; + struct netprio_map *map; + + if (!devname) + return -ENOMEM; + + /* + * Minimally sized valid priomap string + */ + if (strlen(devname) < 3) + goto out_free_devname; + + priostr = strstr(devname, " "); + if (!priostr) + goto out_free_devname; + + /* + *Separate the devname from the associated priority + *and advance the priostr poitner to the priority value + */ + *priostr = '\0'; + priostr++; + + /* + * If the priostr points to NULL, we're at the end of the passed + * in string, and its not a valid write + */ + if (*priostr == '\0') + goto out_free_devname; + + ret = kstrtoul(priostr, 10, &priority); + if (ret < 0) + goto out_free_devname; + + ret = -ENODEV; + + dev = dev_get_by_name(&init_net, devname); + if (!dev) + goto out_free_devname; + + update_netdev_tables(); + ret = 0; + rcu_read_lock(); + map = rcu_dereference(dev->priomap); + if (map) + map->priomap[prioidx] = priority; + rcu_read_unlock(); + dev_put(dev); + +out_free_devname: + kfree(devname); + return ret; +} + +static struct cftype ss_files[] = { + { + .name = "prioidx", + .read_u64 = read_prioidx, + }, + { + .name = "ifpriomap", + .read_map = read_priomap, + .write_string = write_priomap, + }, +}; + +static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) +{ + return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); +} + +static int netprio_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + struct netprio_map *old; + u32 max_len = atomic_read(&max_prioidx); + + /* + * Note this is called with rtnl_lock held so we have update side + * protection on our rcu assignments + */ + + switch (event) { + + case NETDEV_REGISTER: + if (max_len) + extend_netdev_table(dev, max_len); + break; + case NETDEV_UNREGISTER: + old = rtnl_dereference(dev->priomap); + rcu_assign_pointer(dev->priomap, NULL); + if (old) + kfree_rcu(old, rcu); + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block netprio_device_notifier = { + .notifier_call = netprio_device_event +}; + +static int __init init_cgroup_netprio(void) +{ + int ret; + + ret = cgroup_load_subsys(&net_prio_subsys); + if (ret) + goto out; +#ifndef CONFIG_NETPRIO_CGROUP + smp_wmb(); + net_prio_subsys_id = net_prio_subsys.subsys_id; +#endif + + register_netdevice_notifier(&netprio_device_notifier); + +out: + return ret; +} + +static void __exit exit_cgroup_netprio(void) +{ + struct netprio_map *old; + struct net_device *dev; + + unregister_netdevice_notifier(&netprio_device_notifier); + + cgroup_unload_subsys(&net_prio_subsys); + +#ifndef CONFIG_NETPRIO_CGROUP + net_prio_subsys_id = -1; + synchronize_rcu(); +#endif + + rtnl_lock(); + for_each_netdev(&init_net, dev) { + old = rtnl_dereference(dev->priomap); + rcu_assign_pointer(dev->priomap, NULL); + if (old) + kfree_rcu(old, rcu); + } + rtnl_unlock(); +} + +module_init(init_cgroup_netprio); +module_exit(exit_cgroup_netprio); +MODULE_LICENSE("GPL v2"); diff --git a/net/core/sock.c b/net/core/sock.c index 9a8b3fac1401..16069139797c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -125,6 +125,7 @@ #include #include #include +#include #include @@ -221,10 +222,16 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); EXPORT_SYMBOL(sysctl_optmem_max); -#if defined(CONFIG_CGROUPS) && !defined(CONFIG_NET_CLS_CGROUP) +#if defined(CONFIG_CGROUPS) +#if !defined(CONFIG_NET_CLS_CGROUP) int net_cls_subsys_id = -1; EXPORT_SYMBOL_GPL(net_cls_subsys_id); #endif +#if !defined(CONFIG_NETPRIO_CGROUP) +int net_prio_subsys_id = -1; +EXPORT_SYMBOL_GPL(net_prio_subsys_id); +#endif +#endif static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) { @@ -1120,6 +1127,18 @@ void sock_update_classid(struct sock *sk) sk->sk_classid = classid; } EXPORT_SYMBOL(sock_update_classid); + +void sock_update_netprioidx(struct sock *sk) +{ + struct cgroup_netprio_state *state; + if (in_interrupt()) + return; + rcu_read_lock(); + state = task_netprio_state(current); + sk->sk_cgrp_prioidx = state ? state->prioidx : 0; + rcu_read_unlock(); +} +EXPORT_SYMBOL_GPL(sock_update_netprioidx); #endif /** @@ -1147,6 +1166,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, atomic_set(&sk->sk_wmem_alloc, 1); sock_update_classid(sk); + sock_update_netprioidx(sk); } return sk; diff --git a/net/socket.c b/net/socket.c index 425ef4270460..e62b4f055071 100644 --- a/net/socket.c +++ b/net/socket.c @@ -551,6 +551,8 @@ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock, sock_update_classid(sock->sk); + sock_update_netprioidx(sock->sk); + si->sock = sock; si->scm = NULL; si->msg = msg; -- cgit From 180d8cd942ce336b2c869d324855c40c5db478ad Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Sun, 11 Dec 2011 21:47:02 +0000 Subject: foundations of per-cgroup memory pressure controlling. This patch replaces all uses of struct sock fields' memory_pressure, memory_allocated, sockets_allocated, and sysctl_mem to acessor macros. Those macros can either receive a socket argument, or a mem_cgroup argument, depending on the context they live in. Since we're only doing a macro wrapping here, no performance impact at all is expected in the case where we don't have cgroups disabled. Signed-off-by: Glauber Costa Reviewed-by: Hiroyouki Kamezawa CC: David S. Miller CC: Eric W. Biederman CC: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++- include/net/tcp.h | 3 +- net/core/sock.c | 57 ++++++++++++++++++------------ net/ipv4/proc.c | 6 ++-- net/ipv4/tcp_input.c | 12 +++---- net/ipv4/tcp_ipv4.c | 4 +-- net/ipv4/tcp_output.c | 2 +- net/ipv4/tcp_timer.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 9 files changed, 145 insertions(+), 39 deletions(-) (limited to 'include/net/sock.h') diff --git a/include/net/sock.h b/include/net/sock.h index 8ac338cb39ce..ed0dbf034539 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -867,6 +868,99 @@ static inline void sk_refcnt_debug_release(const struct sock *sk) #define sk_refcnt_debug_release(sk) do { } while (0) #endif /* SOCK_REFCNT_DEBUG */ +static inline bool sk_has_memory_pressure(const struct sock *sk) +{ + return sk->sk_prot->memory_pressure != NULL; +} + +static inline bool sk_under_memory_pressure(const struct sock *sk) +{ + if (!sk->sk_prot->memory_pressure) + return false; + return !!*sk->sk_prot->memory_pressure; +} + +static inline void sk_leave_memory_pressure(struct sock *sk) +{ + int *memory_pressure = sk->sk_prot->memory_pressure; + + if (memory_pressure && *memory_pressure) + *memory_pressure = 0; +} + +static inline void sk_enter_memory_pressure(struct sock *sk) +{ + if (sk->sk_prot->enter_memory_pressure) + sk->sk_prot->enter_memory_pressure(sk); +} + +static inline long sk_prot_mem_limits(const struct sock *sk, int index) +{ + long *prot = sk->sk_prot->sysctl_mem; + return prot[index]; +} + +static inline long +sk_memory_allocated(const struct sock *sk) +{ + struct proto *prot = sk->sk_prot; + return atomic_long_read(prot->memory_allocated); +} + +static inline long +sk_memory_allocated_add(struct sock *sk, int amt) +{ + struct proto *prot = sk->sk_prot; + return atomic_long_add_return(amt, prot->memory_allocated); +} + +static inline void +sk_memory_allocated_sub(struct sock *sk, int amt) +{ + struct proto *prot = sk->sk_prot; + atomic_long_sub(amt, prot->memory_allocated); +} + +static inline void sk_sockets_allocated_dec(struct sock *sk) +{ + struct proto *prot = sk->sk_prot; + percpu_counter_dec(prot->sockets_allocated); +} + +static inline void sk_sockets_allocated_inc(struct sock *sk) +{ + struct proto *prot = sk->sk_prot; + percpu_counter_inc(prot->sockets_allocated); +} + +static inline int +sk_sockets_allocated_read_positive(struct sock *sk) +{ + struct proto *prot = sk->sk_prot; + + return percpu_counter_sum_positive(prot->sockets_allocated); +} + +static inline int +proto_sockets_allocated_sum_positive(struct proto *prot) +{ + return percpu_counter_sum_positive(prot->sockets_allocated); +} + +static inline long +proto_memory_allocated(struct proto *prot) +{ + return atomic_long_read(prot->memory_allocated); +} + +static inline bool +proto_memory_pressure(struct proto *prot) +{ + if (!prot->memory_pressure) + return false; + return !!*prot->memory_pressure; +} + #ifdef CONFIG_PROC_FS /* Called with local bh disabled */ @@ -1674,7 +1768,7 @@ static inline struct page *sk_stream_alloc_page(struct sock *sk) page = alloc_pages(sk->sk_allocation, 0); if (!page) { - sk->sk_prot->enter_memory_pressure(sk); + sk_enter_memory_pressure(sk); sk_stream_moderate_sndbuf(sk); } return page; diff --git a/include/net/tcp.h b/include/net/tcp.h index 02f070d339ba..913473b4eda7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -44,6 +44,7 @@ #include #include +#include extern struct inet_hashinfo tcp_hashinfo; @@ -285,7 +286,7 @@ static inline bool tcp_too_many_orphans(struct sock *sk, int shift) } if (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && - atomic_long_read(&tcp_memory_allocated) > sysctl_tcp_mem[2]) + sk_memory_allocated(sk) > sk_prot_mem_limits(sk, 2)) return true; return false; } diff --git a/net/core/sock.c b/net/core/sock.c index 9777da86aeac..a3d4205e7238 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1323,7 +1323,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) newsk->sk_wq = NULL; if (newsk->sk_prot->sockets_allocated) - percpu_counter_inc(newsk->sk_prot->sockets_allocated); + sk_sockets_allocated_inc(newsk); if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) net_enable_timestamp(); @@ -1713,28 +1713,28 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind) long allocated; sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; - allocated = atomic_long_add_return(amt, prot->memory_allocated); + + allocated = sk_memory_allocated_add(sk, amt); /* Under limit. */ - if (allocated <= prot->sysctl_mem[0]) { - if (prot->memory_pressure && *prot->memory_pressure) - *prot->memory_pressure = 0; + if (allocated <= sk_prot_mem_limits(sk, 0)) { + sk_leave_memory_pressure(sk); return 1; } /* Under pressure. */ - if (allocated > prot->sysctl_mem[1]) - if (prot->enter_memory_pressure) - prot->enter_memory_pressure(sk); + if (allocated > sk_prot_mem_limits(sk, 1)) + sk_enter_memory_pressure(sk); /* Over hard limit. */ - if (allocated > prot->sysctl_mem[2]) + if (allocated > sk_prot_mem_limits(sk, 2)) goto suppress_allocation; /* guarantee minimum buffer size under pressure */ if (kind == SK_MEM_RECV) { if (atomic_read(&sk->sk_rmem_alloc) < prot->sysctl_rmem[0]) return 1; + } else { /* SK_MEM_SEND */ if (sk->sk_type == SOCK_STREAM) { if (sk->sk_wmem_queued < prot->sysctl_wmem[0]) @@ -1744,13 +1744,13 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind) return 1; } - if (prot->memory_pressure) { + if (sk_has_memory_pressure(sk)) { int alloc; - if (!*prot->memory_pressure) + if (!sk_under_memory_pressure(sk)) return 1; - alloc = percpu_counter_read_positive(prot->sockets_allocated); - if (prot->sysctl_mem[2] > alloc * + alloc = sk_sockets_allocated_read_positive(sk); + if (sk_prot_mem_limits(sk, 2) > alloc * sk_mem_pages(sk->sk_wmem_queued + atomic_read(&sk->sk_rmem_alloc) + sk->sk_forward_alloc)) @@ -1773,7 +1773,9 @@ suppress_allocation: /* Alas. Undo changes. */ sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM; - atomic_long_sub(amt, prot->memory_allocated); + + sk_memory_allocated_sub(sk, amt); + return 0; } EXPORT_SYMBOL(__sk_mem_schedule); @@ -1784,15 +1786,13 @@ EXPORT_SYMBOL(__sk_mem_schedule); */ void __sk_mem_reclaim(struct sock *sk) { - struct proto *prot = sk->sk_prot; - - atomic_long_sub(sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT, - prot->memory_allocated); + sk_memory_allocated_sub(sk, + sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT); sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1; - if (prot->memory_pressure && *prot->memory_pressure && - (atomic_long_read(prot->memory_allocated) < prot->sysctl_mem[0])) - *prot->memory_pressure = 0; + if (sk_under_memory_pressure(sk) && + (sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0))) + sk_leave_memory_pressure(sk); } EXPORT_SYMBOL(__sk_mem_reclaim); @@ -2507,16 +2507,27 @@ static char proto_method_implemented(const void *method) { return method == NULL ? 'n' : 'y'; } +static long sock_prot_memory_allocated(struct proto *proto) +{ + return proto->memory_allocated != NULL ? proto_memory_allocated(proto): -1L; +} + +static char *sock_prot_memory_pressure(struct proto *proto) +{ + return proto->memory_pressure != NULL ? + proto_memory_pressure(proto) ? "yes" : "no" : "NI"; +} static void proto_seq_printf(struct seq_file *seq, struct proto *proto) { + seq_printf(seq, "%-9s %4u %6d %6ld %-3s %6u %-3s %-10s " "%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n", proto->name, proto->obj_size, sock_prot_inuse_get(seq_file_net(seq), proto), - proto->memory_allocated != NULL ? atomic_long_read(proto->memory_allocated) : -1L, - proto->memory_pressure != NULL ? *proto->memory_pressure ? "yes" : "no" : "NI", + sock_prot_memory_allocated(proto), + sock_prot_memory_pressure(proto), proto->max_header, proto->slab == NULL ? "no" : "yes", module_name(proto->owner), diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 961eed4f510a..3569d8ecaeac 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -56,17 +56,17 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) local_bh_disable(); orphans = percpu_counter_sum_positive(&tcp_orphan_count); - sockets = percpu_counter_sum_positive(&tcp_sockets_allocated); + sockets = proto_sockets_allocated_sum_positive(&tcp_prot); local_bh_enable(); socket_seq_show(seq); seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %ld\n", sock_prot_inuse_get(net, &tcp_prot), orphans, tcp_death_row.tw_count, sockets, - atomic_long_read(&tcp_memory_allocated)); + proto_memory_allocated(&tcp_prot)); seq_printf(seq, "UDP: inuse %d mem %ld\n", sock_prot_inuse_get(net, &udp_prot), - atomic_long_read(&udp_memory_allocated)); + proto_memory_allocated(&udp_prot)); seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse_get(net, &udplite_prot)); seq_printf(seq, "RAW: inuse %d\n", diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b9cbc351c511..f131d92d25ee 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -322,7 +322,7 @@ static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) /* Check #1 */ if (tp->rcv_ssthresh < tp->window_clamp && (int)tp->rcv_ssthresh < tcp_space(sk) && - !tcp_memory_pressure) { + !sk_under_memory_pressure(sk)) { int incr; /* Check #2. Increase window, if skb with such overhead @@ -411,8 +411,8 @@ static void tcp_clamp_window(struct sock *sk) if (sk->sk_rcvbuf < sysctl_tcp_rmem[2] && !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) && - !tcp_memory_pressure && - atomic_long_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) { + !sk_under_memory_pressure(sk) && + sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)) { sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc), sysctl_tcp_rmem[2]); } @@ -4866,7 +4866,7 @@ static int tcp_prune_queue(struct sock *sk) if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) tcp_clamp_window(sk); - else if (tcp_memory_pressure) + else if (sk_under_memory_pressure(sk)) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); tcp_collapse_ofo_queue(sk); @@ -4932,11 +4932,11 @@ static int tcp_should_expand_sndbuf(const struct sock *sk) return 0; /* If we are under global TCP memory pressure, do not expand. */ - if (tcp_memory_pressure) + if (sk_under_memory_pressure(sk)) return 0; /* If we are under soft global TCP memory pressure, do not expand. */ - if (atomic_long_read(&tcp_memory_allocated) >= sysctl_tcp_mem[0]) + if (sk_memory_allocated(sk) >= sk_prot_mem_limits(sk, 0)) return 0; /* If we filled the congestion window, do not expand. */ diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c4b8b09db9f5..f48bf312cfe8 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1917,7 +1917,7 @@ static int tcp_v4_init_sock(struct sock *sk) sk->sk_rcvbuf = sysctl_tcp_rmem[1]; local_bh_disable(); - percpu_counter_inc(&tcp_sockets_allocated); + sk_sockets_allocated_inc(sk); local_bh_enable(); return 0; @@ -1973,7 +1973,7 @@ void tcp_v4_destroy_sock(struct sock *sk) tp->cookie_values = NULL; } - percpu_counter_dec(&tcp_sockets_allocated); + sk_sockets_allocated_dec(sk); } EXPORT_SYMBOL(tcp_v4_destroy_sock); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index cf3068038942..8c8de2780c7a 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1922,7 +1922,7 @@ u32 __tcp_select_window(struct sock *sk) if (free_space < (full_space >> 1)) { icsk->icsk_ack.quick = 0; - if (tcp_memory_pressure) + if (sk_under_memory_pressure(sk)) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index aa39a692f4c8..40a41f077981 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -261,7 +261,7 @@ static void tcp_delack_timer(unsigned long data) } out: - if (tcp_memory_pressure) + if (sk_under_memory_pressure(sk)) sk_mem_reclaim(sk); out_unlock: bh_unlock_sock(sk); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9d74eee334d6..b69c7030aba9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1994,7 +1994,7 @@ static int tcp_v6_init_sock(struct sock *sk) sk->sk_rcvbuf = sysctl_tcp_rmem[1]; local_bh_disable(); - percpu_counter_inc(&tcp_sockets_allocated); + sk_sockets_allocated_inc(sk); local_bh_enable(); return 0; -- cgit From e1aab161e0135aafcd439be20b4f35e4b0922d95 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Sun, 11 Dec 2011 21:47:03 +0000 Subject: socket: initial cgroup code. The goal of this work is to move the memory pressure tcp controls to a cgroup, instead of just relying on global conditions. To avoid excessive overhead in the network fast paths, the code that accounts allocated memory to a cgroup is hidden inside a static_branch(). This branch is patched out until the first non-root cgroup is created. So when nobody is using cgroups, even if it is mounted, no significant performance penalty should be seen. This patch handles the generic part of the code, and has nothing tcp-specific. Signed-off-by: Glauber Costa Reviewed-by: KAMEZAWA Hiroyuki CC: Kirill A. Shutemov CC: David S. Miller CC: Eric W. Biederman CC: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/cgroups/memory.txt | 4 +- include/linux/memcontrol.h | 22 ++++++ include/net/sock.h | 156 +++++++++++++++++++++++++++++++++++++-- mm/memcontrol.c | 46 +++++++++++- net/core/sock.c | 24 ++++-- 5 files changed, 235 insertions(+), 17 deletions(-) (limited to 'include/net/sock.h') diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index f2453241142b..23a8dc5319a3 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -289,7 +289,9 @@ to trigger slab reclaim when those limits are reached. 2.7.1 Current Kernel Memory resources accounted -None +* sockets memory pressure: some sockets protocols have memory pressure +thresholds. The Memory Controller allows them to be controlled individually +per cgroup, instead of globally. 3. User Interface diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index b87068a1a09e..f15021b9f734 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -85,6 +85,8 @@ extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page); extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm); +extern struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg); + static inline int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup) { @@ -381,5 +383,25 @@ mem_cgroup_print_bad_page(struct page *page) } #endif +#ifdef CONFIG_INET +enum { + UNDER_LIMIT, + SOFT_LIMIT, + OVER_LIMIT, +}; + +struct sock; +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +void sock_update_memcg(struct sock *sk); +void sock_release_memcg(struct sock *sk); +#else +static inline void sock_update_memcg(struct sock *sk) +{ +} +static inline void sock_release_memcg(struct sock *sk) +{ +} +#endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ +#endif /* CONFIG_INET */ #endif /* _LINUX_MEMCONTROL_H */ diff --git a/include/net/sock.h b/include/net/sock.h index ed0dbf034539..d5eab256167c 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -168,6 +169,7 @@ struct sock_common { /* public: */ }; +struct cg_proto; /** * struct sock - network layer representation of sockets * @__sk_common: shared layout with inet_timewait_sock @@ -228,6 +230,7 @@ struct sock_common { * @sk_security: used by security modules * @sk_mark: generic packet mark * @sk_classid: this socket's cgroup classid + * @sk_cgrp: this socket's cgroup-specific proto data * @sk_write_pending: a write to stream socket waits to start * @sk_state_change: callback to indicate change in the state of the sock * @sk_data_ready: callback to indicate there is data to be processed @@ -342,6 +345,7 @@ struct sock { #endif __u32 sk_mark; u32 sk_classid; + struct cg_proto *sk_cgrp; void (*sk_state_change)(struct sock *sk); void (*sk_data_ready)(struct sock *sk, int bytes); void (*sk_write_space)(struct sock *sk); @@ -838,6 +842,37 @@ struct proto { #ifdef SOCK_REFCNT_DEBUG atomic_t socks; #endif +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM + /* + * cgroup specific init/deinit functions. Called once for all + * protocols that implement it, from cgroups populate function. + * This function has to setup any files the protocol want to + * appear in the kmem cgroup filesystem. + */ + int (*init_cgroup)(struct cgroup *cgrp, + struct cgroup_subsys *ss); + void (*destroy_cgroup)(struct cgroup *cgrp, + struct cgroup_subsys *ss); + struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg); +#endif +}; + +struct cg_proto { + void (*enter_memory_pressure)(struct sock *sk); + struct res_counter *memory_allocated; /* Current allocated memory. */ + struct percpu_counter *sockets_allocated; /* Current number of sockets. */ + int *memory_pressure; + long *sysctl_mem; + /* + * memcg field is used to find which memcg we belong directly + * Each memcg struct can hold more than one cg_proto, so container_of + * won't really cut. + * + * The elegant solution would be having an inverse function to + * proto_cgroup in struct proto, but that means polluting the structure + * for everybody, instead of just for memcg users. + */ + struct mem_cgroup *memcg; }; extern int proto_register(struct proto *prot, int alloc_slab); @@ -856,7 +891,7 @@ static inline void sk_refcnt_debug_dec(struct sock *sk) sk->sk_prot->name, sk, atomic_read(&sk->sk_prot->socks)); } -static inline void sk_refcnt_debug_release(const struct sock *sk) +inline void sk_refcnt_debug_release(const struct sock *sk) { if (atomic_read(&sk->sk_refcnt) != 1) printk(KERN_DEBUG "Destruction of the %s socket %p delayed, refcnt=%d\n", @@ -868,6 +903,24 @@ static inline void sk_refcnt_debug_release(const struct sock *sk) #define sk_refcnt_debug_release(sk) do { } while (0) #endif /* SOCK_REFCNT_DEBUG */ +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +extern struct jump_label_key memcg_socket_limit_enabled; +static inline struct cg_proto *parent_cg_proto(struct proto *proto, + struct cg_proto *cg_proto) +{ + return proto->proto_cgroup(parent_mem_cgroup(cg_proto->memcg)); +} +#define mem_cgroup_sockets_enabled static_branch(&memcg_socket_limit_enabled) +#else +#define mem_cgroup_sockets_enabled 0 +static inline struct cg_proto *parent_cg_proto(struct proto *proto, + struct cg_proto *cg_proto) +{ + return NULL; +} +#endif + + static inline bool sk_has_memory_pressure(const struct sock *sk) { return sk->sk_prot->memory_pressure != NULL; @@ -877,6 +930,10 @@ static inline bool sk_under_memory_pressure(const struct sock *sk) { if (!sk->sk_prot->memory_pressure) return false; + + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) + return !!*sk->sk_cgrp->memory_pressure; + return !!*sk->sk_prot->memory_pressure; } @@ -884,52 +941,136 @@ static inline void sk_leave_memory_pressure(struct sock *sk) { int *memory_pressure = sk->sk_prot->memory_pressure; - if (memory_pressure && *memory_pressure) + if (!memory_pressure) + return; + + if (*memory_pressure) *memory_pressure = 0; + + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) { + struct cg_proto *cg_proto = sk->sk_cgrp; + struct proto *prot = sk->sk_prot; + + for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto)) + if (*cg_proto->memory_pressure) + *cg_proto->memory_pressure = 0; + } + } static inline void sk_enter_memory_pressure(struct sock *sk) { - if (sk->sk_prot->enter_memory_pressure) - sk->sk_prot->enter_memory_pressure(sk); + if (!sk->sk_prot->enter_memory_pressure) + return; + + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) { + struct cg_proto *cg_proto = sk->sk_cgrp; + struct proto *prot = sk->sk_prot; + + for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto)) + cg_proto->enter_memory_pressure(sk); + } + + sk->sk_prot->enter_memory_pressure(sk); } static inline long sk_prot_mem_limits(const struct sock *sk, int index) { long *prot = sk->sk_prot->sysctl_mem; + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) + prot = sk->sk_cgrp->sysctl_mem; return prot[index]; } +static inline void memcg_memory_allocated_add(struct cg_proto *prot, + unsigned long amt, + int *parent_status) +{ + struct res_counter *fail; + int ret; + + ret = res_counter_charge(prot->memory_allocated, + amt << PAGE_SHIFT, &fail); + + if (ret < 0) + *parent_status = OVER_LIMIT; +} + +static inline void memcg_memory_allocated_sub(struct cg_proto *prot, + unsigned long amt) +{ + res_counter_uncharge(prot->memory_allocated, amt << PAGE_SHIFT); +} + +static inline u64 memcg_memory_allocated_read(struct cg_proto *prot) +{ + u64 ret; + ret = res_counter_read_u64(prot->memory_allocated, RES_USAGE); + return ret >> PAGE_SHIFT; +} + static inline long sk_memory_allocated(const struct sock *sk) { struct proto *prot = sk->sk_prot; + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) + return memcg_memory_allocated_read(sk->sk_cgrp); + return atomic_long_read(prot->memory_allocated); } static inline long -sk_memory_allocated_add(struct sock *sk, int amt) +sk_memory_allocated_add(struct sock *sk, int amt, int *parent_status) { struct proto *prot = sk->sk_prot; + + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) { + memcg_memory_allocated_add(sk->sk_cgrp, amt, parent_status); + /* update the root cgroup regardless */ + atomic_long_add_return(amt, prot->memory_allocated); + return memcg_memory_allocated_read(sk->sk_cgrp); + } + return atomic_long_add_return(amt, prot->memory_allocated); } static inline void -sk_memory_allocated_sub(struct sock *sk, int amt) +sk_memory_allocated_sub(struct sock *sk, int amt, int parent_status) { struct proto *prot = sk->sk_prot; + + if (mem_cgroup_sockets_enabled && sk->sk_cgrp && + parent_status != OVER_LIMIT) /* Otherwise was uncharged already */ + memcg_memory_allocated_sub(sk->sk_cgrp, amt); + atomic_long_sub(amt, prot->memory_allocated); } static inline void sk_sockets_allocated_dec(struct sock *sk) { struct proto *prot = sk->sk_prot; + + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) { + struct cg_proto *cg_proto = sk->sk_cgrp; + + for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto)) + percpu_counter_dec(cg_proto->sockets_allocated); + } + percpu_counter_dec(prot->sockets_allocated); } static inline void sk_sockets_allocated_inc(struct sock *sk) { struct proto *prot = sk->sk_prot; + + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) { + struct cg_proto *cg_proto = sk->sk_cgrp; + + for (; cg_proto; cg_proto = parent_cg_proto(prot, cg_proto)) + percpu_counter_inc(cg_proto->sockets_allocated); + } + percpu_counter_inc(prot->sockets_allocated); } @@ -938,6 +1079,9 @@ sk_sockets_allocated_read_positive(struct sock *sk) { struct proto *prot = sk->sk_prot; + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) + return percpu_counter_sum_positive(sk->sk_cgrp->sockets_allocated); + return percpu_counter_sum_positive(prot->sockets_allocated); } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 9fbcff71245e..3de3901ae0a7 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -379,7 +379,48 @@ enum mem_type { static void mem_cgroup_get(struct mem_cgroup *memcg); static void mem_cgroup_put(struct mem_cgroup *memcg); -static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg); + +/* Writing them here to avoid exposing memcg's inner layout */ +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +#ifdef CONFIG_INET +#include + +static bool mem_cgroup_is_root(struct mem_cgroup *memcg); +void sock_update_memcg(struct sock *sk) +{ + /* A socket spends its whole life in the same cgroup */ + if (sk->sk_cgrp) { + WARN_ON(1); + return; + } + if (static_branch(&memcg_socket_limit_enabled)) { + struct mem_cgroup *memcg; + + BUG_ON(!sk->sk_prot->proto_cgroup); + + rcu_read_lock(); + memcg = mem_cgroup_from_task(current); + if (!mem_cgroup_is_root(memcg)) { + mem_cgroup_get(memcg); + sk->sk_cgrp = sk->sk_prot->proto_cgroup(memcg); + } + rcu_read_unlock(); + } +} +EXPORT_SYMBOL(sock_update_memcg); + +void sock_release_memcg(struct sock *sk) +{ + if (static_branch(&memcg_socket_limit_enabled) && sk->sk_cgrp) { + struct mem_cgroup *memcg; + WARN_ON(!sk->sk_cgrp->memcg); + memcg = sk->sk_cgrp->memcg; + mem_cgroup_put(memcg); + } +} +#endif /* CONFIG_INET */ +#endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ + static void drain_all_stock_async(struct mem_cgroup *memcg); static struct mem_cgroup_per_zone * @@ -4932,12 +4973,13 @@ static void mem_cgroup_put(struct mem_cgroup *memcg) /* * Returns the parent mem_cgroup in memcgroup hierarchy with hierarchy enabled. */ -static struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg) +struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg) { if (!memcg->res.parent) return NULL; return mem_cgroup_from_res_counter(memcg->res.parent, res); } +EXPORT_SYMBOL(parent_mem_cgroup); #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP static void __init enable_swap_cgroup(void) diff --git a/net/core/sock.c b/net/core/sock.c index a3d4205e7238..6a871b8fdd20 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -111,6 +111,7 @@ #include #include #include +#include #include #include @@ -142,6 +143,9 @@ static struct lock_class_key af_family_keys[AF_MAX]; static struct lock_class_key af_family_slock_keys[AF_MAX]; +struct jump_label_key memcg_socket_limit_enabled; +EXPORT_SYMBOL(memcg_socket_limit_enabled); + /* * Make lock validator output more readable. (we pre-construct these * strings build-time, so that runtime initialization of socket @@ -1711,23 +1715,27 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind) struct proto *prot = sk->sk_prot; int amt = sk_mem_pages(size); long allocated; + int parent_status = UNDER_LIMIT; sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; - allocated = sk_memory_allocated_add(sk, amt); + allocated = sk_memory_allocated_add(sk, amt, &parent_status); /* Under limit. */ - if (allocated <= sk_prot_mem_limits(sk, 0)) { + if (parent_status == UNDER_LIMIT && + allocated <= sk_prot_mem_limits(sk, 0)) { sk_leave_memory_pressure(sk); return 1; } - /* Under pressure. */ - if (allocated > sk_prot_mem_limits(sk, 1)) + /* Under pressure. (we or our parents) */ + if ((parent_status > SOFT_LIMIT) || + allocated > sk_prot_mem_limits(sk, 1)) sk_enter_memory_pressure(sk); - /* Over hard limit. */ - if (allocated > sk_prot_mem_limits(sk, 2)) + /* Over hard limit (we or our parents) */ + if ((parent_status == OVER_LIMIT) || + (allocated > sk_prot_mem_limits(sk, 2))) goto suppress_allocation; /* guarantee minimum buffer size under pressure */ @@ -1774,7 +1782,7 @@ suppress_allocation: /* Alas. Undo changes. */ sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM; - sk_memory_allocated_sub(sk, amt); + sk_memory_allocated_sub(sk, amt, parent_status); return 0; } @@ -1787,7 +1795,7 @@ EXPORT_SYMBOL(__sk_mem_schedule); void __sk_mem_reclaim(struct sock *sk) { sk_memory_allocated_sub(sk, - sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT); + sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT, 0); sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1; if (sk_under_memory_pressure(sk) && -- cgit From d1a4c0b37c296e600ffe08edb0db2dc1b8f550d7 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Sun, 11 Dec 2011 21:47:04 +0000 Subject: tcp memory pressure controls This patch introduces memory pressure controls for the tcp protocol. It uses the generic socket memory pressure code introduced in earlier patches, and fills in the necessary data in cg_proto struct. Signed-off-by: Glauber Costa Reviewed-by: KAMEZAWA Hiroyuki CC: Eric W. Biederman Signed-off-by: David S. Miller --- Documentation/cgroups/memory.txt | 2 ++ include/linux/memcontrol.h | 1 + include/net/sock.h | 2 ++ include/net/tcp_memcontrol.h | 17 +++++++++ mm/memcontrol.c | 40 +++++++++++++++++++++- net/core/sock.c | 43 +++++++++++++++++++++-- net/ipv4/Makefile | 1 + net/ipv4/tcp_ipv4.c | 9 ++++- net/ipv4/tcp_memcontrol.c | 74 ++++++++++++++++++++++++++++++++++++++++ net/ipv6/tcp_ipv6.c | 5 +++ 10 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 include/net/tcp_memcontrol.h create mode 100644 net/ipv4/tcp_memcontrol.c (limited to 'include/net/sock.h') diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 23a8dc5319a3..687dea5bf1fd 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -293,6 +293,8 @@ to trigger slab reclaim when those limits are reached. thresholds. The Memory Controller allows them to be controlled individually per cgroup, instead of globally. +* tcp memory pressure: sockets memory pressure for the tcp protocol. + 3. User Interface 0. Configuration diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index f15021b9f734..1513994ce207 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -86,6 +86,7 @@ extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm); extern struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg); +extern struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont); static inline int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup) diff --git a/include/net/sock.h b/include/net/sock.h index d5eab256167c..18ecc9919d29 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -64,6 +64,8 @@ #include #include +int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss); +void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss); /* * This structure really needs to be cleaned up. * Most of it is for TCP, and not used by any of diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h new file mode 100644 index 000000000000..5f5e1582d764 --- /dev/null +++ b/include/net/tcp_memcontrol.h @@ -0,0 +1,17 @@ +#ifndef _TCP_MEMCG_H +#define _TCP_MEMCG_H + +struct tcp_memcontrol { + struct cg_proto cg_proto; + /* per-cgroup tcp memory pressure knobs */ + struct res_counter tcp_memory_allocated; + struct percpu_counter tcp_sockets_allocated; + /* those two are read-mostly, leave them at the end */ + long tcp_prot_mem[3]; + int tcp_memory_pressure; +}; + +struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg); +int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss); +void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss); +#endif /* _TCP_MEMCG_H */ diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3de3901ae0a7..7266202fa7cf 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -50,6 +50,8 @@ #include #include #include "internal.h" +#include +#include #include @@ -295,6 +297,10 @@ struct mem_cgroup { */ struct mem_cgroup_stat_cpu nocpu_base; spinlock_t pcp_counter_lock; + +#ifdef CONFIG_INET + struct tcp_memcontrol tcp_mem; +#endif }; /* Stuffs for move charges at task migration. */ @@ -384,6 +390,7 @@ static void mem_cgroup_put(struct mem_cgroup *memcg); #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM #ifdef CONFIG_INET #include +#include static bool mem_cgroup_is_root(struct mem_cgroup *memcg); void sock_update_memcg(struct sock *sk) @@ -418,6 +425,15 @@ void sock_release_memcg(struct sock *sk) mem_cgroup_put(memcg); } } + +struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg) +{ + if (!memcg || mem_cgroup_is_root(memcg)) + return NULL; + + return &memcg->tcp_mem.cg_proto; +} +EXPORT_SYMBOL(tcp_proto_cgroup); #endif /* CONFIG_INET */ #endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ @@ -800,7 +816,7 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page) preempt_enable(); } -static struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont) +struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont) { return container_of(cgroup_subsys_state(cont, mem_cgroup_subsys_id), struct mem_cgroup, @@ -4732,14 +4748,34 @@ static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) ret = cgroup_add_files(cont, ss, kmem_cgroup_files, ARRAY_SIZE(kmem_cgroup_files)); + + /* + * Part of this would be better living in a separate allocation + * function, leaving us with just the cgroup tree population work. + * We, however, depend on state such as network's proto_list that + * is only initialized after cgroup creation. I found the less + * cumbersome way to deal with it to defer it all to populate time + */ + if (!ret) + ret = mem_cgroup_sockets_init(cont, ss); return ret; }; +static void kmem_cgroup_destroy(struct cgroup_subsys *ss, + struct cgroup *cont) +{ + mem_cgroup_sockets_destroy(cont, ss); +} #else static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) { return 0; } + +static void kmem_cgroup_destroy(struct cgroup_subsys *ss, + struct cgroup *cont) +{ +} #endif static struct cftype mem_cgroup_files[] = { @@ -5098,6 +5134,8 @@ static void mem_cgroup_destroy(struct cgroup_subsys *ss, { struct mem_cgroup *memcg = mem_cgroup_from_cont(cont); + kmem_cgroup_destroy(ss, cont); + mem_cgroup_put(memcg); } diff --git a/net/core/sock.c b/net/core/sock.c index 6a871b8fdd20..5a6a90620656 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -136,6 +136,46 @@ #include #endif +static DEFINE_RWLOCK(proto_list_lock); +static LIST_HEAD(proto_list); + +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) +{ + struct proto *proto; + int ret = 0; + + read_lock(&proto_list_lock); + list_for_each_entry(proto, &proto_list, node) { + if (proto->init_cgroup) { + ret = proto->init_cgroup(cgrp, ss); + if (ret) + goto out; + } + } + + read_unlock(&proto_list_lock); + return ret; +out: + list_for_each_entry_continue_reverse(proto, &proto_list, node) + if (proto->destroy_cgroup) + proto->destroy_cgroup(cgrp, ss); + read_unlock(&proto_list_lock); + return ret; +} + +void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss) +{ + struct proto *proto; + + read_lock(&proto_list_lock); + list_for_each_entry_reverse(proto, &proto_list, node) + if (proto->destroy_cgroup) + proto->destroy_cgroup(cgrp, ss); + read_unlock(&proto_list_lock); +} +#endif + /* * Each address family might have different locking rules, so we have * one slock key per address family: @@ -2291,9 +2331,6 @@ void sk_common_release(struct sock *sk) } EXPORT_SYMBOL(sk_common_release); -static DEFINE_RWLOCK(proto_list_lock); -static LIST_HEAD(proto_list); - #ifdef CONFIG_PROC_FS #define PROTO_INUSE_NR 64 /* should be enough for the first time */ struct prot_inuse { diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index e9d98e621112..ff75d3bbcd6a 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o +obj-$(CONFIG_CGROUP_MEM_RES_CTLR_KMEM) += tcp_memcontrol.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f48bf312cfe8..42714cb1fef3 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -73,6 +73,7 @@ #include #include #include +#include #include #include @@ -1917,6 +1918,7 @@ static int tcp_v4_init_sock(struct sock *sk) sk->sk_rcvbuf = sysctl_tcp_rmem[1]; local_bh_disable(); + sock_update_memcg(sk); sk_sockets_allocated_inc(sk); local_bh_enable(); @@ -1974,6 +1976,7 @@ void tcp_v4_destroy_sock(struct sock *sk) } sk_sockets_allocated_dec(sk); + sock_release_memcg(sk); } EXPORT_SYMBOL(tcp_v4_destroy_sock); @@ -2634,10 +2637,14 @@ struct proto tcp_prot = { .compat_setsockopt = compat_tcp_setsockopt, .compat_getsockopt = compat_tcp_getsockopt, #endif +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM + .init_cgroup = tcp_init_cgroup, + .destroy_cgroup = tcp_destroy_cgroup, + .proto_cgroup = tcp_proto_cgroup, +#endif }; EXPORT_SYMBOL(tcp_prot); - static int __net_init tcp_sk_init(struct net *net) { return inet_ctl_sock_create(&net->ipv4.tcp_sock, diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c new file mode 100644 index 000000000000..4a68d2c24556 --- /dev/null +++ b/net/ipv4/tcp_memcontrol.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto) +{ + return container_of(cg_proto, struct tcp_memcontrol, cg_proto); +} + +static void memcg_tcp_enter_memory_pressure(struct sock *sk) +{ + if (!sk->sk_cgrp->memory_pressure) + *sk->sk_cgrp->memory_pressure = 1; +} +EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure); + +int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) +{ + /* + * The root cgroup does not use res_counters, but rather, + * rely on the data already collected by the network + * subsystem + */ + struct res_counter *res_parent = NULL; + struct cg_proto *cg_proto, *parent_cg; + struct tcp_memcontrol *tcp; + struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); + struct mem_cgroup *parent = parent_mem_cgroup(memcg); + + cg_proto = tcp_prot.proto_cgroup(memcg); + if (!cg_proto) + return 0; + + tcp = tcp_from_cgproto(cg_proto); + + tcp->tcp_prot_mem[0] = sysctl_tcp_mem[0]; + tcp->tcp_prot_mem[1] = sysctl_tcp_mem[1]; + tcp->tcp_prot_mem[2] = sysctl_tcp_mem[2]; + tcp->tcp_memory_pressure = 0; + + parent_cg = tcp_prot.proto_cgroup(parent); + if (parent_cg) + res_parent = parent_cg->memory_allocated; + + res_counter_init(&tcp->tcp_memory_allocated, res_parent); + percpu_counter_init(&tcp->tcp_sockets_allocated, 0); + + cg_proto->enter_memory_pressure = memcg_tcp_enter_memory_pressure; + cg_proto->memory_pressure = &tcp->tcp_memory_pressure; + cg_proto->sysctl_mem = tcp->tcp_prot_mem; + cg_proto->memory_allocated = &tcp->tcp_memory_allocated; + cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated; + cg_proto->memcg = memcg; + + return 0; +} +EXPORT_SYMBOL(tcp_init_cgroup); + +void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss) +{ + struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp); + struct cg_proto *cg_proto; + struct tcp_memcontrol *tcp; + + cg_proto = tcp_prot.proto_cgroup(memcg); + if (!cg_proto) + return; + + tcp = tcp_from_cgproto(cg_proto); + percpu_counter_destroy(&tcp->tcp_sockets_allocated); +} +EXPORT_SYMBOL(tcp_destroy_cgroup); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b69c7030aba9..95d3cfb65d39 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -62,6 +62,7 @@ #include #include #include +#include #include @@ -1994,6 +1995,7 @@ static int tcp_v6_init_sock(struct sock *sk) sk->sk_rcvbuf = sysctl_tcp_rmem[1]; local_bh_disable(); + sock_update_memcg(sk); sk_sockets_allocated_inc(sk); local_bh_enable(); @@ -2227,6 +2229,9 @@ struct proto tcpv6_prot = { .compat_setsockopt = compat_tcp_setsockopt, .compat_getsockopt = compat_tcp_getsockopt, #endif +#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM + .proto_cgroup = tcp_proto_cgroup, +#endif }; static const struct inet6_protocol tcpv6_protocol = { -- cgit From 9f048bfba15a22d1d1ce0c1f44567fa16bed4d25 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Dec 2011 03:59:08 +0000 Subject: net: fix build error if CONFIG_CGROUPS=n Reported-by: Christoph Paasch Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/net/sock.h') diff --git a/include/net/sock.h b/include/net/sock.h index 18ecc9919d29..6fe0dae81451 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -64,6 +64,8 @@ #include #include +struct cgroup; +struct cgroup_subsys; int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss); void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss); /* -- cgit From c607b2ed84929e143d9fb5653c4b5d0109147cde Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 16 Dec 2011 00:52:00 +0000 Subject: net: fix compilation with !CONFIG_NET Reported-by: Randy Dunlap Signed-off-by: Glauber Costa CC: Hiroyouki Kamezawa CC: David S. Miller CC: Eric Dumazet CC: Stephen Rothwell Signed-off-by: David S. Miller --- include/net/sock.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include/net/sock.h') diff --git a/include/net/sock.h b/include/net/sock.h index 6fe0dae81451..3144c7950649 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -66,8 +66,20 @@ struct cgroup; struct cgroup_subsys; +#ifdef CONFIG_NET int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss); void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss); +#else +static inline +int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) +{ + return 0; +} +static inline +void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss) +{ +} +#endif /* * This structure really needs to be cleaned up. * Most of it is for TCP, and not used by any of -- cgit From 0fd7bac6b6157eed6cf0cb86a1e88ba29e57c033 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Dec 2011 07:11:44 +0000 Subject: net: relax rcvbuf limits skb->truesize might be big even for a small packet. Its even bigger after commit 87fb4b7b533 (net: more accurate skb truesize) and big MTU. We should allow queueing at least one packet per receiver, even with a low RCVBUF setting. Reported-by: Michal Simek Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 4 +++- net/core/sock.c | 6 +----- net/packet/af_packet.c | 6 ++---- 3 files changed, 6 insertions(+), 10 deletions(-) (limited to 'include/net/sock.h') diff --git a/include/net/sock.h b/include/net/sock.h index abb6e0f0c3c3..32e39371fba6 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -637,12 +637,14 @@ static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb) /* * Take into account size of receive queue and backlog queue + * Do not take into account this skb truesize, + * to allow even a single big packet to come. */ static inline bool sk_rcvqueues_full(const struct sock *sk, const struct sk_buff *skb) { unsigned int qsize = sk->sk_backlog.len + atomic_read(&sk->sk_rmem_alloc); - return qsize + skb->truesize > sk->sk_rcvbuf; + return qsize > sk->sk_rcvbuf; } /* The per-socket spinlock must be held here. */ diff --git a/net/core/sock.c b/net/core/sock.c index 4ed7b1d12f5e..b23f174ab84c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -288,11 +288,7 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) unsigned long flags; struct sk_buff_head *list = &sk->sk_receive_queue; - /* Cast sk->rcvbuf to unsigned... It's pointless, but reduces - number of warnings when compiling with -W --ANK - */ - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned)sk->sk_rcvbuf) { + if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) { atomic_inc(&sk->sk_drops); trace_sock_rcvqueue_full(sk, skb); return -ENOMEM; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 82a6f34d39d0..3891702b81df 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1630,8 +1630,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, if (snaplen > res) snaplen = res; - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned)sk->sk_rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) goto drop_n_acct; if (skb_shared(skb)) { @@ -1762,8 +1761,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if (po->tp_version <= TPACKET_V2) { if (macoff + snaplen > po->rx_ring.frame_size) { if (po->copy_thresh && - atomic_read(&sk->sk_rmem_alloc) + skb->truesize - < (unsigned)sk->sk_rcvbuf) { + atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) { if (skb_shared(skb)) { copy_skb = skb_clone(skb, GFP_ATOMIC); } else { -- cgit From 1a3bc369ba547c11ca8b3ed079d7584f27499e70 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 21 Jan 2012 09:03:10 +0000 Subject: kernel-doc: fix new warning in net/sock.h Fix new kernel-doc warning: Warning(include/net/sock.h:372): No description found for parameter 'sk_cgrp_prioidx' Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- include/net/sock.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/net/sock.h') diff --git a/include/net/sock.h b/include/net/sock.h index bb972d254dff..97fc0ad47da0 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -226,6 +226,7 @@ struct cg_proto; * @sk_ack_backlog: current listen backlog * @sk_max_ack_backlog: listen backlog set in listen() * @sk_priority: %SO_PRIORITY setting + * @sk_cgrp_prioidx: socket group's priority map index * @sk_type: socket type (%SOCK_STREAM, etc) * @sk_protocol: which protocol this socket belongs in this network family * @sk_peer_pid: &struct pid for this socket's peer -- cgit From 376be5ff8a6a36efadd131860cf26841f366d44c Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 20 Jan 2012 04:57:14 +0000 Subject: net: fix socket memcg build with !CONFIG_NET There is still a build bug with the sock memcg code, that triggers with !CONFIG_NET, that survived my series of randconfig builds. Signed-off-by: Glauber Costa Reported-by: Randy Dunlap CC: Hiroyouki Kamezawa Signed-off-by: David S. Miller --- include/net/sock.h | 2 +- mm/memcontrol.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include/net/sock.h') diff --git a/include/net/sock.h b/include/net/sock.h index 97fc0ad47da0..0e7a9b05f92b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -922,7 +922,7 @@ inline void sk_refcnt_debug_release(const struct sock *sk) #define sk_refcnt_debug_release(sk) do { } while (0) #endif /* SOCK_REFCNT_DEBUG */ -#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM +#if defined(CONFIG_CGROUP_MEM_RES_CTLR_KMEM) && defined(CONFIG_NET) extern struct jump_label_key memcg_socket_limit_enabled; static inline struct cg_proto *parent_cg_proto(struct proto *proto, struct cg_proto *cg_proto) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3dbff4dcde35..c3688dfd9a5f 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -379,7 +379,7 @@ static void mem_cgroup_put(struct mem_cgroup *memcg); static bool mem_cgroup_is_root(struct mem_cgroup *memcg); void sock_update_memcg(struct sock *sk) { - if (static_branch(&memcg_socket_limit_enabled)) { + if (mem_cgroup_sockets_enabled) { struct mem_cgroup *memcg; BUG_ON(!sk->sk_prot->proto_cgroup); @@ -411,7 +411,7 @@ EXPORT_SYMBOL(sock_update_memcg); void sock_release_memcg(struct sock *sk) { - if (static_branch(&memcg_socket_limit_enabled) && sk->sk_cgrp) { + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) { struct mem_cgroup *memcg; WARN_ON(!sk->sk_cgrp->memcg); memcg = sk->sk_cgrp->memcg; -- cgit From 0e90b31f4ba77027a7c21cbfc66404df0851ca21 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 20 Jan 2012 04:57:16 +0000 Subject: net: introduce res_counter_charge_nofail() for socket allocations There is a case in __sk_mem_schedule(), where an allocation is beyond the maximum, but yet we are allowed to proceed. It happens under the following condition: sk->sk_wmem_queued + size >= sk->sk_sndbuf The network code won't revert the allocation in this case, meaning that at some point later it'll try to do it. Since this is never communicated to the underlying res_counter code, there is an inbalance in res_counter uncharge operation. I see two ways of fixing this: 1) storing the information about those allocations somewhere in memcg, and then deducting from that first, before we start draining the res_counter, 2) providing a slightly different allocation function for the res_counter, that matches the original behavior of the network code more closely. I decided to go for #2 here, believing it to be more elegant, since #1 would require us to do basically that, but in a more obscure way. Signed-off-by: Glauber Costa Cc: KAMEZAWA Hiroyuki Cc: Johannes Weiner Cc: Michal Hocko CC: Tejun Heo CC: Li Zefan CC: Laurent Chavey Acked-by: Tejun Heo Signed-off-by: David S. Miller --- include/linux/res_counter.h | 6 ++++++ include/net/sock.h | 10 ++++------ kernel/res_counter.c | 25 +++++++++++++++++++++++++ net/core/sock.c | 4 ++-- 4 files changed, 37 insertions(+), 8 deletions(-) (limited to 'include/net/sock.h') diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h index d06d014afda6..da81af086eaf 100644 --- a/include/linux/res_counter.h +++ b/include/linux/res_counter.h @@ -109,12 +109,18 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent); * * returns 0 on success and <0 if the counter->usage will exceed the * counter->limit _locked call expects the counter->lock to be taken + * + * charge_nofail works the same, except that it charges the resource + * counter unconditionally, and returns < 0 if the after the current + * charge we are over limit. */ int __must_check res_counter_charge_locked(struct res_counter *counter, unsigned long val); int __must_check res_counter_charge(struct res_counter *counter, unsigned long val, struct res_counter **limit_fail_at); +int __must_check res_counter_charge_nofail(struct res_counter *counter, + unsigned long val, struct res_counter **limit_fail_at); /* * uncharge - tell that some portion of the resource is released diff --git a/include/net/sock.h b/include/net/sock.h index 0e7a9b05f92b..4c69ac165e6b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1008,9 +1008,8 @@ static inline void memcg_memory_allocated_add(struct cg_proto *prot, struct res_counter *fail; int ret; - ret = res_counter_charge(prot->memory_allocated, - amt << PAGE_SHIFT, &fail); - + ret = res_counter_charge_nofail(prot->memory_allocated, + amt << PAGE_SHIFT, &fail); if (ret < 0) *parent_status = OVER_LIMIT; } @@ -1054,12 +1053,11 @@ sk_memory_allocated_add(struct sock *sk, int amt, int *parent_status) } static inline void -sk_memory_allocated_sub(struct sock *sk, int amt, int parent_status) +sk_memory_allocated_sub(struct sock *sk, int amt) { struct proto *prot = sk->sk_prot; - if (mem_cgroup_sockets_enabled && sk->sk_cgrp && - parent_status != OVER_LIMIT) /* Otherwise was uncharged already */ + if (mem_cgroup_sockets_enabled && sk->sk_cgrp) memcg_memory_allocated_sub(sk->sk_cgrp, amt); atomic_long_sub(amt, prot->memory_allocated); diff --git a/kernel/res_counter.c b/kernel/res_counter.c index 6d269cce7aa1..d508363858b3 100644 --- a/kernel/res_counter.c +++ b/kernel/res_counter.c @@ -66,6 +66,31 @@ done: return ret; } +int res_counter_charge_nofail(struct res_counter *counter, unsigned long val, + struct res_counter **limit_fail_at) +{ + int ret, r; + unsigned long flags; + struct res_counter *c; + + r = ret = 0; + *limit_fail_at = NULL; + local_irq_save(flags); + for (c = counter; c != NULL; c = c->parent) { + spin_lock(&c->lock); + r = res_counter_charge_locked(c, val); + if (r) + c->usage += val; + spin_unlock(&c->lock); + if (r < 0 && ret == 0) { + *limit_fail_at = c; + ret = r; + } + } + local_irq_restore(flags); + + return ret; +} void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val) { if (WARN_ON(counter->usage < val)) diff --git a/net/core/sock.c b/net/core/sock.c index 5c5af9988f94..3e81fd2e3c75 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1827,7 +1827,7 @@ suppress_allocation: /* Alas. Undo changes. */ sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM; - sk_memory_allocated_sub(sk, amt, parent_status); + sk_memory_allocated_sub(sk, amt); return 0; } @@ -1840,7 +1840,7 @@ EXPORT_SYMBOL(__sk_mem_schedule); void __sk_mem_reclaim(struct sock *sk) { sk_memory_allocated_sub(sk, - sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT, 0); + sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT); sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1; if (sk_under_memory_pressure(sk) && -- cgit From 9018e93948c6f8f95fbcc9fa05f6c403d6adb406 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Thu, 26 Jan 2012 12:09:28 +0000 Subject: net: explicitly add jump_label.h header to sock.h Commit 36a1211970193ce215de50ed1e4e1272bc814df1 removed linux/module.h include statement from one of the headers that end up in net/sock.h. It was providing us with static_branch() definition implicitly, so after its removal the build got broken. To fix this, and avoid having this happening in the future, let me do the right thing and include linux/jump_label.h explicitly in sock.h. Signed-off-by: Glauber Costa Reported-by: Randy Dunlap CC: David S. Miller Signed-off-by: David S. Miller --- include/net/sock.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/net/sock.h') diff --git a/include/net/sock.h b/include/net/sock.h index 4c69ac165e6b..91c1c8baf020 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -55,6 +55,7 @@ #include #include #include +#include #include #include -- cgit