aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/sock.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/sock.c')
-rw-r--r--net/core/sock.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/net/core/sock.c b/net/core/sock.c
index 6354863b1c68..76334228ed1c 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -631,7 +631,7 @@ set_rcvbuf:
631 631
632 case SO_TIMESTAMPING: 632 case SO_TIMESTAMPING:
633 if (val & ~SOF_TIMESTAMPING_MASK) { 633 if (val & ~SOF_TIMESTAMPING_MASK) {
634 ret = EINVAL; 634 ret = -EINVAL;
635 break; 635 break;
636 } 636 }
637 sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE, 637 sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE,
@@ -919,13 +919,19 @@ static inline void sock_lock_init(struct sock *sk)
919 af_family_keys + sk->sk_family); 919 af_family_keys + sk->sk_family);
920} 920}
921 921
922/*
923 * Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet,
924 * even temporarly, because of RCU lookups. sk_node should also be left as is.
925 */
922static void sock_copy(struct sock *nsk, const struct sock *osk) 926static void sock_copy(struct sock *nsk, const struct sock *osk)
923{ 927{
924#ifdef CONFIG_SECURITY_NETWORK 928#ifdef CONFIG_SECURITY_NETWORK
925 void *sptr = nsk->sk_security; 929 void *sptr = nsk->sk_security;
926#endif 930#endif
927 931 BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) !=
928 memcpy(nsk, osk, osk->sk_prot->obj_size); 932 sizeof(osk->sk_node) + sizeof(osk->sk_refcnt));
933 memcpy(&nsk->sk_copy_start, &osk->sk_copy_start,
934 osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start));
929#ifdef CONFIG_SECURITY_NETWORK 935#ifdef CONFIG_SECURITY_NETWORK
930 nsk->sk_security = sptr; 936 nsk->sk_security = sptr;
931 security_sk_clone(osk, nsk); 937 security_sk_clone(osk, nsk);
@@ -939,8 +945,23 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,
939 struct kmem_cache *slab; 945 struct kmem_cache *slab;
940 946
941 slab = prot->slab; 947 slab = prot->slab;
942 if (slab != NULL) 948 if (slab != NULL) {
943 sk = kmem_cache_alloc(slab, priority); 949 sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO);
950 if (!sk)
951 return sk;
952 if (priority & __GFP_ZERO) {
953 /*
954 * caches using SLAB_DESTROY_BY_RCU should let
955 * sk_node.next un-modified. Special care is taken
956 * when initializing object to zero.
957 */
958 if (offsetof(struct sock, sk_node.next) != 0)
959 memset(sk, 0, offsetof(struct sock, sk_node.next));
960 memset(&sk->sk_node.pprev, 0,
961 prot->obj_size - offsetof(struct sock,
962 sk_node.pprev));
963 }
964 }
944 else 965 else
945 sk = kmalloc(prot->obj_size, priority); 966 sk = kmalloc(prot->obj_size, priority);
946 967
@@ -1004,6 +1025,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
1004 sk->sk_prot = sk->sk_prot_creator = prot; 1025 sk->sk_prot = sk->sk_prot_creator = prot;
1005 sock_lock_init(sk); 1026 sock_lock_init(sk);
1006 sock_net_set(sk, get_net(net)); 1027 sock_net_set(sk, get_net(net));
1028 atomic_set(&sk->sk_wmem_alloc, 1);
1007 } 1029 }
1008 1030
1009 return sk; 1031 return sk;
@@ -1125,6 +1147,11 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
1125 1147
1126 newsk->sk_err = 0; 1148 newsk->sk_err = 0;
1127 newsk->sk_priority = 0; 1149 newsk->sk_priority = 0;
1150 /*
1151 * Before updating sk_refcnt, we must commit prior changes to memory
1152 * (Documentation/RCU/rculist_nulls.txt for details)
1153 */
1154 smp_wmb();
1128 atomic_set(&newsk->sk_refcnt, 2); 1155 atomic_set(&newsk->sk_refcnt, 2);
1129 1156
1130 /* 1157 /*
@@ -1840,8 +1867,12 @@ void sock_init_data(struct socket *sock, struct sock *sk)
1840 1867
1841 sk->sk_stamp = ktime_set(-1L, 0); 1868 sk->sk_stamp = ktime_set(-1L, 0);
1842 1869
1870 /*
1871 * Before updating sk_refcnt, we must commit prior changes to memory
1872 * (Documentation/RCU/rculist_nulls.txt for details)
1873 */
1874 smp_wmb();
1843 atomic_set(&sk->sk_refcnt, 1); 1875 atomic_set(&sk->sk_refcnt, 1);
1844 atomic_set(&sk->sk_wmem_alloc, 1);
1845 atomic_set(&sk->sk_drops, 0); 1876 atomic_set(&sk->sk_drops, 0);
1846} 1877}
1847EXPORT_SYMBOL(sock_init_data); 1878EXPORT_SYMBOL(sock_init_data);