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