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