Blame view

net/rds/bind.c 5.14 KB
639b321b4   Andy Grover   RDS: Socket inter...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  /*
   * Copyright (c) 2006 Oracle.  All rights reserved.
   *
   * This software is available to you under a choice of one of two
   * licenses.  You may choose to be licensed under the terms of the GNU
   * General Public License (GPL) Version 2, available from the file
   * COPYING in the main directory of this source tree, or the
   * OpenIB.org BSD license below:
   *
   *     Redistribution and use in source and binary forms, with or
   *     without modification, are permitted provided that the following
   *     conditions are met:
   *
   *      - Redistributions of source code must retain the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer.
   *
   *      - Redistributions in binary form must reproduce the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer in the documentation and/or other materials
   *        provided with the distribution.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   *
   */
  #include <linux/kernel.h>
  #include <net/sock.h>
  #include <linux/in.h>
  #include <linux/if_arp.h>
38a4e5e61   Chris Mason   rds: Use RCU for ...
37
  #include <linux/jhash.h>
cb0a60564   Manuel Zerpies   net/rds: use prin...
38
  #include <linux/ratelimit.h>
639b321b4   Andy Grover   RDS: Socket inter...
39
  #include "rds.h"
38a4e5e61   Chris Mason   rds: Use RCU for ...
40
41
42
43
44
45
46
47
48
  #define BIND_HASH_SIZE 1024
  static struct hlist_head bind_hash_table[BIND_HASH_SIZE];
  static DEFINE_SPINLOCK(rds_bind_lock);
  
  static struct hlist_head *hash_to_bucket(__be32 addr, __be16 port)
  {
  	return bind_hash_table + (jhash_2words((u32)addr, (u32)port, 0) &
  				  (BIND_HASH_SIZE - 1));
  }
639b321b4   Andy Grover   RDS: Socket inter...
49

38a4e5e61   Chris Mason   rds: Use RCU for ...
50
51
  static struct rds_sock *rds_bind_lookup(__be32 addr, __be16 port,
  					struct rds_sock *insert)
639b321b4   Andy Grover   RDS: Socket inter...
52
  {
639b321b4   Andy Grover   RDS: Socket inter...
53
  	struct rds_sock *rs;
38a4e5e61   Chris Mason   rds: Use RCU for ...
54
  	struct hlist_head *head = hash_to_bucket(addr, port);
639b321b4   Andy Grover   RDS: Socket inter...
55
56
  	u64 cmp;
  	u64 needle = ((u64)be32_to_cpu(addr) << 32) | be16_to_cpu(port);
38a4e5e61   Chris Mason   rds: Use RCU for ...
57
  	rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
58
  	hlist_for_each_entry_rcu(rs, head, rs_bound_node) {
639b321b4   Andy Grover   RDS: Socket inter...
59
60
  		cmp = ((u64)be32_to_cpu(rs->rs_bound_addr) << 32) |
  		      be16_to_cpu(rs->rs_bound_port);
38a4e5e61   Chris Mason   rds: Use RCU for ...
61
62
  		if (cmp == needle) {
  			rcu_read_unlock();
639b321b4   Andy Grover   RDS: Socket inter...
63
  			return rs;
38a4e5e61   Chris Mason   rds: Use RCU for ...
64
  		}
639b321b4   Andy Grover   RDS: Socket inter...
65
  	}
38a4e5e61   Chris Mason   rds: Use RCU for ...
66
  	rcu_read_unlock();
639b321b4   Andy Grover   RDS: Socket inter...
67
68
  
  	if (insert) {
38a4e5e61   Chris Mason   rds: Use RCU for ...
69
70
71
72
73
74
75
76
77
78
79
  		/*
  		 * make sure our addr and port are set before
  		 * we are added to the list, other people
  		 * in rcu will find us as soon as the
  		 * hlist_add_head_rcu is done
  		 */
  		insert->rs_bound_addr = addr;
  		insert->rs_bound_port = port;
  		rds_sock_addref(insert);
  
  		hlist_add_head_rcu(&insert->rs_bound_node, head);
639b321b4   Andy Grover   RDS: Socket inter...
80
81
82
83
84
85
86
87
88
89
90
91
92
  	}
  	return NULL;
  }
  
  /*
   * Return the rds_sock bound at the given local address.
   *
   * The rx path can race with rds_release.  We notice if rds_release() has
   * marked this socket and don't return a rs ref to the rx path.
   */
  struct rds_sock *rds_find_bound(__be32 addr, __be16 port)
  {
  	struct rds_sock *rs;
639b321b4   Andy Grover   RDS: Socket inter...
93

38a4e5e61   Chris Mason   rds: Use RCU for ...
94
  	rs = rds_bind_lookup(addr, port, NULL);
639b321b4   Andy Grover   RDS: Socket inter...
95
96
97
98
  	if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD))
  		rds_sock_addref(rs);
  	else
  		rs = NULL;
639b321b4   Andy Grover   RDS: Socket inter...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  
  	rdsdebug("returning rs %p for %pI4:%u
  ", rs, &addr,
  		ntohs(port));
  	return rs;
  }
  
  /* returns -ve errno or +ve port */
  static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port)
  {
  	unsigned long flags;
  	int ret = -EADDRINUSE;
  	u16 rover, last;
  
  	if (*port != 0) {
  		rover = be16_to_cpu(*port);
  		last = rover;
  	} else {
  		rover = max_t(u16, net_random(), 2);
  		last = rover - 1;
  	}
38a4e5e61   Chris Mason   rds: Use RCU for ...
120
  	spin_lock_irqsave(&rds_bind_lock, flags);
639b321b4   Andy Grover   RDS: Socket inter...
121
122
123
124
  
  	do {
  		if (rover == 0)
  			rover++;
38a4e5e61   Chris Mason   rds: Use RCU for ...
125
126
  		if (!rds_bind_lookup(addr, cpu_to_be16(rover), rs)) {
  			*port = rs->rs_bound_port;
639b321b4   Andy Grover   RDS: Socket inter...
127
  			ret = 0;
38a4e5e61   Chris Mason   rds: Use RCU for ...
128
129
130
  			rdsdebug("rs %p binding to %pI4:%d
  ",
  			  rs, &addr, (int)ntohs(*port));
639b321b4   Andy Grover   RDS: Socket inter...
131
132
133
  			break;
  		}
  	} while (rover++ != last);
38a4e5e61   Chris Mason   rds: Use RCU for ...
134
  	spin_unlock_irqrestore(&rds_bind_lock, flags);
639b321b4   Andy Grover   RDS: Socket inter...
135
136
137
138
139
140
141
  
  	return ret;
  }
  
  void rds_remove_bound(struct rds_sock *rs)
  {
  	unsigned long flags;
38a4e5e61   Chris Mason   rds: Use RCU for ...
142
  	spin_lock_irqsave(&rds_bind_lock, flags);
639b321b4   Andy Grover   RDS: Socket inter...
143
144
145
146
147
148
  
  	if (rs->rs_bound_addr) {
  		rdsdebug("rs %p unbinding from %pI4:%d
  ",
  		  rs, &rs->rs_bound_addr,
  		  ntohs(rs->rs_bound_port));
38a4e5e61   Chris Mason   rds: Use RCU for ...
149
  		hlist_del_init_rcu(&rs->rs_bound_node);
639b321b4   Andy Grover   RDS: Socket inter...
150
151
152
  		rds_sock_put(rs);
  		rs->rs_bound_addr = 0;
  	}
38a4e5e61   Chris Mason   rds: Use RCU for ...
153
  	spin_unlock_irqrestore(&rds_bind_lock, flags);
639b321b4   Andy Grover   RDS: Socket inter...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  }
  
  int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
  {
  	struct sock *sk = sock->sk;
  	struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
  	struct rds_sock *rs = rds_sk_to_rs(sk);
  	struct rds_transport *trans;
  	int ret = 0;
  
  	lock_sock(sk);
  
  	if (addr_len != sizeof(struct sockaddr_in) ||
  	    sin->sin_family != AF_INET ||
  	    rs->rs_bound_addr ||
  	    sin->sin_addr.s_addr == htonl(INADDR_ANY)) {
  		ret = -EINVAL;
  		goto out;
  	}
  
  	ret = rds_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port);
  	if (ret)
  		goto out;
  
  	trans = rds_trans_get_preferred(sin->sin_addr.s_addr);
8690bfa17   Andy Grover   RDS: cleanup: rem...
179
  	if (!trans) {
639b321b4   Andy Grover   RDS: Socket inter...
180
181
  		ret = -EADDRNOTAVAIL;
  		rds_remove_bound(rs);
cb0a60564   Manuel Zerpies   net/rds: use prin...
182
  		printk_ratelimited(KERN_INFO "RDS: rds_bind() could not find a transport, "
f2c449320   Andy Grover   RDS: Add a debug ...
183
184
  				"load rds_tcp or rds_rdma?
  ");
639b321b4   Andy Grover   RDS: Socket inter...
185
186
187
188
189
190
191
192
  		goto out;
  	}
  
  	rs->rs_transport = trans;
  	ret = 0;
  
  out:
  	release_sock(sk);
38a4e5e61   Chris Mason   rds: Use RCU for ...
193
194
195
196
  
  	/* we might have called rds_remove_bound on error */
  	if (ret)
  		synchronize_rcu();
639b321b4   Andy Grover   RDS: Socket inter...
197
198
  	return ret;
  }