Blame view

fs/dlm/lowcomms.c 41.8 KB
fdda387f7   Patrick Caulfield   [DLM] Add support...
1
2
3
4
  /******************************************************************************
  *******************************************************************************
  **
  **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
5e9ccc372   Christine Caulfield   dlm: replace idr ...
5
  **  Copyright (C) 2004-2009 Red Hat, Inc.  All rights reserved.
fdda387f7   Patrick Caulfield   [DLM] Add support...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  **
  **  This copyrighted material is made available to anyone wishing to use,
  **  modify, copy, or redistribute it subject to the terms and conditions
  **  of the GNU General Public License v.2.
  **
  *******************************************************************************
  ******************************************************************************/
  
  /*
   * lowcomms.c
   *
   * This is the "low-level" comms layer.
   *
   * It is responsible for sending/receiving messages
   * from other nodes in the cluster.
   *
   * Cluster nodes are referred to by their nodeids. nodeids are
   * simply 32 bit numbers to the locking module - if they need to
2cf12c0bf   Joe Perches   dlm: comment typo...
24
   * be expanded for the cluster infrastructure then that is its
fdda387f7   Patrick Caulfield   [DLM] Add support...
25
26
27
28
29
30
31
32
33
34
35
36
37
38
   * responsibility. It is this layer's
   * responsibility to resolve these into IP address or
   * whatever it needs for inter-node communication.
   *
   * The comms level is two kernel threads that deal mainly with
   * the receiving of messages from other nodes and passing them
   * up to the mid-level comms layer (which understands the
   * message format) for execution by the locking core, and
   * a send thread which does all the setting up of connections
   * to remote nodes and the sending of data. Threads are not allowed
   * to send their own data because it may cause them to wait in times
   * of high load. Also, this way, the sending thread can collect together
   * messages bound for one node and send them in one block.
   *
2cf12c0bf   Joe Perches   dlm: comment typo...
39
   * lowcomms will choose to use either TCP or SCTP as its transport layer
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
40
   * depending on the configuration variable 'protocol'. This should be set
2cf12c0bf   Joe Perches   dlm: comment typo...
41
   * to 0 (default) for TCP or 1 for SCTP. It should be configured using a
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
42
43
   * cluster-wide mechanism as it must be the same on all nodes of the cluster
   * for the DLM to function.
fdda387f7   Patrick Caulfield   [DLM] Add support...
44
45
   *
   */
fdda387f7   Patrick Caulfield   [DLM] Add support...
46
47
48
49
  #include <asm/ioctls.h>
  #include <net/sock.h>
  #include <net/tcp.h>
  #include <linux/pagemap.h>
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
50
  #include <linux/file.h>
7a936ce71   Matthias Kaehlcke   dlm: convert conn...
51
  #include <linux/mutex.h>
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
52
  #include <linux/sctp.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
53
  #include <linux/slab.h>
2f2d76cc3   Benjamin Poirier   dlm: Do not alloc...
54
  #include <net/sctp/sctp.h>
44ad532b3   Joe Perches   dlm: use ipv6_add...
55
  #include <net/ipv6.h>
fdda387f7   Patrick Caulfield   [DLM] Add support...
56
57
58
59
60
  
  #include "dlm_internal.h"
  #include "lowcomms.h"
  #include "midcomms.h"
  #include "config.h"
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
61
  #define NEEDED_RMEM (4*1024*1024)
5e9ccc372   Christine Caulfield   dlm: replace idr ...
62
  #define CONN_HASH_SIZE 32
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
63

f92c8dd7a   Bob Peterson   dlm: reduce cond_...
64
65
  /* Number of messages to send before rescheduling */
  #define MAX_SEND_MSG_COUNT 25
fdda387f7   Patrick Caulfield   [DLM] Add support...
66
  struct cbuf {
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
67
68
69
  	unsigned int base;
  	unsigned int len;
  	unsigned int mask;
fdda387f7   Patrick Caulfield   [DLM] Add support...
70
  };
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
71
72
73
74
  static void cbuf_add(struct cbuf *cb, int n)
  {
  	cb->len += n;
  }
fdda387f7   Patrick Caulfield   [DLM] Add support...
75

ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  static int cbuf_data(struct cbuf *cb)
  {
  	return ((cb->base + cb->len) & cb->mask);
  }
  
  static void cbuf_init(struct cbuf *cb, int size)
  {
  	cb->base = cb->len = 0;
  	cb->mask = size-1;
  }
  
  static void cbuf_eat(struct cbuf *cb, int n)
  {
  	cb->len  -= n;
  	cb->base += n;
  	cb->base &= cb->mask;
  }
  
  static bool cbuf_empty(struct cbuf *cb)
  {
  	return cb->len == 0;
  }
fdda387f7   Patrick Caulfield   [DLM] Add support...
98

fdda387f7   Patrick Caulfield   [DLM] Add support...
99
100
101
  struct connection {
  	struct socket *sock;	/* NULL if not connected */
  	uint32_t nodeid;	/* So we know who we are in the list */
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
102
  	struct mutex sock_mutex;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
103
  	unsigned long flags;
fdda387f7   Patrick Caulfield   [DLM] Add support...
104
105
106
  #define CF_READ_PENDING 1
  #define CF_WRITE_PENDING 2
  #define CF_CONNECT_PENDING 3
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
107
108
  #define CF_INIT_PENDING 4
  #define CF_IS_OTHERCON 5
063c4c996   Lars Marowsky-Bree   dlm: fix connecti...
109
  #define CF_CLOSE 6
b36930dd5   David Miller   dlm: Handle appli...
110
  #define CF_APP_LIMITED 7
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
111
  	struct list_head writequeue;  /* List of outgoing writequeue_entries */
fdda387f7   Patrick Caulfield   [DLM] Add support...
112
113
  	spinlock_t writequeue_lock;
  	int (*rx_action) (struct connection *);	/* What to do when active */
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
114
  	void (*connect_action) (struct connection *);	/* What to do to connect */
fdda387f7   Patrick Caulfield   [DLM] Add support...
115
116
117
  	struct page *rx_page;
  	struct cbuf cb;
  	int retries;
fdda387f7   Patrick Caulfield   [DLM] Add support...
118
  #define MAX_CONNECT_RETRIES 3
5e9ccc372   Christine Caulfield   dlm: replace idr ...
119
  	struct hlist_node list;
fdda387f7   Patrick Caulfield   [DLM] Add support...
120
  	struct connection *othercon;
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
121
122
  	struct work_struct rwork; /* Receive workqueue */
  	struct work_struct swork; /* Send workqueue */
b81171cb6   Bob Peterson   DLM: Save and res...
123
124
125
126
  	void (*orig_error_report)(struct sock *);
  	void (*orig_data_ready)(struct sock *);
  	void (*orig_state_change)(struct sock *);
  	void (*orig_write_space)(struct sock *);
fdda387f7   Patrick Caulfield   [DLM] Add support...
127
128
129
130
131
132
133
134
135
136
137
138
139
  };
  #define sock2con(x) ((struct connection *)(x)->sk_user_data)
  
  /* An entry waiting to be sent */
  struct writequeue_entry {
  	struct list_head list;
  	struct page *page;
  	int offset;
  	int len;
  	int end;
  	int users;
  	struct connection *con;
  };
36b71a8bf   David Teigland   dlm: fix deadlock...
140
141
142
143
  struct dlm_node_addr {
  	struct list_head list;
  	int nodeid;
  	int addr_count;
98e1b60ec   Mike Christie   dlm: try other IP...
144
  	int curr_addr_index;
36b71a8bf   David Teigland   dlm: fix deadlock...
145
146
147
148
149
  	struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
  };
  
  static LIST_HEAD(dlm_node_addrs);
  static DEFINE_SPINLOCK(dlm_node_addrs_spin);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
150
151
  static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
  static int dlm_local_count;
513ef596d   David Teigland   dlm: prevent conn...
152
  static int dlm_allow_conn;
fdda387f7   Patrick Caulfield   [DLM] Add support...
153

1d6e8131c   Patrick Caulfield   [DLM] Use workque...
154
155
156
  /* Work queues */
  static struct workqueue_struct *recv_workqueue;
  static struct workqueue_struct *send_workqueue;
fdda387f7   Patrick Caulfield   [DLM] Add support...
157

5e9ccc372   Christine Caulfield   dlm: replace idr ...
158
  static struct hlist_head connection_hash[CONN_HASH_SIZE];
7a936ce71   Matthias Kaehlcke   dlm: convert conn...
159
  static DEFINE_MUTEX(connections_lock);
c80e7c83d   Patrick Caulfield   [DLM] fix compile...
160
  static struct kmem_cache *con_cache;
fdda387f7   Patrick Caulfield   [DLM] Add support...
161

1d6e8131c   Patrick Caulfield   [DLM] Use workque...
162
163
  static void process_recv_sockets(struct work_struct *work);
  static void process_send_sockets(struct work_struct *work);
fdda387f7   Patrick Caulfield   [DLM] Add support...
164

5e9ccc372   Christine Caulfield   dlm: replace idr ...
165
166
167
168
169
170
171
172
173
174
175
176
  
  /* This is deliberately very simple because most clusters have simple
     sequential nodeids, so we should be able to go straight to a connection
     struct in the array */
  static inline int nodeid_hash(int nodeid)
  {
  	return nodeid & (CONN_HASH_SIZE-1);
  }
  
  static struct connection *__find_con(int nodeid)
  {
  	int r;
5e9ccc372   Christine Caulfield   dlm: replace idr ...
177
178
179
  	struct connection *con;
  
  	r = nodeid_hash(nodeid);
b67bfe0d4   Sasha Levin   hlist: drop the n...
180
  	hlist_for_each_entry(con, &connection_hash[r], list) {
5e9ccc372   Christine Caulfield   dlm: replace idr ...
181
182
183
184
185
  		if (con->nodeid == nodeid)
  			return con;
  	}
  	return NULL;
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
186
187
188
189
190
  /*
   * If 'allocation' is zero then we don't attempt to create a new
   * connection structure for this node.
   */
  static struct connection *__nodeid2con(int nodeid, gfp_t alloc)
fdda387f7   Patrick Caulfield   [DLM] Add support...
191
192
  {
  	struct connection *con = NULL;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
193
  	int r;
fdda387f7   Patrick Caulfield   [DLM] Add support...
194

5e9ccc372   Christine Caulfield   dlm: replace idr ...
195
  	con = __find_con(nodeid);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
196
197
  	if (con || !alloc)
  		return con;
fdda387f7   Patrick Caulfield   [DLM] Add support...
198

6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
199
200
201
  	con = kmem_cache_zalloc(con_cache, alloc);
  	if (!con)
  		return NULL;
fdda387f7   Patrick Caulfield   [DLM] Add support...
202

5e9ccc372   Christine Caulfield   dlm: replace idr ...
203
204
  	r = nodeid_hash(nodeid);
  	hlist_add_head(&con->list, &connection_hash[r]);
fdda387f7   Patrick Caulfield   [DLM] Add support...
205

6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
206
207
208
209
210
211
  	con->nodeid = nodeid;
  	mutex_init(&con->sock_mutex);
  	INIT_LIST_HEAD(&con->writequeue);
  	spin_lock_init(&con->writequeue_lock);
  	INIT_WORK(&con->swork, process_send_sockets);
  	INIT_WORK(&con->rwork, process_recv_sockets);
fdda387f7   Patrick Caulfield   [DLM] Add support...
212

6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
213
214
  	/* Setup action pointers for child sockets */
  	if (con->nodeid) {
5e9ccc372   Christine Caulfield   dlm: replace idr ...
215
  		struct connection *zerocon = __find_con(0);
fdda387f7   Patrick Caulfield   [DLM] Add support...
216

6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
217
218
219
  		con->connect_action = zerocon->connect_action;
  		if (!con->rx_action)
  			con->rx_action = zerocon->rx_action;
fdda387f7   Patrick Caulfield   [DLM] Add support...
220
  	}
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
221
222
  	return con;
  }
5e9ccc372   Christine Caulfield   dlm: replace idr ...
223
224
225
226
  /* Loop round all connections */
  static void foreach_conn(void (*conn_func)(struct connection *c))
  {
  	int i;
b67bfe0d4   Sasha Levin   hlist: drop the n...
227
  	struct hlist_node *n;
5e9ccc372   Christine Caulfield   dlm: replace idr ...
228
229
230
  	struct connection *con;
  
  	for (i = 0; i < CONN_HASH_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
231
  		hlist_for_each_entry_safe(con, n, &connection_hash[i], list)
5e9ccc372   Christine Caulfield   dlm: replace idr ...
232
  			conn_func(con);
5e9ccc372   Christine Caulfield   dlm: replace idr ...
233
234
  	}
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
235
236
237
  static struct connection *nodeid2con(int nodeid, gfp_t allocation)
  {
  	struct connection *con;
7a936ce71   Matthias Kaehlcke   dlm: convert conn...
238
  	mutex_lock(&connections_lock);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
239
  	con = __nodeid2con(nodeid, allocation);
7a936ce71   Matthias Kaehlcke   dlm: convert conn...
240
  	mutex_unlock(&connections_lock);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
241

fdda387f7   Patrick Caulfield   [DLM] Add support...
242
243
  	return con;
  }
36b71a8bf   David Teigland   dlm: fix deadlock...
244
245
246
247
248
249
250
251
252
253
254
255
  static struct dlm_node_addr *find_node_addr(int nodeid)
  {
  	struct dlm_node_addr *na;
  
  	list_for_each_entry(na, &dlm_node_addrs, list) {
  		if (na->nodeid == nodeid)
  			return na;
  	}
  	return NULL;
  }
  
  static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
256
  {
36b71a8bf   David Teigland   dlm: fix deadlock...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  	switch (x->ss_family) {
  	case AF_INET: {
  		struct sockaddr_in *sinx = (struct sockaddr_in *)x;
  		struct sockaddr_in *siny = (struct sockaddr_in *)y;
  		if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr)
  			return 0;
  		if (sinx->sin_port != siny->sin_port)
  			return 0;
  		break;
  	}
  	case AF_INET6: {
  		struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x;
  		struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y;
  		if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr))
  			return 0;
  		if (sinx->sin6_port != siny->sin6_port)
  			return 0;
  		break;
  	}
  	default:
  		return 0;
  	}
  	return 1;
  }
  
  static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out,
98e1b60ec   Mike Christie   dlm: try other IP...
283
  			  struct sockaddr *sa_out, bool try_new_addr)
36b71a8bf   David Teigland   dlm: fix deadlock...
284
285
286
  {
  	struct sockaddr_storage sas;
  	struct dlm_node_addr *na;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
287
288
289
  
  	if (!dlm_local_count)
  		return -1;
36b71a8bf   David Teigland   dlm: fix deadlock...
290
291
  	spin_lock(&dlm_node_addrs_spin);
  	na = find_node_addr(nodeid);
98e1b60ec   Mike Christie   dlm: try other IP...
292
  	if (na && na->addr_count) {
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
293
294
  		memcpy(&sas, na->addr[na->curr_addr_index],
  		       sizeof(struct sockaddr_storage));
98e1b60ec   Mike Christie   dlm: try other IP...
295
296
297
298
299
  		if (try_new_addr) {
  			na->curr_addr_index++;
  			if (na->curr_addr_index == na->addr_count)
  				na->curr_addr_index = 0;
  		}
98e1b60ec   Mike Christie   dlm: try other IP...
300
  	}
36b71a8bf   David Teigland   dlm: fix deadlock...
301
302
303
304
305
306
307
308
309
310
311
312
313
  	spin_unlock(&dlm_node_addrs_spin);
  
  	if (!na)
  		return -EEXIST;
  
  	if (!na->addr_count)
  		return -ENOENT;
  
  	if (sas_out)
  		memcpy(sas_out, &sas, sizeof(struct sockaddr_storage));
  
  	if (!sa_out)
  		return 0;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
314
315
  
  	if (dlm_local_addr[0]->ss_family == AF_INET) {
36b71a8bf   David Teigland   dlm: fix deadlock...
316
317
  		struct sockaddr_in *in4  = (struct sockaddr_in *) &sas;
  		struct sockaddr_in *ret4 = (struct sockaddr_in *) sa_out;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
318
319
  		ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
  	} else {
36b71a8bf   David Teigland   dlm: fix deadlock...
320
321
  		struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &sas;
  		struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) sa_out;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
322
  		ret6->sin6_addr = in6->sin6_addr;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
323
324
325
326
  	}
  
  	return 0;
  }
36b71a8bf   David Teigland   dlm: fix deadlock...
327
328
329
330
  static int addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
  {
  	struct dlm_node_addr *na;
  	int rv = -EEXIST;
98e1b60ec   Mike Christie   dlm: try other IP...
331
  	int addr_i;
36b71a8bf   David Teigland   dlm: fix deadlock...
332
333
334
335
336
  
  	spin_lock(&dlm_node_addrs_spin);
  	list_for_each_entry(na, &dlm_node_addrs, list) {
  		if (!na->addr_count)
  			continue;
98e1b60ec   Mike Christie   dlm: try other IP...
337
338
339
340
341
342
343
  		for (addr_i = 0; addr_i < na->addr_count; addr_i++) {
  			if (addr_compare(na->addr[addr_i], addr)) {
  				*nodeid = na->nodeid;
  				rv = 0;
  				goto unlock;
  			}
  		}
36b71a8bf   David Teigland   dlm: fix deadlock...
344
  	}
98e1b60ec   Mike Christie   dlm: try other IP...
345
  unlock:
36b71a8bf   David Teigland   dlm: fix deadlock...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  	spin_unlock(&dlm_node_addrs_spin);
  	return rv;
  }
  
  int dlm_lowcomms_addr(int nodeid, struct sockaddr_storage *addr, int len)
  {
  	struct sockaddr_storage *new_addr;
  	struct dlm_node_addr *new_node, *na;
  
  	new_node = kzalloc(sizeof(struct dlm_node_addr), GFP_NOFS);
  	if (!new_node)
  		return -ENOMEM;
  
  	new_addr = kzalloc(sizeof(struct sockaddr_storage), GFP_NOFS);
  	if (!new_addr) {
  		kfree(new_node);
  		return -ENOMEM;
  	}
  
  	memcpy(new_addr, addr, len);
  
  	spin_lock(&dlm_node_addrs_spin);
  	na = find_node_addr(nodeid);
  	if (!na) {
  		new_node->nodeid = nodeid;
  		new_node->addr[0] = new_addr;
  		new_node->addr_count = 1;
  		list_add(&new_node->list, &dlm_node_addrs);
  		spin_unlock(&dlm_node_addrs_spin);
  		return 0;
  	}
  
  	if (na->addr_count >= DLM_MAX_ADDR_COUNT) {
  		spin_unlock(&dlm_node_addrs_spin);
  		kfree(new_addr);
  		kfree(new_node);
  		return -ENOSPC;
  	}
  
  	na->addr[na->addr_count++] = new_addr;
  	spin_unlock(&dlm_node_addrs_spin);
  	kfree(new_node);
  	return 0;
  }
fdda387f7   Patrick Caulfield   [DLM] Add support...
390
  /* Data available on socket or listen socket received a connect */
676d23690   David S. Miller   net: Fix use afte...
391
  static void lowcomms_data_ready(struct sock *sk)
fdda387f7   Patrick Caulfield   [DLM] Add support...
392
393
  {
  	struct connection *con = sock2con(sk);
afb853fb4   Patrick Caulfield   [DLM] fix socket ...
394
  	if (con && !test_and_set_bit(CF_READ_PENDING, &con->flags))
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
395
  		queue_work(recv_workqueue, &con->rwork);
fdda387f7   Patrick Caulfield   [DLM] Add support...
396
397
398
399
400
  }
  
  static void lowcomms_write_space(struct sock *sk)
  {
  	struct connection *con = sock2con(sk);
b36930dd5   David Miller   dlm: Handle appli...
401
402
403
404
405
406
407
  	if (!con)
  		return;
  
  	clear_bit(SOCK_NOSPACE, &con->sock->flags);
  
  	if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) {
  		con->sock->sk->sk_write_pending--;
9cd3e072b   Eric Dumazet   net: rename SOCK_...
408
  		clear_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags);
b36930dd5   David Miller   dlm: Handle appli...
409
410
411
  	}
  
  	if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
412
  		queue_work(send_workqueue, &con->swork);
fdda387f7   Patrick Caulfield   [DLM] Add support...
413
414
415
416
  }
  
  static inline void lowcomms_connect_sock(struct connection *con)
  {
063c4c996   Lars Marowsky-Bree   dlm: fix connecti...
417
418
  	if (test_bit(CF_CLOSE, &con->flags))
  		return;
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
419
420
  	if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
  		queue_work(send_workqueue, &con->swork);
fdda387f7   Patrick Caulfield   [DLM] Add support...
421
422
423
424
  }
  
  static void lowcomms_state_change(struct sock *sk)
  {
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
425
426
427
428
429
430
431
432
433
  	/* SCTP layer is not calling sk_data_ready when the connection
  	 * is done, so we catch the signal through here. Also, it
  	 * doesn't switch socket state when entering shutdown, so we
  	 * skip the write in that case.
  	 */
  	if (sk->sk_shutdown) {
  		if (sk->sk_shutdown == RCV_SHUTDOWN)
  			lowcomms_data_ready(sk);
  	} else if (sk->sk_state == TCP_ESTABLISHED) {
fdda387f7   Patrick Caulfield   [DLM] Add support...
434
  		lowcomms_write_space(sk);
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
435
  	}
fdda387f7   Patrick Caulfield   [DLM] Add support...
436
  }
391fbdc5d   Christine Caulfield   dlm: connect to n...
437
438
439
440
441
442
443
444
445
446
447
448
449
  int dlm_lowcomms_connect_node(int nodeid)
  {
  	struct connection *con;
  
  	if (nodeid == dlm_our_nodeid())
  		return 0;
  
  	con = nodeid2con(nodeid, GFP_NOFS);
  	if (!con)
  		return -ENOMEM;
  	lowcomms_connect_sock(con);
  	return 0;
  }
b3a5bbfd7   Bob Peterson   dlm: print error ...
450
451
  static void lowcomms_error_report(struct sock *sk)
  {
b81171cb6   Bob Peterson   DLM: Save and res...
452
  	struct connection *con;
b3a5bbfd7   Bob Peterson   dlm: print error ...
453
  	struct sockaddr_storage saddr;
1a31833d0   Bob Peterson   DLM: Replace node...
454
  	int buflen;
b81171cb6   Bob Peterson   DLM: Save and res...
455
  	void (*orig_report)(struct sock *) = NULL;
b3a5bbfd7   Bob Peterson   dlm: print error ...
456

b81171cb6   Bob Peterson   DLM: Save and res...
457
458
459
460
461
462
  	read_lock_bh(&sk->sk_callback_lock);
  	con = sock2con(sk);
  	if (con == NULL)
  		goto out;
  
  	orig_report = con->orig_error_report;
1a31833d0   Bob Peterson   DLM: Replace node...
463
464
  	if (con->sock == NULL ||
  	    kernel_getpeername(con->sock, (struct sockaddr *)&saddr, &buflen)) {
b3a5bbfd7   Bob Peterson   dlm: print error ...
465
466
467
468
469
470
  		printk_ratelimited(KERN_ERR "dlm: node %d: socket error "
  				   "sending to node %d, port %d, "
  				   "sk_err=%d/%d
  ", dlm_our_nodeid(),
  				   con->nodeid, dlm_config.ci_tcp_port,
  				   sk->sk_err, sk->sk_err_soft);
b3a5bbfd7   Bob Peterson   dlm: print error ...
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
  	} else if (saddr.ss_family == AF_INET) {
  		struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr;
  
  		printk_ratelimited(KERN_ERR "dlm: node %d: socket error "
  				   "sending to node %d at %pI4, port %d, "
  				   "sk_err=%d/%d
  ", dlm_our_nodeid(),
  				   con->nodeid, &sin4->sin_addr.s_addr,
  				   dlm_config.ci_tcp_port, sk->sk_err,
  				   sk->sk_err_soft);
  	} else {
  		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&saddr;
  
  		printk_ratelimited(KERN_ERR "dlm: node %d: socket error "
  				   "sending to node %d at %u.%u.%u.%u, "
  				   "port %d, sk_err=%d/%d
  ", dlm_our_nodeid(),
  				   con->nodeid, sin6->sin6_addr.s6_addr32[0],
  				   sin6->sin6_addr.s6_addr32[1],
  				   sin6->sin6_addr.s6_addr32[2],
  				   sin6->sin6_addr.s6_addr32[3],
  				   dlm_config.ci_tcp_port, sk->sk_err,
  				   sk->sk_err_soft);
  	}
b81171cb6   Bob Peterson   DLM: Save and res...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  out:
  	read_unlock_bh(&sk->sk_callback_lock);
  	if (orig_report)
  		orig_report(sk);
  }
  
  /* Note: sk_callback_lock must be locked before calling this function. */
  static void save_callbacks(struct connection *con, struct sock *sk)
  {
  	lock_sock(sk);
  	con->orig_data_ready = sk->sk_data_ready;
  	con->orig_state_change = sk->sk_state_change;
  	con->orig_write_space = sk->sk_write_space;
  	con->orig_error_report = sk->sk_error_report;
  	release_sock(sk);
  }
  
  static void restore_callbacks(struct connection *con, struct sock *sk)
  {
  	write_lock_bh(&sk->sk_callback_lock);
  	lock_sock(sk);
  	sk->sk_user_data = NULL;
  	sk->sk_data_ready = con->orig_data_ready;
  	sk->sk_state_change = con->orig_state_change;
  	sk->sk_write_space = con->orig_write_space;
  	sk->sk_error_report = con->orig_error_report;
  	release_sock(sk);
  	write_unlock_bh(&sk->sk_callback_lock);
b3a5bbfd7   Bob Peterson   dlm: print error ...
523
  }
fdda387f7   Patrick Caulfield   [DLM] Add support...
524
  /* Make a socket active */
4dd40f0cd   Ying Xue   dlm: convert add_...
525
  static void add_sock(struct socket *sock, struct connection *con)
fdda387f7   Patrick Caulfield   [DLM] Add support...
526
  {
b81171cb6   Bob Peterson   DLM: Save and res...
527
528
529
  	struct sock *sk = sock->sk;
  
  	write_lock_bh(&sk->sk_callback_lock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
530
  	con->sock = sock;
b81171cb6   Bob Peterson   DLM: Save and res...
531
532
533
  	sk->sk_user_data = con;
  	if (!test_bit(CF_IS_OTHERCON, &con->flags))
  		save_callbacks(con, sk);
fdda387f7   Patrick Caulfield   [DLM] Add support...
534
  	/* Install a data_ready callback */
b81171cb6   Bob Peterson   DLM: Save and res...
535
536
537
538
539
540
  	sk->sk_data_ready = lowcomms_data_ready;
  	sk->sk_write_space = lowcomms_write_space;
  	sk->sk_state_change = lowcomms_state_change;
  	sk->sk_allocation = GFP_NOFS;
  	sk->sk_error_report = lowcomms_error_report;
  	write_unlock_bh(&sk->sk_callback_lock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
541
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
542
  /* Add the port number to an IPv6 or 4 sockaddr and return the address
fdda387f7   Patrick Caulfield   [DLM] Add support...
543
544
545
546
     length */
  static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
  			  int *addr_len)
  {
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
547
  	saddr->ss_family =  dlm_local_addr[0]->ss_family;
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
548
  	if (saddr->ss_family == AF_INET) {
fdda387f7   Patrick Caulfield   [DLM] Add support...
549
550
551
  		struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
  		in4_addr->sin_port = cpu_to_be16(port);
  		*addr_len = sizeof(struct sockaddr_in);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
552
  		memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
553
  	} else {
fdda387f7   Patrick Caulfield   [DLM] Add support...
554
555
556
557
  		struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
  		in6_addr->sin6_port = cpu_to_be16(port);
  		*addr_len = sizeof(struct sockaddr_in6);
  	}
01c8cab25   Patrick Caulfield   [DLM] zero unused...
558
  	memset((char *)saddr + *addr_len, 0, sizeof(struct sockaddr_storage) - *addr_len);
fdda387f7   Patrick Caulfield   [DLM] Add support...
559
560
561
  }
  
  /* Close a remote connection and tidy up */
0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
562
563
  static void close_connection(struct connection *con, bool and_other,
  			     bool tx, bool rx)
fdda387f7   Patrick Caulfield   [DLM] Add support...
564
  {
0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
565
566
567
568
569
570
  	clear_bit(CF_CONNECT_PENDING, &con->flags);
  	clear_bit(CF_WRITE_PENDING, &con->flags);
  	if (tx && cancel_work_sync(&con->swork))
  		log_print("canceled swork for node %d", con->nodeid);
  	if (rx && cancel_work_sync(&con->rwork))
  		log_print("canceled rwork for node %d", con->nodeid);
fdda387f7   Patrick Caulfield   [DLM] Add support...
571

0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
572
  	mutex_lock(&con->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
573
  	if (con->sock) {
b81171cb6   Bob Peterson   DLM: Save and res...
574
575
  		if (!test_bit(CF_IS_OTHERCON, &con->flags))
  			restore_callbacks(con, con->sock->sk);
fdda387f7   Patrick Caulfield   [DLM] Add support...
576
577
578
579
  		sock_release(con->sock);
  		con->sock = NULL;
  	}
  	if (con->othercon && and_other) {
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
580
  		/* Will only re-enter once. */
0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
581
  		close_connection(con->othercon, false, true, true);
fdda387f7   Patrick Caulfield   [DLM] Add support...
582
583
584
585
586
  	}
  	if (con->rx_page) {
  		__free_page(con->rx_page);
  		con->rx_page = NULL;
  	}
9e5f2825a   Patrick Caulfield   [DLM] More otherc...
587

61d96be0f   Patrick Caulfield   [DLM] Fix lowcomm...
588
589
  	con->retries = 0;
  	mutex_unlock(&con->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
590
591
592
593
594
595
  }
  
  /* Data received from remote end */
  static int receive_from_sock(struct connection *con)
  {
  	int ret = 0;
58addbffd   Al Viro   [PATCH] dlm: use ...
596
597
  	struct msghdr msg = {};
  	struct kvec iov[2];
fdda387f7   Patrick Caulfield   [DLM] Add support...
598
599
600
  	unsigned len;
  	int r;
  	int call_again_soon = 0;
58addbffd   Al Viro   [PATCH] dlm: use ...
601
  	int nvec;
fdda387f7   Patrick Caulfield   [DLM] Add support...
602

f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
603
  	mutex_lock(&con->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
604

a34fbc636   Patrick Caulfield   [DLM] fix softloc...
605
606
607
608
  	if (con->sock == NULL) {
  		ret = -EAGAIN;
  		goto out_close;
  	}
acee4e527   Marcelo Ricardo Leitner   dlm: replace BUG_...
609
610
611
612
  	if (con->nodeid == 0) {
  		ret = -EINVAL;
  		goto out_close;
  	}
a34fbc636   Patrick Caulfield   [DLM] fix softloc...
613

fdda387f7   Patrick Caulfield   [DLM] Add support...
614
615
616
617
618
619
620
621
  	if (con->rx_page == NULL) {
  		/*
  		 * This doesn't need to be atomic, but I think it should
  		 * improve performance if it is.
  		 */
  		con->rx_page = alloc_page(GFP_ATOMIC);
  		if (con->rx_page == NULL)
  			goto out_resched;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
622
  		cbuf_init(&con->cb, PAGE_SIZE);
fdda387f7   Patrick Caulfield   [DLM] Add support...
623
  	}
fdda387f7   Patrick Caulfield   [DLM] Add support...
624
625
626
627
  	/*
  	 * iov[0] is the bit of the circular buffer between the current end
  	 * point (cb.base + cb.len) and the end of the buffer.
  	 */
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
628
629
  	iov[0].iov_len = con->cb.base - cbuf_data(&con->cb);
  	iov[0].iov_base = page_address(con->rx_page) + cbuf_data(&con->cb);
89adc934f   Patrick Caulfield   [DLM] Fix uniniti...
630
  	iov[1].iov_len = 0;
58addbffd   Al Viro   [PATCH] dlm: use ...
631
  	nvec = 1;
fdda387f7   Patrick Caulfield   [DLM] Add support...
632
633
634
635
636
  
  	/*
  	 * iov[1] is the bit of the circular buffer between the start of the
  	 * buffer and the start of the currently used section (cb.base)
  	 */
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
637
  	if (cbuf_data(&con->cb) >= con->cb.base) {
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
638
  		iov[0].iov_len = PAGE_SIZE - cbuf_data(&con->cb);
fdda387f7   Patrick Caulfield   [DLM] Add support...
639
640
  		iov[1].iov_len = con->cb.base;
  		iov[1].iov_base = page_address(con->rx_page);
58addbffd   Al Viro   [PATCH] dlm: use ...
641
  		nvec = 2;
fdda387f7   Patrick Caulfield   [DLM] Add support...
642
643
  	}
  	len = iov[0].iov_len + iov[1].iov_len;
58addbffd   Al Viro   [PATCH] dlm: use ...
644
  	r = ret = kernel_recvmsg(con->sock, &msg, iov, nvec, len,
fdda387f7   Patrick Caulfield   [DLM] Add support...
645
  			       MSG_DONTWAIT | MSG_NOSIGNAL);
fdda387f7   Patrick Caulfield   [DLM] Add support...
646
647
  	if (ret <= 0)
  		goto out_close;
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
648
649
  	else if (ret == len)
  		call_again_soon = 1;
bd44e2b00   Patrick Caulfield   [DLM] fix lowcomm...
650

ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
651
  	cbuf_add(&con->cb, ret);
fdda387f7   Patrick Caulfield   [DLM] Add support...
652
653
654
  	ret = dlm_process_incoming_buffer(con->nodeid,
  					  page_address(con->rx_page),
  					  con->cb.base, con->cb.len,
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
655
  					  PAGE_SIZE);
fdda387f7   Patrick Caulfield   [DLM] Add support...
656
  	if (ret == -EBADMSG) {
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
657
658
659
  		log_print("lowcomms: addr=%p, base=%u, len=%u, read=%d",
  			  page_address(con->rx_page), con->cb.base,
  			  con->cb.len, r);
fdda387f7   Patrick Caulfield   [DLM] Add support...
660
661
662
  	}
  	if (ret < 0)
  		goto out_close;
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
663
  	cbuf_eat(&con->cb, ret);
fdda387f7   Patrick Caulfield   [DLM] Add support...
664

ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
665
  	if (cbuf_empty(&con->cb) && !call_again_soon) {
fdda387f7   Patrick Caulfield   [DLM] Add support...
666
667
668
  		__free_page(con->rx_page);
  		con->rx_page = NULL;
  	}
fdda387f7   Patrick Caulfield   [DLM] Add support...
669
670
  	if (call_again_soon)
  		goto out_resched;
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
671
  	mutex_unlock(&con->sock_mutex);
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
672
  	return 0;
fdda387f7   Patrick Caulfield   [DLM] Add support...
673

ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
674
  out_resched:
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
675
676
  	if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
  		queue_work(recv_workqueue, &con->rwork);
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
677
  	mutex_unlock(&con->sock_mutex);
bd44e2b00   Patrick Caulfield   [DLM] fix lowcomm...
678
  	return -EAGAIN;
fdda387f7   Patrick Caulfield   [DLM] Add support...
679

ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
680
  out_close:
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
681
  	mutex_unlock(&con->sock_mutex);
9e5f2825a   Patrick Caulfield   [DLM] More otherc...
682
  	if (ret != -EAGAIN) {
0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
683
  		close_connection(con, false, true, false);
fdda387f7   Patrick Caulfield   [DLM] Add support...
684
685
  		/* Reconnect when there is something to send */
  	}
a34fbc636   Patrick Caulfield   [DLM] fix softloc...
686
687
688
  	/* Don't return success if we really got EOF */
  	if (ret == 0)
  		ret = -EAGAIN;
fdda387f7   Patrick Caulfield   [DLM] Add support...
689

fdda387f7   Patrick Caulfield   [DLM] Add support...
690
691
692
693
  	return ret;
  }
  
  /* Listening socket is busy, accept a connection */
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
694
  static int tcp_accept_from_sock(struct connection *con)
fdda387f7   Patrick Caulfield   [DLM] Add support...
695
696
697
698
699
700
701
  {
  	int result;
  	struct sockaddr_storage peeraddr;
  	struct socket *newsock;
  	int len;
  	int nodeid;
  	struct connection *newcon;
bd44e2b00   Patrick Caulfield   [DLM] fix lowcomm...
702
  	struct connection *addcon;
fdda387f7   Patrick Caulfield   [DLM] Add support...
703

513ef596d   David Teigland   dlm: prevent conn...
704
705
706
707
708
709
  	mutex_lock(&connections_lock);
  	if (!dlm_allow_conn) {
  		mutex_unlock(&connections_lock);
  		return -1;
  	}
  	mutex_unlock(&connections_lock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
710
  	memset(&peeraddr, 0, sizeof(peeraddr));
eeb1bd5c4   Eric W. Biederman   net: Add a struct...
711
712
  	result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
  				  SOCK_STREAM, IPPROTO_TCP, &newsock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
713
714
  	if (result < 0)
  		return -ENOMEM;
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
715
  	mutex_lock_nested(&con->sock_mutex, 0);
fdda387f7   Patrick Caulfield   [DLM] Add support...
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  
  	result = -ENOTCONN;
  	if (con->sock == NULL)
  		goto accept_err;
  
  	newsock->type = con->sock->type;
  	newsock->ops = con->sock->ops;
  
  	result = con->sock->ops->accept(con->sock, newsock, O_NONBLOCK);
  	if (result < 0)
  		goto accept_err;
  
  	/* Get the connected socket's peer */
  	memset(&peeraddr, 0, sizeof(peeraddr));
  	if (newsock->ops->getname(newsock, (struct sockaddr *)&peeraddr,
  				  &len, 2)) {
  		result = -ECONNABORTED;
  		goto accept_err;
  	}
  
  	/* Get the new node's NODEID */
  	make_sockaddr(&peeraddr, 0, &len);
36b71a8bf   David Teigland   dlm: fix deadlock...
738
  	if (addr_to_nodeid(&peeraddr, &nodeid)) {
bcaadf5c1   Masatake YAMATO   dlm: dump address...
739
  		unsigned char *b=(unsigned char *)&peeraddr;
617e82e10   David Teigland   [DLM] lowcomms style
740
  		log_print("connect from non cluster node");
bcaadf5c1   Masatake YAMATO   dlm: dump address...
741
742
  		print_hex_dump_bytes("ss: ", DUMP_PREFIX_NONE, 
  				     b, sizeof(struct sockaddr_storage));
fdda387f7   Patrick Caulfield   [DLM] Add support...
743
  		sock_release(newsock);
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
744
  		mutex_unlock(&con->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
745
746
747
748
749
750
751
752
  		return -1;
  	}
  
  	log_print("got connection from %d", nodeid);
  
  	/*  Check to see if we already have a connection to this node. This
  	 *  could happen if the two nodes initiate a connection at roughly
  	 *  the same time and the connections cross on the wire.
fdda387f7   Patrick Caulfield   [DLM] Add support...
753
754
  	 *  In this case we store the incoming one in "othercon"
  	 */
748285ccf   David Teigland   dlm: use more NOF...
755
  	newcon = nodeid2con(nodeid, GFP_NOFS);
fdda387f7   Patrick Caulfield   [DLM] Add support...
756
757
758
759
  	if (!newcon) {
  		result = -ENOMEM;
  		goto accept_err;
  	}
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
760
  	mutex_lock_nested(&newcon->sock_mutex, 1);
fdda387f7   Patrick Caulfield   [DLM] Add support...
761
  	if (newcon->sock) {
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
762
  		struct connection *othercon = newcon->othercon;
fdda387f7   Patrick Caulfield   [DLM] Add support...
763
764
  
  		if (!othercon) {
748285ccf   David Teigland   dlm: use more NOF...
765
  			othercon = kmem_cache_zalloc(con_cache, GFP_NOFS);
fdda387f7   Patrick Caulfield   [DLM] Add support...
766
  			if (!othercon) {
617e82e10   David Teigland   [DLM] lowcomms style
767
  				log_print("failed to allocate incoming socket");
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
768
  				mutex_unlock(&newcon->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
769
770
771
  				result = -ENOMEM;
  				goto accept_err;
  			}
fdda387f7   Patrick Caulfield   [DLM] Add support...
772
773
  			othercon->nodeid = nodeid;
  			othercon->rx_action = receive_from_sock;
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
774
  			mutex_init(&othercon->sock_mutex);
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
775
776
  			INIT_WORK(&othercon->swork, process_send_sockets);
  			INIT_WORK(&othercon->rwork, process_recv_sockets);
fdda387f7   Patrick Caulfield   [DLM] Add support...
777
  			set_bit(CF_IS_OTHERCON, &othercon->flags);
61d96be0f   Patrick Caulfield   [DLM] Fix lowcomm...
778
779
  		}
  		if (!othercon->sock) {
fdda387f7   Patrick Caulfield   [DLM] Add support...
780
  			newcon->othercon = othercon;
97d848365   Patrick Caulfield   [DLM] Telnet to p...
781
782
783
784
785
786
787
788
789
  			othercon->sock = newsock;
  			newsock->sk->sk_user_data = othercon;
  			add_sock(newsock, othercon);
  			addcon = othercon;
  		}
  		else {
  			printk("Extra connection from node %d attempted
  ", nodeid);
  			result = -EAGAIN;
f4fadb23c   akpm@linux-foundation.org   [GFS2] git-gfs2-n...
790
  			mutex_unlock(&newcon->sock_mutex);
97d848365   Patrick Caulfield   [DLM] Telnet to p...
791
  			goto accept_err;
fdda387f7   Patrick Caulfield   [DLM] Add support...
792
  		}
fdda387f7   Patrick Caulfield   [DLM] Add support...
793
794
795
796
797
  	}
  	else {
  		newsock->sk->sk_user_data = newcon;
  		newcon->rx_action = receive_from_sock;
  		add_sock(newsock, newcon);
bd44e2b00   Patrick Caulfield   [DLM] fix lowcomm...
798
  		addcon = newcon;
fdda387f7   Patrick Caulfield   [DLM] Add support...
799
  	}
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
800
  	mutex_unlock(&newcon->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
801
802
803
  
  	/*
  	 * Add it to the active queue in case we got data
25985edce   Lucas De Marchi   Fix common misspe...
804
  	 * between processing the accept adding the socket
fdda387f7   Patrick Caulfield   [DLM] Add support...
805
806
  	 * to the read_sockets list
  	 */
bd44e2b00   Patrick Caulfield   [DLM] fix lowcomm...
807
808
  	if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags))
  		queue_work(recv_workqueue, &addcon->rwork);
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
809
  	mutex_unlock(&con->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
810
811
  
  	return 0;
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
812
  accept_err:
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
813
  	mutex_unlock(&con->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
814
815
816
  	sock_release(newsock);
  
  	if (result != -EAGAIN)
617e82e10   David Teigland   [DLM] lowcomms style
817
  		log_print("error accepting connection from node: %d", result);
fdda387f7   Patrick Caulfield   [DLM] Add support...
818
819
  	return result;
  }
18df8a87b   kbuild test robot   dlm: sctp_accept_...
820
  static int sctp_accept_from_sock(struct connection *con)
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  {
  	/* Check that the new node is in the lockspace */
  	struct sctp_prim prim;
  	int nodeid;
  	int prim_len, ret;
  	int addr_len;
  	struct connection *newcon;
  	struct connection *addcon;
  	struct socket *newsock;
  
  	mutex_lock(&connections_lock);
  	if (!dlm_allow_conn) {
  		mutex_unlock(&connections_lock);
  		return -1;
  	}
  	mutex_unlock(&connections_lock);
  
  	mutex_lock_nested(&con->sock_mutex, 0);
  
  	ret = kernel_accept(con->sock, &newsock, O_NONBLOCK);
  	if (ret < 0)
  		goto accept_err;
  
  	memset(&prim, 0, sizeof(struct sctp_prim));
  	prim_len = sizeof(struct sctp_prim);
  
  	ret = kernel_getsockopt(newsock, IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
  				(char *)&prim, &prim_len);
  	if (ret < 0) {
  		log_print("getsockopt/sctp_primary_addr failed: %d", ret);
  		goto accept_err;
  	}
  
  	make_sockaddr(&prim.ssp_addr, 0, &addr_len);
  	if (addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
  		unsigned char *b = (unsigned char *)&prim.ssp_addr;
  
  		log_print("reject connect from unknown addr");
  		print_hex_dump_bytes("ss: ", DUMP_PREFIX_NONE,
  				     b, sizeof(struct sockaddr_storage));
  		goto accept_err;
  	}
  
  	newcon = nodeid2con(nodeid, GFP_NOFS);
  	if (!newcon) {
  		ret = -ENOMEM;
  		goto accept_err;
  	}
  
  	mutex_lock_nested(&newcon->sock_mutex, 1);
  
  	if (newcon->sock) {
  		struct connection *othercon = newcon->othercon;
  
  		if (!othercon) {
  			othercon = kmem_cache_zalloc(con_cache, GFP_NOFS);
  			if (!othercon) {
  				log_print("failed to allocate incoming socket");
  				mutex_unlock(&newcon->sock_mutex);
  				ret = -ENOMEM;
  				goto accept_err;
  			}
  			othercon->nodeid = nodeid;
  			othercon->rx_action = receive_from_sock;
  			mutex_init(&othercon->sock_mutex);
  			INIT_WORK(&othercon->swork, process_send_sockets);
  			INIT_WORK(&othercon->rwork, process_recv_sockets);
  			set_bit(CF_IS_OTHERCON, &othercon->flags);
  		}
  		if (!othercon->sock) {
  			newcon->othercon = othercon;
  			othercon->sock = newsock;
  			newsock->sk->sk_user_data = othercon;
  			add_sock(newsock, othercon);
  			addcon = othercon;
  		} else {
  			printk("Extra connection from node %d attempted
  ", nodeid);
  			ret = -EAGAIN;
  			mutex_unlock(&newcon->sock_mutex);
  			goto accept_err;
  		}
  	} else {
  		newsock->sk->sk_user_data = newcon;
  		newcon->rx_action = receive_from_sock;
  		add_sock(newsock, newcon);
  		addcon = newcon;
  	}
  
  	log_print("connected to %d", nodeid);
  
  	mutex_unlock(&newcon->sock_mutex);
  
  	/*
  	 * Add it to the active queue in case we got data
  	 * between processing the accept adding the socket
  	 * to the read_sockets list
  	 */
  	if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags))
  		queue_work(recv_workqueue, &addcon->rwork);
  	mutex_unlock(&con->sock_mutex);
  
  	return 0;
  
  accept_err:
  	mutex_unlock(&con->sock_mutex);
  	if (newsock)
  		sock_release(newsock);
  	if (ret != -EAGAIN)
  		log_print("error accepting connection from node: %d", ret);
  
  	return ret;
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
934
935
936
937
938
  static void free_entry(struct writequeue_entry *e)
  {
  	__free_page(e->page);
  	kfree(e);
  }
5d6898714   Mike Christie   dlm: retry failed...
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
  /*
   * writequeue_entry_complete - try to delete and free write queue entry
   * @e: write queue entry to try to delete
   * @completed: bytes completed
   *
   * writequeue_lock must be held.
   */
  static void writequeue_entry_complete(struct writequeue_entry *e, int completed)
  {
  	e->offset += completed;
  	e->len -= completed;
  
  	if (e->len == 0 && e->users == 0) {
  		list_del(&e->list);
  		free_entry(e);
  	}
  }
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
  /*
   * sctp_bind_addrs - bind a SCTP socket to all our addresses
   */
  static int sctp_bind_addrs(struct connection *con, uint16_t port)
  {
  	struct sockaddr_storage localaddr;
  	int i, addr_len, result = 0;
  
  	for (i = 0; i < dlm_local_count; i++) {
  		memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
  		make_sockaddr(&localaddr, port, &addr_len);
  
  		if (!i)
  			result = kernel_bind(con->sock,
  					     (struct sockaddr *)&localaddr,
  					     addr_len);
  		else
  			result = kernel_setsockopt(con->sock, SOL_SCTP,
  						   SCTP_SOCKOPT_BINDX_ADD,
  						   (char *)&localaddr, addr_len);
  
  		if (result < 0) {
  			log_print("Can't bind to %d addr number %d, %d.
  ",
  				  port, i + 1, result);
  			break;
  		}
  	}
  	return result;
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
986
987
988
989
990
  /* Initiate an SCTP association.
     This is a special case of send_to_sock() in that we don't yet have a
     peeled-off socket for this association, so we use the listening socket
     and add the primary IP address of the remote node.
   */
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
991
  static void sctp_connect_to_sock(struct connection *con)
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
992
  {
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
993
994
995
996
997
998
999
1000
1001
1002
  	struct sockaddr_storage daddr;
  	int one = 1;
  	int result;
  	int addr_len;
  	struct socket *sock;
  
  	if (con->nodeid == 0) {
  		log_print("attempt to connect sock 0 foiled");
  		return;
  	}
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1003

5d6898714   Mike Christie   dlm: retry failed...
1004
  	mutex_lock(&con->sock_mutex);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1005

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  	/* Some odd races can cause double-connects, ignore them */
  	if (con->retries++ > MAX_CONNECT_RETRIES)
  		goto out;
  
  	if (con->sock) {
  		log_print("node %d already connected.", con->nodeid);
  		goto out;
  	}
  
  	memset(&daddr, 0, sizeof(daddr));
  	result = nodeid_to_addr(con->nodeid, &daddr, NULL, true);
  	if (result < 0) {
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1018
  		log_print("no address for nodeid %d", con->nodeid);
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1019
  		goto out;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1020
  	}
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1021

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1022
1023
1024
1025
1026
  	/* Create a socket to communicate with */
  	result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
  				  SOCK_STREAM, IPPROTO_SCTP, &sock);
  	if (result < 0)
  		goto socket_err;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1027

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1028
1029
1030
1031
  	sock->sk->sk_user_data = con;
  	con->rx_action = receive_from_sock;
  	con->connect_action = sctp_connect_to_sock;
  	add_sock(sock, con);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1032

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1033
1034
1035
  	/* Bind to all addresses. */
  	if (sctp_bind_addrs(con, 0))
  		goto bind_err;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1036

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1037
  	make_sockaddr(&daddr, dlm_config.ci_tcp_port, &addr_len);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1038

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1039
  	log_print("connecting to %d", con->nodeid);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1040

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1041
1042
1043
  	/* Turn off Nagle's algorithm */
  	kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
  			  sizeof(one));
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1044

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1045
1046
1047
1048
1049
1050
  	result = sock->ops->connect(sock, (struct sockaddr *)&daddr, addr_len,
  				   O_NONBLOCK);
  	if (result == -EINPROGRESS)
  		result = 0;
  	if (result == 0)
  		goto out;
98e1b60ec   Mike Christie   dlm: try other IP...
1051

6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1052

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1053
1054
1055
  bind_err:
  	con->sock = NULL;
  	sock_release(sock);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1056

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
  socket_err:
  	/*
  	 * Some errors are fatal and this list might need adjusting. For other
  	 * errors we try again until the max number of retries is reached.
  	 */
  	if (result != -EHOSTUNREACH &&
  	    result != -ENETUNREACH &&
  	    result != -ENETDOWN &&
  	    result != -EINVAL &&
  	    result != -EPROTONOSUPPORT) {
  		log_print("connect %d try %d error %d", con->nodeid,
  			  con->retries, result);
  		mutex_unlock(&con->sock_mutex);
  		msleep(1000);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1071
  		clear_bit(CF_CONNECT_PENDING, &con->flags);
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1072
1073
  		lowcomms_connect_sock(con);
  		return;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1074
  	}
5d6898714   Mike Christie   dlm: retry failed...
1075

ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1076
  out:
5d6898714   Mike Christie   dlm: retry failed...
1077
  	mutex_unlock(&con->sock_mutex);
00dcffaeb   Marcelo Ricardo Leitner   dlm: fix reconnec...
1078
  	set_bit(CF_WRITE_PENDING, &con->flags);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1079
  }
fdda387f7   Patrick Caulfield   [DLM] Add support...
1080
  /* Connect a new socket to its peer */
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1081
  static void tcp_connect_to_sock(struct connection *con)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1082
  {
6bd8fedaa   Lon Hohberger   dlm: bind connect...
1083
  	struct sockaddr_storage saddr, src_addr;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1084
  	int addr_len;
a89d63a15   Casey Dahlin   dlm: free socket ...
1085
  	struct socket *sock = NULL;
cb2d45da8   David Teigland   dlm: use TCP_NODELAY
1086
  	int one = 1;
36b71a8bf   David Teigland   dlm: fix deadlock...
1087
  	int result;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1088
1089
1090
  
  	if (con->nodeid == 0) {
  		log_print("attempt to connect sock 0 foiled");
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1091
  		return;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1092
  	}
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
1093
  	mutex_lock(&con->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1094
1095
1096
1097
  	if (con->retries++ > MAX_CONNECT_RETRIES)
  		goto out;
  
  	/* Some odd races can cause double-connects, ignore them */
36b71a8bf   David Teigland   dlm: fix deadlock...
1098
  	if (con->sock)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1099
  		goto out;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1100
1101
  
  	/* Create a socket to communicate with */
eeb1bd5c4   Eric W. Biederman   net: Add a struct...
1102
1103
  	result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
  				  SOCK_STREAM, IPPROTO_TCP, &sock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1104
1105
1106
1107
  	if (result < 0)
  		goto out_err;
  
  	memset(&saddr, 0, sizeof(saddr));
98e1b60ec   Mike Christie   dlm: try other IP...
1108
  	result = nodeid_to_addr(con->nodeid, &saddr, NULL, false);
36b71a8bf   David Teigland   dlm: fix deadlock...
1109
1110
  	if (result < 0) {
  		log_print("no address for nodeid %d", con->nodeid);
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1111
  		goto out_err;
36b71a8bf   David Teigland   dlm: fix deadlock...
1112
  	}
fdda387f7   Patrick Caulfield   [DLM] Add support...
1113
1114
1115
  
  	sock->sk->sk_user_data = con;
  	con->rx_action = receive_from_sock;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1116
1117
  	con->connect_action = tcp_connect_to_sock;
  	add_sock(sock, con);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1118

6bd8fedaa   Lon Hohberger   dlm: bind connect...
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
  	/* Bind to our cluster-known address connecting to avoid
  	   routing problems */
  	memcpy(&src_addr, dlm_local_addr[0], sizeof(src_addr));
  	make_sockaddr(&src_addr, 0, &addr_len);
  	result = sock->ops->bind(sock, (struct sockaddr *) &src_addr,
  				 addr_len);
  	if (result < 0) {
  		log_print("could not bind for connect: %d", result);
  		/* This *may* not indicate a critical error */
  	}
68c817a1c   David Teigland   [DLM] rename dlm_...
1129
  	make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1130

fdda387f7   Patrick Caulfield   [DLM] Add support...
1131
  	log_print("connecting to %d", con->nodeid);
cb2d45da8   David Teigland   dlm: use TCP_NODELAY
1132
1133
1134
1135
  
  	/* Turn off Nagle's algorithm */
  	kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
  			  sizeof(one));
36b71a8bf   David Teigland   dlm: fix deadlock...
1136
  	result = sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1137
  				   O_NONBLOCK);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1138
1139
  	if (result == -EINPROGRESS)
  		result = 0;
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1140
1141
  	if (result == 0)
  		goto out;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1142

ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1143
  out_err:
fdda387f7   Patrick Caulfield   [DLM] Add support...
1144
1145
1146
  	if (con->sock) {
  		sock_release(con->sock);
  		con->sock = NULL;
a89d63a15   Casey Dahlin   dlm: free socket ...
1147
1148
  	} else if (sock) {
  		sock_release(sock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1149
1150
1151
1152
1153
  	}
  	/*
  	 * Some errors are fatal and this list might need adjusting. For other
  	 * errors we try again until the max number of retries is reached.
  	 */
36b71a8bf   David Teigland   dlm: fix deadlock...
1154
1155
1156
1157
1158
1159
1160
1161
1162
  	if (result != -EHOSTUNREACH &&
  	    result != -ENETUNREACH &&
  	    result != -ENETDOWN && 
  	    result != -EINVAL &&
  	    result != -EPROTONOSUPPORT) {
  		log_print("connect %d try %d error %d", con->nodeid,
  			  con->retries, result);
  		mutex_unlock(&con->sock_mutex);
  		msleep(1000);
356344c4c   Marcelo Ricardo Leitner   dlm: fix not reco...
1163
  		clear_bit(CF_CONNECT_PENDING, &con->flags);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1164
  		lowcomms_connect_sock(con);
36b71a8bf   David Teigland   dlm: fix deadlock...
1165
  		return;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1166
  	}
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1167
  out:
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
1168
  	mutex_unlock(&con->sock_mutex);
00dcffaeb   Marcelo Ricardo Leitner   dlm: fix reconnec...
1169
  	set_bit(CF_WRITE_PENDING, &con->flags);
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1170
  	return;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1171
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1172
1173
  static struct socket *tcp_create_listen_sock(struct connection *con,
  					     struct sockaddr_storage *saddr)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1174
  {
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1175
  	struct socket *sock = NULL;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1176
1177
1178
  	int result = 0;
  	int one = 1;
  	int addr_len;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1179
  	if (dlm_local_addr[0]->ss_family == AF_INET)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1180
1181
1182
1183
1184
  		addr_len = sizeof(struct sockaddr_in);
  	else
  		addr_len = sizeof(struct sockaddr_in6);
  
  	/* Create a socket to communicate with */
eeb1bd5c4   Eric W. Biederman   net: Add a struct...
1185
1186
  	result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
  				  SOCK_STREAM, IPPROTO_TCP, &sock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1187
  	if (result < 0) {
617e82e10   David Teigland   [DLM] lowcomms style
1188
  		log_print("Can't create listening comms socket");
fdda387f7   Patrick Caulfield   [DLM] Add support...
1189
1190
  		goto create_out;
  	}
cb2d45da8   David Teigland   dlm: use TCP_NODELAY
1191
1192
1193
  	/* Turn off Nagle's algorithm */
  	kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
  			  sizeof(one));
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1194
1195
  	result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
  				   (char *)&one, sizeof(one));
fdda387f7   Patrick Caulfield   [DLM] Add support...
1196
  	if (result < 0) {
617e82e10   David Teigland   [DLM] lowcomms style
1197
  		log_print("Failed to set SO_REUSEADDR on socket: %d", result);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1198
  	}
b81171cb6   Bob Peterson   DLM: Save and res...
1199
  	sock->sk->sk_user_data = con;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1200
1201
  	con->rx_action = tcp_accept_from_sock;
  	con->connect_action = tcp_connect_to_sock;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1202
1203
  
  	/* Bind to our port */
68c817a1c   David Teigland   [DLM] rename dlm_...
1204
  	make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1205
1206
  	result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);
  	if (result < 0) {
617e82e10   David Teigland   [DLM] lowcomms style
1207
  		log_print("Can't bind to port %d", dlm_config.ci_tcp_port);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1208
1209
1210
1211
1212
  		sock_release(sock);
  		sock = NULL;
  		con->sock = NULL;
  		goto create_out;
  	}
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1213
  	result = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1214
  				 (char *)&one, sizeof(one));
fdda387f7   Patrick Caulfield   [DLM] Add support...
1215
  	if (result < 0) {
617e82e10   David Teigland   [DLM] lowcomms style
1216
  		log_print("Set keepalive failed: %d", result);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1217
1218
1219
1220
  	}
  
  	result = sock->ops->listen(sock, 5);
  	if (result < 0) {
617e82e10   David Teigland   [DLM] lowcomms style
1221
  		log_print("Can't listen on port %d", dlm_config.ci_tcp_port);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1222
1223
1224
1225
  		sock_release(sock);
  		sock = NULL;
  		goto create_out;
  	}
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1226
  create_out:
fdda387f7   Patrick Caulfield   [DLM] Add support...
1227
1228
  	return sock;
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1229
1230
1231
1232
1233
  /* Get local addresses */
  static void init_local(void)
  {
  	struct sockaddr_storage sas, *addr;
  	int i;
30d3a2373   Patrick Caulfield   [DLM] Lowcomms no...
1234
  	dlm_local_count = 0;
1b189b888   David Teigland   dlm: last element...
1235
  	for (i = 0; i < DLM_MAX_ADDR_COUNT; i++) {
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1236
1237
  		if (dlm_our_addr(&sas, i))
  			break;
5c93f56f7   Amitoj Kaur Chawla   dlm: Use kmemdup ...
1238
  		addr = kmemdup(&sas, sizeof(*addr), GFP_NOFS);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1239
1240
  		if (!addr)
  			break;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1241
1242
1243
  		dlm_local_addr[dlm_local_count++] = addr;
  	}
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1244
1245
1246
1247
  /* Initialise SCTP socket and bind to all interfaces */
  static int sctp_listen_for_all(void)
  {
  	struct socket *sock = NULL;
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1248
  	int result = -EINVAL;
573c24c4a   David Teigland   dlm: always use G...
1249
  	struct connection *con = nodeid2con(0, GFP_NOFS);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1250
  	int bufsize = NEEDED_RMEM;
86e92ad29   Mike Christie   dlm: disable nagl...
1251
  	int one = 1;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1252
1253
1254
1255
1256
  
  	if (!con)
  		return -ENOMEM;
  
  	log_print("Using SCTP for communications");
eeb1bd5c4   Eric W. Biederman   net: Add a struct...
1257
  	result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1258
  				  SOCK_STREAM, IPPROTO_SCTP, &sock);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1259
1260
1261
1262
  	if (result < 0) {
  		log_print("Can't create comms socket, check SCTP is loaded");
  		goto out;
  	}
df61c9526   David S. Miller   [DLM] lowcomms: D...
1263
  	result = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE,
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1264
1265
  				 (char *)&bufsize, sizeof(bufsize));
  	if (result)
617e82e10   David Teigland   [DLM] lowcomms style
1266
  		log_print("Error increasing buffer space on socket %d", result);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1267

86e92ad29   Mike Christie   dlm: disable nagl...
1268
1269
1270
1271
1272
  	result = kernel_setsockopt(sock, SOL_SCTP, SCTP_NODELAY, (char *)&one,
  				   sizeof(one));
  	if (result < 0)
  		log_print("Could not set SCTP NODELAY error %d
  ", result);
b81171cb6   Bob Peterson   DLM: Save and res...
1273
  	write_lock_bh(&sock->sk->sk_callback_lock);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1274
1275
1276
1277
  	/* Init con struct */
  	sock->sk->sk_user_data = con;
  	con->sock = sock;
  	con->sock->sk->sk_data_ready = lowcomms_data_ready;
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1278
1279
  	con->rx_action = sctp_accept_from_sock;
  	con->connect_action = sctp_connect_to_sock;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1280

b81171cb6   Bob Peterson   DLM: Save and res...
1281
  	write_unlock_bh(&sock->sk->sk_callback_lock);
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1282
1283
1284
  	/* Bind to all addresses. */
  	if (sctp_bind_addrs(con, dlm_config.ci_tcp_port))
  		goto create_delsock;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
  
  	result = sock->ops->listen(sock, 5);
  	if (result < 0) {
  		log_print("Can't set socket listening");
  		goto create_delsock;
  	}
  
  	return 0;
  
  create_delsock:
  	sock_release(sock);
  	con->sock = NULL;
  out:
  	return result;
  }
  
  static int tcp_listen_for_all(void)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1302
1303
  {
  	struct socket *sock = NULL;
573c24c4a   David Teigland   dlm: always use G...
1304
  	struct connection *con = nodeid2con(0, GFP_NOFS);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1305
  	int result = -EINVAL;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1306
1307
  	if (!con)
  		return -ENOMEM;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1308
  	/* We don't support multi-homed hosts */
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1309
  	if (dlm_local_addr[1] != NULL) {
617e82e10   David Teigland   [DLM] lowcomms style
1310
1311
  		log_print("TCP protocol can't handle multi-homed hosts, "
  			  "try SCTP");
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1312
1313
1314
1315
  		return -EINVAL;
  	}
  
  	log_print("Using TCP for communications");
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1316
  	sock = tcp_create_listen_sock(con, dlm_local_addr[0]);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
  	if (sock) {
  		add_sock(sock, con);
  		result = 0;
  	}
  	else {
  		result = -EADDRINUSE;
  	}
  
  	return result;
  }
  
  
  
  static struct writequeue_entry *new_writequeue_entry(struct connection *con,
  						     gfp_t allocation)
  {
  	struct writequeue_entry *entry;
  
  	entry = kmalloc(sizeof(struct writequeue_entry), allocation);
  	if (!entry)
  		return NULL;
  
  	entry->page = alloc_page(allocation);
  	if (!entry->page) {
  		kfree(entry);
  		return NULL;
  	}
  
  	entry->offset = 0;
  	entry->len = 0;
  	entry->end = 0;
  	entry->users = 0;
  	entry->con = con;
  
  	return entry;
  }
617e82e10   David Teigland   [DLM] lowcomms style
1353
  void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1354
1355
1356
1357
  {
  	struct connection *con;
  	struct writequeue_entry *e;
  	int offset = 0;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1358

fdda387f7   Patrick Caulfield   [DLM] Add support...
1359
1360
1361
  	con = nodeid2con(nodeid, allocation);
  	if (!con)
  		return NULL;
4edde74ee   Patrick Caulfield   [DLM] Fix spin lo...
1362
  	spin_lock(&con->writequeue_lock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1363
  	e = list_entry(con->writequeue.prev, struct writequeue_entry, list);
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1364
  	if ((&e->list == &con->writequeue) ||
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
1365
  	    (PAGE_SIZE - e->end < len)) {
fdda387f7   Patrick Caulfield   [DLM] Add support...
1366
1367
1368
1369
  		e = NULL;
  	} else {
  		offset = e->end;
  		e->end += len;
eeee2b5fe   Wei Yongjun   dlm: remove unuse...
1370
  		e->users++;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1371
1372
1373
1374
  	}
  	spin_unlock(&con->writequeue_lock);
  
  	if (e) {
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1375
  	got_one:
fdda387f7   Patrick Caulfield   [DLM] Add support...
1376
1377
1378
1379
1380
1381
1382
1383
1384
  		*ppc = page_address(e->page) + offset;
  		return e;
  	}
  
  	e = new_writequeue_entry(con, allocation);
  	if (e) {
  		spin_lock(&con->writequeue_lock);
  		offset = e->end;
  		e->end += len;
eeee2b5fe   Wei Yongjun   dlm: remove unuse...
1385
  		e->users++;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
  		list_add_tail(&e->list, &con->writequeue);
  		spin_unlock(&con->writequeue_lock);
  		goto got_one;
  	}
  	return NULL;
  }
  
  void dlm_lowcomms_commit_buffer(void *mh)
  {
  	struct writequeue_entry *e = (struct writequeue_entry *)mh;
  	struct connection *con = e->con;
  	int users;
4edde74ee   Patrick Caulfield   [DLM] Fix spin lo...
1398
  	spin_lock(&con->writequeue_lock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1399
1400
1401
1402
  	users = --e->users;
  	if (users)
  		goto out;
  	e->len = e->end - e->offset;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1403
  	spin_unlock(&con->writequeue_lock);
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1404
1405
  	if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) {
  		queue_work(send_workqueue, &con->swork);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1406
1407
  	}
  	return;
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1408
  out:
fdda387f7   Patrick Caulfield   [DLM] Add support...
1409
1410
1411
  	spin_unlock(&con->writequeue_lock);
  	return;
  }
fdda387f7   Patrick Caulfield   [DLM] Add support...
1412
  /* Send a message */
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1413
  static void send_to_sock(struct connection *con)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1414
1415
  {
  	int ret = 0;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1416
1417
1418
  	const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL;
  	struct writequeue_entry *e;
  	int len, offset;
f92c8dd7a   Bob Peterson   dlm: reduce cond_...
1419
  	int count = 0;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1420

f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
1421
  	mutex_lock(&con->sock_mutex);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1422
1423
  	if (con->sock == NULL)
  		goto out_connect;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
  	spin_lock(&con->writequeue_lock);
  	for (;;) {
  		e = list_entry(con->writequeue.next, struct writequeue_entry,
  			       list);
  		if ((struct list_head *) e == &con->writequeue)
  			break;
  
  		len = e->len;
  		offset = e->offset;
  		BUG_ON(len == 0 && e->users == 0);
  		spin_unlock(&con->writequeue_lock);
  
  		ret = 0;
  		if (len) {
1329e3f2c   Paolo Bonzini   dlm: use kernel_s...
1438
1439
  			ret = kernel_sendpage(con->sock, e->page, offset, len,
  					      msg_flags);
d66f8277f   Patrick Caulfield   [DLM] Make dlm_se...
1440
  			if (ret == -EAGAIN || ret == 0) {
b36930dd5   David Miller   dlm: Handle appli...
1441
  				if (ret == -EAGAIN &&
9cd3e072b   Eric Dumazet   net: rename SOCK_...
1442
  				    test_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags) &&
b36930dd5   David Miller   dlm: Handle appli...
1443
1444
1445
1446
1447
1448
1449
  				    !test_and_set_bit(CF_APP_LIMITED, &con->flags)) {
  					/* Notify TCP that we're limited by the
  					 * application window size.
  					 */
  					set_bit(SOCK_NOSPACE, &con->sock->flags);
  					con->sock->sk->sk_write_pending++;
  				}
d66f8277f   Patrick Caulfield   [DLM] Make dlm_se...
1450
  				cond_resched();
fdda387f7   Patrick Caulfield   [DLM] Add support...
1451
  				goto out;
9c5bef584   Ying Xue   dlm: cleanup send...
1452
  			} else if (ret < 0)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1453
  				goto send_error;
d66f8277f   Patrick Caulfield   [DLM] Make dlm_se...
1454
  		}
f92c8dd7a   Bob Peterson   dlm: reduce cond_...
1455
1456
1457
  
  		/* Don't starve people filling buffers */
  		if (++count >= MAX_SEND_MSG_COUNT) {
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1458
  			cond_resched();
f92c8dd7a   Bob Peterson   dlm: reduce cond_...
1459
1460
  			count = 0;
  		}
fdda387f7   Patrick Caulfield   [DLM] Add support...
1461
1462
  
  		spin_lock(&con->writequeue_lock);
5d6898714   Mike Christie   dlm: retry failed...
1463
  		writequeue_entry_complete(e, ret);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1464
1465
  	}
  	spin_unlock(&con->writequeue_lock);
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1466
  out:
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
1467
  	mutex_unlock(&con->sock_mutex);
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1468
  	return;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1469

ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1470
  send_error:
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
1471
  	mutex_unlock(&con->sock_mutex);
0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
1472
  	close_connection(con, false, false, true);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1473
  	lowcomms_connect_sock(con);
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1474
  	return;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1475

ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1476
  out_connect:
f1f1c1ccf   Patrick Caulfield   [DLM] Make sock_s...
1477
  	mutex_unlock(&con->sock_mutex);
ee44b4bc0   Marcelo Ricardo Leitner   dlm: use sctp 1-t...
1478
  	lowcomms_connect_sock(con);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1479
1480
1481
1482
  }
  
  static void clean_one_writequeue(struct connection *con)
  {
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1483
  	struct writequeue_entry *e, *safe;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1484
1485
  
  	spin_lock(&con->writequeue_lock);
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1486
  	list_for_each_entry_safe(e, safe, &con->writequeue, list) {
fdda387f7   Patrick Caulfield   [DLM] Add support...
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
  		list_del(&e->list);
  		free_entry(e);
  	}
  	spin_unlock(&con->writequeue_lock);
  }
  
  /* Called from recovery when it knows that a node has
     left the cluster */
  int dlm_lowcomms_close(int nodeid)
  {
  	struct connection *con;
36b71a8bf   David Teigland   dlm: fix deadlock...
1498
  	struct dlm_node_addr *na;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1499

fdda387f7   Patrick Caulfield   [DLM] Add support...
1500
1501
1502
  	log_print("closing connection to node %d", nodeid);
  	con = nodeid2con(nodeid, 0);
  	if (con) {
063c4c996   Lars Marowsky-Bree   dlm: fix connecti...
1503
  		set_bit(CF_CLOSE, &con->flags);
0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
1504
  		close_connection(con, true, true, true);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1505
  		clean_one_writequeue(con);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1506
  	}
36b71a8bf   David Teigland   dlm: fix deadlock...
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
  
  	spin_lock(&dlm_node_addrs_spin);
  	na = find_node_addr(nodeid);
  	if (na) {
  		list_del(&na->list);
  		while (na->addr_count--)
  			kfree(na->addr[na->addr_count]);
  		kfree(na);
  	}
  	spin_unlock(&dlm_node_addrs_spin);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1517
  	return 0;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1518
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1519
  /* Receive workqueue function */
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1520
  static void process_recv_sockets(struct work_struct *work)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1521
  {
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1522
1523
  	struct connection *con = container_of(work, struct connection, rwork);
  	int err;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1524

1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1525
1526
1527
1528
  	clear_bit(CF_READ_PENDING, &con->flags);
  	do {
  		err = con->rx_action(con);
  	} while (!err);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1529
  }
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1530
  /* Send workqueue function */
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1531
  static void process_send_sockets(struct work_struct *work)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1532
  {
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1533
  	struct connection *con = container_of(work, struct connection, swork);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1534

00dcffaeb   Marcelo Ricardo Leitner   dlm: fix reconnec...
1535
  	if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags))
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1536
  		con->connect_action(con);
063c4c996   Lars Marowsky-Bree   dlm: fix connecti...
1537
1538
  	if (test_and_clear_bit(CF_WRITE_PENDING, &con->flags))
  		send_to_sock(con);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1539
1540
1541
1542
1543
1544
  }
  
  
  /* Discard all entries on the write queues */
  static void clean_writequeues(void)
  {
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1545
  	foreach_conn(clean_one_writequeue);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1546
  }
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1547
  static void work_stop(void)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1548
  {
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1549
1550
  	destroy_workqueue(recv_workqueue);
  	destroy_workqueue(send_workqueue);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1551
  }
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1552
  static int work_start(void)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1553
  {
e43f055a9   David Teigland   dlm: use alloc_wo...
1554
1555
  	recv_workqueue = alloc_workqueue("dlm_recv",
  					 WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
b9d410527   Namhyung Kim   dlm: sanitize wor...
1556
1557
1558
  	if (!recv_workqueue) {
  		log_print("can't start dlm_recv");
  		return -ENOMEM;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1559
  	}
fdda387f7   Patrick Caulfield   [DLM] Add support...
1560

e43f055a9   David Teigland   dlm: use alloc_wo...
1561
1562
  	send_workqueue = alloc_workqueue("dlm_send",
  					 WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
b9d410527   Namhyung Kim   dlm: sanitize wor...
1563
1564
  	if (!send_workqueue) {
  		log_print("can't start dlm_send");
1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1565
  		destroy_workqueue(recv_workqueue);
b9d410527   Namhyung Kim   dlm: sanitize wor...
1566
  		return -ENOMEM;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1567
  	}
fdda387f7   Patrick Caulfield   [DLM] Add support...
1568
1569
1570
  
  	return 0;
  }
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1571
  static void stop_conn(struct connection *con)
fdda387f7   Patrick Caulfield   [DLM] Add support...
1572
  {
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1573
  	con->flags |= 0x0F;
391fbdc5d   Christine Caulfield   dlm: connect to n...
1574
  	if (con->sock && con->sock->sk)
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1575
1576
  		con->sock->sk->sk_user_data = NULL;
  }
fdda387f7   Patrick Caulfield   [DLM] Add support...
1577

5e9ccc372   Christine Caulfield   dlm: replace idr ...
1578
1579
  static void free_conn(struct connection *con)
  {
0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
1580
  	close_connection(con, true, true, true);
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1581
1582
1583
1584
1585
1586
1587
1588
  	if (con->othercon)
  		kmem_cache_free(con_cache, con->othercon);
  	hlist_del(&con->list);
  	kmem_cache_free(con_cache, con);
  }
  
  void dlm_lowcomms_stop(void)
  {
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1589
  	/* Set all the flags to prevent any
fdda387f7   Patrick Caulfield   [DLM] Add support...
1590
1591
  	   socket activity.
  	*/
7a936ce71   Matthias Kaehlcke   dlm: convert conn...
1592
  	mutex_lock(&connections_lock);
513ef596d   David Teigland   dlm: prevent conn...
1593
  	dlm_allow_conn = 0;
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1594
  	foreach_conn(stop_conn);
7a936ce71   Matthias Kaehlcke   dlm: convert conn...
1595
  	mutex_unlock(&connections_lock);
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1596

1d6e8131c   Patrick Caulfield   [DLM] Use workque...
1597
  	work_stop();
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1598

7a936ce71   Matthias Kaehlcke   dlm: convert conn...
1599
  	mutex_lock(&connections_lock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1600
  	clean_writequeues();
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1601
  	foreach_conn(free_conn);
7a936ce71   Matthias Kaehlcke   dlm: convert conn...
1602
  	mutex_unlock(&connections_lock);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1603
1604
  	kmem_cache_destroy(con_cache);
  }
fdda387f7   Patrick Caulfield   [DLM] Add support...
1605
1606
  int dlm_lowcomms_start(void)
  {
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1607
1608
  	int error = -EINVAL;
  	struct connection *con;
5e9ccc372   Christine Caulfield   dlm: replace idr ...
1609
1610
1611
1612
  	int i;
  
  	for (i = 0; i < CONN_HASH_SIZE; i++)
  		INIT_HLIST_HEAD(&connection_hash[i]);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1613

6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1614
1615
  	init_local();
  	if (!dlm_local_count) {
617e82e10   David Teigland   [DLM] lowcomms style
1616
  		error = -ENOTCONN;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1617
  		log_print("no local IP address has been set");
513ef596d   David Teigland   dlm: prevent conn...
1618
  		goto fail;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1619
  	}
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1620
  	error = -ENOMEM;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1621
  	con_cache = kmem_cache_create("dlm_conn", sizeof(struct connection),
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1622
  				      __alignof__(struct connection), 0,
20c2df83d   Paul Mundt   mm: Remove slab d...
1623
  				      NULL);
fdda387f7   Patrick Caulfield   [DLM] Add support...
1624
  	if (!con_cache)
513ef596d   David Teigland   dlm: prevent conn...
1625
1626
1627
1628
1629
1630
1631
  		goto fail;
  
  	error = work_start();
  	if (error)
  		goto fail_destroy;
  
  	dlm_allow_conn = 1;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1632

fdda387f7   Patrick Caulfield   [DLM] Add support...
1633
  	/* Start listening */
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1634
1635
1636
1637
  	if (dlm_config.ci_protocol == 0)
  		error = tcp_listen_for_all();
  	else
  		error = sctp_listen_for_all();
fdda387f7   Patrick Caulfield   [DLM] Add support...
1638
1639
  	if (error)
  		goto fail_unlisten;
fdda387f7   Patrick Caulfield   [DLM] Add support...
1640
  	return 0;
ac33d0710   Patrick Caulfield   [DLM] Clean up lo...
1641
  fail_unlisten:
513ef596d   David Teigland   dlm: prevent conn...
1642
  	dlm_allow_conn = 0;
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1643
1644
  	con = nodeid2con(0,0);
  	if (con) {
0d737a8cf   Marcelo Ricardo Leitner   dlm: fix race whi...
1645
  		close_connection(con, false, true, true);
6ed7257b4   Patrick Caulfield   [DLM] Consolidate...
1646
1647
  		kmem_cache_free(con_cache, con);
  	}
513ef596d   David Teigland   dlm: prevent conn...
1648
  fail_destroy:
fdda387f7   Patrick Caulfield   [DLM] Add support...
1649
  	kmem_cache_destroy(con_cache);
513ef596d   David Teigland   dlm: prevent conn...
1650
  fail:
fdda387f7   Patrick Caulfield   [DLM] Add support...
1651
1652
  	return error;
  }
36b71a8bf   David Teigland   dlm: fix deadlock...
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
  
  void dlm_lowcomms_exit(void)
  {
  	struct dlm_node_addr *na, *safe;
  
  	spin_lock(&dlm_node_addrs_spin);
  	list_for_each_entry_safe(na, safe, &dlm_node_addrs, list) {
  		list_del(&na->list);
  		while (na->addr_count--)
  			kfree(na->addr[na->addr_count]);
  		kfree(na);
  	}
  	spin_unlock(&dlm_node_addrs_spin);
  }