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