sock: struct proto hash function may error
authorCraig Gallek <kraig@google.com>
Wed, 10 Feb 2016 16:50:35 +0000 (11:50 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 11 Feb 2016 08:54:14 +0000 (03:54 -0500)
In order to support fast reuseport lookups in TCP, the hash function
defined in struct proto must be capable of returning an error code.
This patch changes the function signature of all related hash functions
to return an integer and handles or propagates this return value at
all call sites.

Signed-off-by: Craig Gallek <kraig@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
15 files changed:
include/net/inet_hashtables.h
include/net/phonet/phonet.h
include/net/ping.h
include/net/raw.h
include/net/sock.h
include/net/udp.h
net/ieee802154/socket.c
net/ipv4/af_inet.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_hashtables.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv6/af_inet6.c
net/phonet/socket.c
net/sctp/socket.c

index de2e3ade61028cc9937861a6218e3f26ff4a1321..554440e7f83d53485b3e8205c46d397f8dba764a 100644 (file)
@@ -208,7 +208,7 @@ void inet_hashinfo_init(struct inet_hashinfo *h);
 bool inet_ehash_insert(struct sock *sk, struct sock *osk);
 bool inet_ehash_nolisten(struct sock *sk, struct sock *osk);
 void __inet_hash(struct sock *sk, struct sock *osk);
-void inet_hash(struct sock *sk);
+int inet_hash(struct sock *sk);
 void inet_unhash(struct sock *sk);
 
 struct sock *__inet_lookup_listener(struct net *net,
index 68e509750caa4cb60d54b48d62cb23cf109dd17d..039cc29cb4a81284d29935c23451a84f04fe1ded 100644 (file)
@@ -51,7 +51,7 @@ void pn_sock_init(void);
 struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *sa);
 void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb);
 void phonet_get_local_port_range(int *min, int *max);
-void pn_sock_hash(struct sock *sk);
+int pn_sock_hash(struct sock *sk);
 void pn_sock_unhash(struct sock *sk);
 int pn_sock_get_port(struct sock *sk, unsigned short sport);
 
index ac80cb45e63004ef5e12383002721e9a4634971c..5fd7cc244833d3f22b2069ff39b8282903c158e8 100644 (file)
@@ -65,7 +65,7 @@ struct pingfakehdr {
 };
 
 int  ping_get_port(struct sock *sk, unsigned short ident);
-void ping_hash(struct sock *sk);
+int ping_hash(struct sock *sk);
 void ping_unhash(struct sock *sk);
 
 int  ping_init_sock(struct sock *sk);
index 6a40c6562dd2a39ac5b4f6ee4a1331b0559bfb02..3e789008394d32f0faba9e170b1fa5f09dbbe7f4 100644 (file)
@@ -57,7 +57,7 @@ int raw_seq_open(struct inode *ino, struct file *file,
 
 #endif
 
-void raw_hash_sk(struct sock *sk);
+int raw_hash_sk(struct sock *sk);
 void raw_unhash_sk(struct sock *sk);
 
 struct raw_sock {
index f5ea148853e2f76257aca80a4aef65a30d587538..255d3e03727b737091141c1eb8b2f796afff9d9b 100644 (file)
@@ -984,7 +984,7 @@ struct proto {
        void            (*release_cb)(struct sock *sk);
 
        /* Keeping track of sk's, looking them up, and port selection methods. */
-       void                    (*hash)(struct sock *sk);
+       int                     (*hash)(struct sock *sk);
        void                    (*unhash)(struct sock *sk);
        void                    (*rehash)(struct sock *sk);
        int                     (*get_port)(struct sock *sk, unsigned short snum);
@@ -1194,10 +1194,10 @@ static inline void sock_prot_inuse_add(struct net *net, struct proto *prot,
 /* With per-bucket locks this operation is not-atomic, so that
  * this version is not worse.
  */
-static inline void __sk_prot_rehash(struct sock *sk)
+static inline int __sk_prot_rehash(struct sock *sk)
 {
        sk->sk_prot->unhash(sk);
-       sk->sk_prot->hash(sk);
+       return sk->sk_prot->hash(sk);
 }
 
 void sk_prot_clear_portaddr_nulls(struct sock *sk, int size);
index 2842541e28e715ca12b00eed901e0be2f8741a6c..92927f729ac86495a947d0fc9e2650e5e44ded2b 100644 (file)
@@ -177,9 +177,10 @@ static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb)
 }
 
 /* hash routines shared between UDPv4/6 and UDP-Litev4/6 */
-static inline void udp_lib_hash(struct sock *sk)
+static inline int udp_lib_hash(struct sock *sk)
 {
        BUG();
+       return 0;
 }
 
 void udp_lib_unhash(struct sock *sk);
index a548be247e15d87c82cfda7a6cd3bde32a7159a7..e0bd013a1e5ed9fc8fbd16329a877f0231e13271 100644 (file)
@@ -182,12 +182,14 @@ static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
 static HLIST_HEAD(raw_head);
 static DEFINE_RWLOCK(raw_lock);
 
-static void raw_hash(struct sock *sk)
+static int raw_hash(struct sock *sk)
 {
        write_lock_bh(&raw_lock);
        sk_add_node(sk, &raw_head);
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
        write_unlock_bh(&raw_lock);
+
+       return 0;
 }
 
 static void raw_unhash(struct sock *sk)
@@ -462,12 +464,14 @@ static inline struct dgram_sock *dgram_sk(const struct sock *sk)
        return container_of(sk, struct dgram_sock, sk);
 }
 
-static void dgram_hash(struct sock *sk)
+static int dgram_hash(struct sock *sk)
 {
        write_lock_bh(&dgram_lock);
        sk_add_node(sk, &dgram_head);
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
        write_unlock_bh(&dgram_lock);
+
+       return 0;
 }
 
 static void dgram_unhash(struct sock *sk)
@@ -1026,8 +1030,13 @@ static int ieee802154_create(struct net *net, struct socket *sock,
        /* Checksums on by default */
        sock_set_flag(sk, SOCK_ZAPPED);
 
-       if (sk->sk_prot->hash)
-               sk->sk_prot->hash(sk);
+       if (sk->sk_prot->hash) {
+               rc = sk->sk_prot->hash(sk);
+               if (rc) {
+                       sk_common_release(sk);
+                       goto out;
+               }
+       }
 
        if (sk->sk_prot->init) {
                rc = sk->sk_prot->init(sk);
index 5c5db6636704daa0c49fc13e84b2c5b282a44ed3..eade66db214e99b42a732c5c8aa8c3744984a06c 100644 (file)
@@ -370,7 +370,11 @@ lookup_protocol:
                 */
                inet->inet_sport = htons(inet->inet_num);
                /* Add to protocol hash chains. */
-               sk->sk_prot->hash(sk);
+               err = sk->sk_prot->hash(sk);
+               if (err) {
+                       sk_common_release(sk);
+                       goto out;
+               }
        }
 
        if (sk->sk_prot->init) {
@@ -1142,8 +1146,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
         * Besides that, it does not check for connection
         * uniqueness. Wait for troubles.
         */
-       __sk_prot_rehash(sk);
-       return 0;
+       return __sk_prot_rehash(sk);
 }
 
 int inet_sk_rebuild_header(struct sock *sk)
index 9b17c1792dce6b1f93b7c1a0c4e5cf941220b9c2..12c8d389dc18eb45074e2dd84706a57a629a914c 100644 (file)
@@ -734,6 +734,7 @@ int inet_csk_listen_start(struct sock *sk, int backlog)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct inet_sock *inet = inet_sk(sk);
+       int err = -EADDRINUSE;
 
        reqsk_queue_alloc(&icsk->icsk_accept_queue);
 
@@ -751,13 +752,14 @@ int inet_csk_listen_start(struct sock *sk, int backlog)
                inet->inet_sport = htons(inet->inet_num);
 
                sk_dst_reset(sk);
-               sk->sk_prot->hash(sk);
+               err = sk->sk_prot->hash(sk);
 
-               return 0;
+               if (likely(!err))
+                       return 0;
        }
 
        sk->sk_state = TCP_CLOSE;
-       return -EADDRINUSE;
+       return err;
 }
 EXPORT_SYMBOL_GPL(inet_csk_listen_start);
 
index ccc5980797fcdb9ed3a1003db47e4e8cb7180279..b6023b7baae0126cf4d4cde15ba1a37974fe281b 100644 (file)
@@ -468,13 +468,15 @@ void __inet_hash(struct sock *sk, struct sock *osk)
 }
 EXPORT_SYMBOL(__inet_hash);
 
-void inet_hash(struct sock *sk)
+int inet_hash(struct sock *sk)
 {
        if (sk->sk_state != TCP_CLOSE) {
                local_bh_disable();
                __inet_hash(sk, NULL);
                local_bh_enable();
        }
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(inet_hash);
 
index c117b21b937de778dffa484d589141ea31e1b6bc..f6f93fc2c61f33bcce56d7b4277784c9bb1236a1 100644 (file)
@@ -145,10 +145,12 @@ fail:
 }
 EXPORT_SYMBOL_GPL(ping_get_port);
 
-void ping_hash(struct sock *sk)
+int ping_hash(struct sock *sk)
 {
        pr_debug("ping_hash(sk->port=%u)\n", inet_sk(sk)->inet_num);
        BUG(); /* "Please do not press this button again." */
+
+       return 0;
 }
 
 void ping_unhash(struct sock *sk)
index bc35f1842512bef8e4d87e76542d7bf11f8946fa..d6352515d7384df1f6593ef67d4d9e15337541af 100644 (file)
@@ -93,7 +93,7 @@ static struct raw_hashinfo raw_v4_hashinfo = {
        .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
 };
 
-void raw_hash_sk(struct sock *sk)
+int raw_hash_sk(struct sock *sk)
 {
        struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
        struct hlist_head *head;
@@ -104,6 +104,8 @@ void raw_hash_sk(struct sock *sk)
        sk_add_node(sk, head);
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
        write_unlock_bh(&h->lock);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(raw_hash_sk);
 
index 9f5137cd604e51316c6c3a85ca5423b30ed7ce30..b11c37cfd67c81c24115898e8694fd1bfb7684a1 100644 (file)
@@ -235,7 +235,11 @@ lookup_protocol:
                 * creation time automatically shares.
                 */
                inet->inet_sport = htons(inet->inet_num);
-               sk->sk_prot->hash(sk);
+               err = sk->sk_prot->hash(sk);
+               if (err) {
+                       sk_common_release(sk);
+                       goto out;
+               }
        }
        if (sk->sk_prot->init) {
                err = sk->sk_prot->init(sk);
index d575ef4e9aa6d390bde4f78ba85247acf8e9bf65..ffd5f2297584879288eb55d2cf20b3b382b2378d 100644 (file)
@@ -140,13 +140,15 @@ void pn_deliver_sock_broadcast(struct net *net, struct sk_buff *skb)
        rcu_read_unlock();
 }
 
-void pn_sock_hash(struct sock *sk)
+int pn_sock_hash(struct sock *sk)
 {
        struct hlist_head *hlist = pn_hash_list(pn_sk(sk)->sobject);
 
        mutex_lock(&pnsocks.lock);
        sk_add_node_rcu(sk, hlist);
        mutex_unlock(&pnsocks.lock);
+
+       return 0;
 }
 EXPORT_SYMBOL(pn_sock_hash);
 
@@ -200,7 +202,7 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
        pn->resource = spn->spn_resource;
 
        /* Enable RX on the socket */
-       sk->sk_prot->hash(sk);
+       err = sk->sk_prot->hash(sk);
 out_port:
        mutex_unlock(&port_mutex);
 out:
index 5ca2ebfe0be83882fcb841de6fa8029b6455ef85..6427b9d1197eedbdb974c665feba8a21ea769fdc 100644 (file)
@@ -6101,9 +6101,10 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
        return retval;
 }
 
-static void sctp_hash(struct sock *sk)
+static int sctp_hash(struct sock *sk)
 {
        /* STUB */
+       return 0;
 }
 
 static void sctp_unhash(struct sock *sk)