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