xref: /linux/fs/afs/server.c (revision c537b994505099b7197e7d3125b942ecbcc51eb6)
1 /* server.c: AFS server record management
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11 
12 #include <linux/sched.h>
13 #include <linux/slab.h>
14 #include <rxrpc/peer.h>
15 #include <rxrpc/connection.h>
16 #include "volume.h"
17 #include "cell.h"
18 #include "server.h"
19 #include "transport.h"
20 #include "vlclient.h"
21 #include "kafstimod.h"
22 #include "internal.h"
23 
24 DEFINE_SPINLOCK(afs_server_peer_lock);
25 
26 #define FS_SERVICE_ID		1	/* AFS Volume Location Service ID */
27 #define VL_SERVICE_ID		52	/* AFS Volume Location Service ID */
28 
29 static void __afs_server_timeout(struct afs_timer *timer)
30 {
31 	struct afs_server *server =
32 		list_entry(timer, struct afs_server, timeout);
33 
34 	_debug("SERVER TIMEOUT [%p{u=%d}]",
35 	       server, atomic_read(&server->usage));
36 
37 	afs_server_do_timeout(server);
38 }
39 
40 static const struct afs_timer_ops afs_server_timer_ops = {
41 	.timed_out	= __afs_server_timeout,
42 };
43 
44 /*****************************************************************************/
45 /*
46  * lookup a server record in a cell
47  * - TODO: search the cell's server list
48  */
49 int afs_server_lookup(struct afs_cell *cell, const struct in_addr *addr,
50 		      struct afs_server **_server)
51 {
52 	struct afs_server *server, *active, *zombie;
53 	int loop;
54 
55 	_enter("%p,%08x,", cell, ntohl(addr->s_addr));
56 
57 	/* allocate and initialise a server record */
58 	server = kzalloc(sizeof(struct afs_server), GFP_KERNEL);
59 	if (!server) {
60 		_leave(" = -ENOMEM");
61 		return -ENOMEM;
62 	}
63 
64 	atomic_set(&server->usage, 1);
65 
66 	INIT_LIST_HEAD(&server->link);
67 	init_rwsem(&server->sem);
68 	INIT_LIST_HEAD(&server->fs_callq);
69 	spin_lock_init(&server->fs_lock);
70 	INIT_LIST_HEAD(&server->cb_promises);
71 	spin_lock_init(&server->cb_lock);
72 
73 	for (loop = 0; loop < AFS_SERVER_CONN_LIST_SIZE; loop++)
74 		server->fs_conn_cnt[loop] = 4;
75 
76 	memcpy(&server->addr, addr, sizeof(struct in_addr));
77 	server->addr.s_addr = addr->s_addr;
78 
79 	afs_timer_init(&server->timeout, &afs_server_timer_ops);
80 
81 	/* add to the cell */
82 	write_lock(&cell->sv_lock);
83 
84 	/* check the active list */
85 	list_for_each_entry(active, &cell->sv_list, link) {
86 		if (active->addr.s_addr == addr->s_addr)
87 			goto use_active_server;
88 	}
89 
90 	/* check the inactive list */
91 	spin_lock(&cell->sv_gylock);
92 	list_for_each_entry(zombie, &cell->sv_graveyard, link) {
93 		if (zombie->addr.s_addr == addr->s_addr)
94 			goto resurrect_server;
95 	}
96 	spin_unlock(&cell->sv_gylock);
97 
98 	afs_get_cell(cell);
99 	server->cell = cell;
100 	list_add_tail(&server->link, &cell->sv_list);
101 
102 	write_unlock(&cell->sv_lock);
103 
104 	*_server = server;
105 	_leave(" = 0 (%p)", server);
106 	return 0;
107 
108 	/* found a matching active server */
109  use_active_server:
110 	_debug("active server");
111 	afs_get_server(active);
112 	write_unlock(&cell->sv_lock);
113 
114 	kfree(server);
115 
116 	*_server = active;
117 	_leave(" = 0 (%p)", active);
118 	return 0;
119 
120 	/* found a matching server in the graveyard, so resurrect it and
121 	 * dispose of the new record */
122  resurrect_server:
123 	_debug("resurrecting server");
124 
125 	list_move_tail(&zombie->link, &cell->sv_list);
126 	afs_get_server(zombie);
127 	afs_kafstimod_del_timer(&zombie->timeout);
128 	spin_unlock(&cell->sv_gylock);
129 	write_unlock(&cell->sv_lock);
130 
131 	kfree(server);
132 
133 	*_server = zombie;
134 	_leave(" = 0 (%p)", zombie);
135 	return 0;
136 
137 } /* end afs_server_lookup() */
138 
139 /*****************************************************************************/
140 /*
141  * destroy a server record
142  * - removes from the cell list
143  */
144 void afs_put_server(struct afs_server *server)
145 {
146 	struct afs_cell *cell;
147 
148 	if (!server)
149 		return;
150 
151 	_enter("%p", server);
152 
153 	cell = server->cell;
154 
155 	/* sanity check */
156 	BUG_ON(atomic_read(&server->usage) <= 0);
157 
158 	/* to prevent a race, the decrement and the dequeue must be effectively
159 	 * atomic */
160 	write_lock(&cell->sv_lock);
161 
162 	if (likely(!atomic_dec_and_test(&server->usage))) {
163 		write_unlock(&cell->sv_lock);
164 		_leave("");
165 		return;
166 	}
167 
168 	spin_lock(&cell->sv_gylock);
169 	list_move_tail(&server->link, &cell->sv_graveyard);
170 
171 	/* time out in 10 secs */
172 	afs_kafstimod_add_timer(&server->timeout, 10 * HZ);
173 
174 	spin_unlock(&cell->sv_gylock);
175 	write_unlock(&cell->sv_lock);
176 
177 	_leave(" [killed]");
178 } /* end afs_put_server() */
179 
180 /*****************************************************************************/
181 /*
182  * timeout server record
183  * - removes from the cell's graveyard if the usage count is zero
184  */
185 void afs_server_do_timeout(struct afs_server *server)
186 {
187 	struct rxrpc_peer *peer;
188 	struct afs_cell *cell;
189 	int loop;
190 
191 	_enter("%p", server);
192 
193 	cell = server->cell;
194 
195 	BUG_ON(atomic_read(&server->usage) < 0);
196 
197 	/* remove from graveyard if still dead */
198 	spin_lock(&cell->vl_gylock);
199 	if (atomic_read(&server->usage) == 0)
200 		list_del_init(&server->link);
201 	else
202 		server = NULL;
203 	spin_unlock(&cell->vl_gylock);
204 
205 	if (!server) {
206 		_leave("");
207 		return; /* resurrected */
208 	}
209 
210 	/* we can now destroy it properly */
211 	afs_put_cell(cell);
212 
213 	/* uncross-point the structs under a global lock */
214 	spin_lock(&afs_server_peer_lock);
215 	peer = server->peer;
216 	if (peer) {
217 		server->peer = NULL;
218 		peer->user = NULL;
219 	}
220 	spin_unlock(&afs_server_peer_lock);
221 
222 	/* finish cleaning up the server */
223 	for (loop = AFS_SERVER_CONN_LIST_SIZE - 1; loop >= 0; loop--)
224 		if (server->fs_conn[loop])
225 			rxrpc_put_connection(server->fs_conn[loop]);
226 
227 	if (server->vlserver)
228 		rxrpc_put_connection(server->vlserver);
229 
230 	kfree(server);
231 
232 	_leave(" [destroyed]");
233 } /* end afs_server_do_timeout() */
234 
235 /*****************************************************************************/
236 /*
237  * get a callslot on a connection to the fileserver on the specified server
238  */
239 int afs_server_request_callslot(struct afs_server *server,
240 				struct afs_server_callslot *callslot)
241 {
242 	struct afs_server_callslot *pcallslot;
243 	struct rxrpc_connection *conn;
244 	int nconn, ret;
245 
246 	_enter("%p,",server);
247 
248 	INIT_LIST_HEAD(&callslot->link);
249 	callslot->task = current;
250 	callslot->conn = NULL;
251 	callslot->nconn = -1;
252 	callslot->ready = 0;
253 
254 	ret = 0;
255 	conn = NULL;
256 
257 	/* get hold of a callslot first */
258 	spin_lock(&server->fs_lock);
259 
260 	/* resurrect the server if it's death timeout has expired */
261 	if (server->fs_state) {
262 		if (time_before(jiffies, server->fs_dead_jif)) {
263 			ret = server->fs_state;
264 			spin_unlock(&server->fs_lock);
265 			_leave(" = %d [still dead]", ret);
266 			return ret;
267 		}
268 
269 		server->fs_state = 0;
270 	}
271 
272 	/* try and find a connection that has spare callslots */
273 	for (nconn = 0; nconn < AFS_SERVER_CONN_LIST_SIZE; nconn++) {
274 		if (server->fs_conn_cnt[nconn] > 0) {
275 			server->fs_conn_cnt[nconn]--;
276 			spin_unlock(&server->fs_lock);
277 			callslot->nconn = nconn;
278 			goto obtained_slot;
279 		}
280 	}
281 
282 	/* none were available - wait interruptibly for one to become
283 	 * available */
284 	set_current_state(TASK_INTERRUPTIBLE);
285 	list_add_tail(&callslot->link, &server->fs_callq);
286 	spin_unlock(&server->fs_lock);
287 
288 	while (!callslot->ready && !signal_pending(current)) {
289 		schedule();
290 		set_current_state(TASK_INTERRUPTIBLE);
291 	}
292 
293 	set_current_state(TASK_RUNNING);
294 
295 	/* even if we were interrupted we may still be queued */
296 	if (!callslot->ready) {
297 		spin_lock(&server->fs_lock);
298 		list_del_init(&callslot->link);
299 		spin_unlock(&server->fs_lock);
300 	}
301 
302 	nconn = callslot->nconn;
303 
304 	/* if interrupted, we must release any slot we also got before
305 	 * returning an error */
306 	if (signal_pending(current)) {
307 		ret = -EINTR;
308 		goto error_release;
309 	}
310 
311 	/* if we were woken up with an error, then pass that error back to the
312 	 * called */
313 	if (nconn < 0) {
314 		_leave(" = %d", callslot->errno);
315 		return callslot->errno;
316 	}
317 
318 	/* were we given a connection directly? */
319 	if (callslot->conn) {
320 		/* yes - use it */
321 		_leave(" = 0 (nc=%d)", nconn);
322 		return 0;
323 	}
324 
325 	/* got a callslot, but no connection */
326  obtained_slot:
327 
328 	/* need to get hold of the RxRPC connection */
329 	down_write(&server->sem);
330 
331 	/* quick check to see if there's an outstanding error */
332 	ret = server->fs_state;
333 	if (ret)
334 		goto error_release_upw;
335 
336 	if (server->fs_conn[nconn]) {
337 		/* reuse an existing connection */
338 		rxrpc_get_connection(server->fs_conn[nconn]);
339 		callslot->conn = server->fs_conn[nconn];
340 	}
341 	else {
342 		/* create a new connection */
343 		ret = rxrpc_create_connection(afs_transport,
344 					      htons(7000),
345 					      server->addr.s_addr,
346 					      FS_SERVICE_ID,
347 					      NULL,
348 					      &server->fs_conn[nconn]);
349 
350 		if (ret < 0)
351 			goto error_release_upw;
352 
353 		callslot->conn = server->fs_conn[0];
354 		rxrpc_get_connection(callslot->conn);
355 	}
356 
357 	up_write(&server->sem);
358 
359  	_leave(" = 0");
360 	return 0;
361 
362 	/* handle an error occurring */
363  error_release_upw:
364 	up_write(&server->sem);
365 
366  error_release:
367 	/* either release the callslot or pass it along to another deserving
368 	 * task */
369 	spin_lock(&server->fs_lock);
370 
371 	if (nconn < 0) {
372 		/* no callslot allocated */
373 	}
374 	else if (list_empty(&server->fs_callq)) {
375 		/* no one waiting */
376 		server->fs_conn_cnt[nconn]++;
377 		spin_unlock(&server->fs_lock);
378 	}
379 	else {
380 		/* someone's waiting - dequeue them and wake them up */
381 		pcallslot = list_entry(server->fs_callq.next,
382 				       struct afs_server_callslot, link);
383 		list_del_init(&pcallslot->link);
384 
385 		pcallslot->errno = server->fs_state;
386 		if (!pcallslot->errno) {
387 			/* pass them out callslot details */
388 			callslot->conn = xchg(&pcallslot->conn,
389 					      callslot->conn);
390 			pcallslot->nconn = nconn;
391 			callslot->nconn = nconn = -1;
392 		}
393 		pcallslot->ready = 1;
394 		wake_up_process(pcallslot->task);
395 		spin_unlock(&server->fs_lock);
396 	}
397 
398 	rxrpc_put_connection(callslot->conn);
399 	callslot->conn = NULL;
400 
401 	_leave(" = %d", ret);
402 	return ret;
403 
404 } /* end afs_server_request_callslot() */
405 
406 /*****************************************************************************/
407 /*
408  * release a callslot back to the server
409  * - transfers the RxRPC connection to the next pending callslot if possible
410  */
411 void afs_server_release_callslot(struct afs_server *server,
412 				 struct afs_server_callslot *callslot)
413 {
414 	struct afs_server_callslot *pcallslot;
415 
416 	_enter("{ad=%08x,cnt=%u},{%d}",
417 	       ntohl(server->addr.s_addr),
418 	       server->fs_conn_cnt[callslot->nconn],
419 	       callslot->nconn);
420 
421 	BUG_ON(callslot->nconn < 0);
422 
423 	spin_lock(&server->fs_lock);
424 
425 	if (list_empty(&server->fs_callq)) {
426 		/* no one waiting */
427 		server->fs_conn_cnt[callslot->nconn]++;
428 		spin_unlock(&server->fs_lock);
429 	}
430 	else {
431 		/* someone's waiting - dequeue them and wake them up */
432 		pcallslot = list_entry(server->fs_callq.next,
433 				       struct afs_server_callslot, link);
434 		list_del_init(&pcallslot->link);
435 
436 		pcallslot->errno = server->fs_state;
437 		if (!pcallslot->errno) {
438 			/* pass them out callslot details */
439 			callslot->conn = xchg(&pcallslot->conn, callslot->conn);
440 			pcallslot->nconn = callslot->nconn;
441 			callslot->nconn = -1;
442 		}
443 
444 		pcallslot->ready = 1;
445 		wake_up_process(pcallslot->task);
446 		spin_unlock(&server->fs_lock);
447 	}
448 
449 	rxrpc_put_connection(callslot->conn);
450 
451 	_leave("");
452 } /* end afs_server_release_callslot() */
453 
454 /*****************************************************************************/
455 /*
456  * get a handle to a connection to the vlserver (volume location) on the
457  * specified server
458  */
459 int afs_server_get_vlconn(struct afs_server *server,
460 			  struct rxrpc_connection **_conn)
461 {
462 	struct rxrpc_connection *conn;
463 	int ret;
464 
465 	_enter("%p,", server);
466 
467 	ret = 0;
468 	conn = NULL;
469 	down_read(&server->sem);
470 
471 	if (server->vlserver) {
472 		/* reuse an existing connection */
473 		rxrpc_get_connection(server->vlserver);
474 		conn = server->vlserver;
475 		up_read(&server->sem);
476 	}
477 	else {
478 		/* create a new connection */
479 		up_read(&server->sem);
480 		down_write(&server->sem);
481 		if (!server->vlserver) {
482 			ret = rxrpc_create_connection(afs_transport,
483 						      htons(7003),
484 						      server->addr.s_addr,
485 						      VL_SERVICE_ID,
486 						      NULL,
487 						      &server->vlserver);
488 		}
489 		if (ret == 0) {
490 			rxrpc_get_connection(server->vlserver);
491 			conn = server->vlserver;
492 		}
493 		up_write(&server->sem);
494 	}
495 
496 	*_conn = conn;
497 	_leave(" = %d", ret);
498 	return ret;
499 } /* end afs_server_get_vlconn() */
500