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