at v2.6.19 951 lines 25 kB view raw
1/* vlocation.c: volume location 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/kernel.h> 13#include <linux/module.h> 14#include <linux/init.h> 15#include <linux/slab.h> 16#include <linux/fs.h> 17#include <linux/pagemap.h> 18#include "volume.h" 19#include "cell.h" 20#include "cmservice.h" 21#include "fsclient.h" 22#include "vlclient.h" 23#include "kafstimod.h" 24#include <rxrpc/connection.h> 25#include "internal.h" 26 27#define AFS_VLDB_TIMEOUT HZ*1000 28 29static void afs_vlocation_update_timer(struct afs_timer *timer); 30static void afs_vlocation_update_attend(struct afs_async_op *op); 31static void afs_vlocation_update_discard(struct afs_async_op *op); 32static void __afs_put_vlocation(struct afs_vlocation *vlocation); 33 34static void __afs_vlocation_timeout(struct afs_timer *timer) 35{ 36 struct afs_vlocation *vlocation = 37 list_entry(timer, struct afs_vlocation, timeout); 38 39 _debug("VL TIMEOUT [%s{u=%d}]", 40 vlocation->vldb.name, atomic_read(&vlocation->usage)); 41 42 afs_vlocation_do_timeout(vlocation); 43} 44 45static const struct afs_timer_ops afs_vlocation_timer_ops = { 46 .timed_out = __afs_vlocation_timeout, 47}; 48 49static const struct afs_timer_ops afs_vlocation_update_timer_ops = { 50 .timed_out = afs_vlocation_update_timer, 51}; 52 53static const struct afs_async_op_ops afs_vlocation_update_op_ops = { 54 .attend = afs_vlocation_update_attend, 55 .discard = afs_vlocation_update_discard, 56}; 57 58static LIST_HEAD(afs_vlocation_update_pendq); /* queue of VLs awaiting update */ 59static struct afs_vlocation *afs_vlocation_update; /* VL currently being updated */ 60static DEFINE_SPINLOCK(afs_vlocation_update_lock); /* lock guarding update queue */ 61 62#ifdef AFS_CACHING_SUPPORT 63static cachefs_match_val_t afs_vlocation_cache_match(void *target, 64 const void *entry); 65static void afs_vlocation_cache_update(void *source, void *entry); 66 67struct cachefs_index_def afs_vlocation_cache_index_def = { 68 .name = "vldb", 69 .data_size = sizeof(struct afs_cache_vlocation), 70 .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 }, 71 .match = afs_vlocation_cache_match, 72 .update = afs_vlocation_cache_update, 73}; 74#endif 75 76/*****************************************************************************/ 77/* 78 * iterate through the VL servers in a cell until one of them admits knowing 79 * about the volume in question 80 * - caller must have cell->vl_sem write-locked 81 */ 82static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vlocation, 83 const char *name, 84 unsigned namesz, 85 struct afs_cache_vlocation *vldb) 86{ 87 struct afs_server *server = NULL; 88 struct afs_cell *cell = vlocation->cell; 89 int count, ret; 90 91 _enter("%s,%*.*s,%u", cell->name, namesz, namesz, name, namesz); 92 93 ret = -ENOMEDIUM; 94 for (count = cell->vl_naddrs; count > 0; count--) { 95 _debug("CellServ[%hu]: %08x", 96 cell->vl_curr_svix, 97 cell->vl_addrs[cell->vl_curr_svix].s_addr); 98 99 /* try and create a server */ 100 ret = afs_server_lookup(cell, 101 &cell->vl_addrs[cell->vl_curr_svix], 102 &server); 103 switch (ret) { 104 case 0: 105 break; 106 case -ENOMEM: 107 case -ENONET: 108 goto out; 109 default: 110 goto rotate; 111 } 112 113 /* attempt to access the VL server */ 114 ret = afs_rxvl_get_entry_by_name(server, name, namesz, vldb); 115 switch (ret) { 116 case 0: 117 afs_put_server(server); 118 goto out; 119 case -ENOMEM: 120 case -ENONET: 121 case -ENETUNREACH: 122 case -EHOSTUNREACH: 123 case -ECONNREFUSED: 124 down_write(&server->sem); 125 if (server->vlserver) { 126 rxrpc_put_connection(server->vlserver); 127 server->vlserver = NULL; 128 } 129 up_write(&server->sem); 130 afs_put_server(server); 131 if (ret == -ENOMEM || ret == -ENONET) 132 goto out; 133 goto rotate; 134 case -ENOMEDIUM: 135 afs_put_server(server); 136 goto out; 137 default: 138 afs_put_server(server); 139 ret = -ENOMEDIUM; 140 goto rotate; 141 } 142 143 /* rotate the server records upon lookup failure */ 144 rotate: 145 cell->vl_curr_svix++; 146 cell->vl_curr_svix %= cell->vl_naddrs; 147 } 148 149 out: 150 _leave(" = %d", ret); 151 return ret; 152 153} /* end afs_vlocation_access_vl_by_name() */ 154 155/*****************************************************************************/ 156/* 157 * iterate through the VL servers in a cell until one of them admits knowing 158 * about the volume in question 159 * - caller must have cell->vl_sem write-locked 160 */ 161static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vlocation, 162 afs_volid_t volid, 163 afs_voltype_t voltype, 164 struct afs_cache_vlocation *vldb) 165{ 166 struct afs_server *server = NULL; 167 struct afs_cell *cell = vlocation->cell; 168 int count, ret; 169 170 _enter("%s,%x,%d,", cell->name, volid, voltype); 171 172 ret = -ENOMEDIUM; 173 for (count = cell->vl_naddrs; count > 0; count--) { 174 _debug("CellServ[%hu]: %08x", 175 cell->vl_curr_svix, 176 cell->vl_addrs[cell->vl_curr_svix].s_addr); 177 178 /* try and create a server */ 179 ret = afs_server_lookup(cell, 180 &cell->vl_addrs[cell->vl_curr_svix], 181 &server); 182 switch (ret) { 183 case 0: 184 break; 185 case -ENOMEM: 186 case -ENONET: 187 goto out; 188 default: 189 goto rotate; 190 } 191 192 /* attempt to access the VL server */ 193 ret = afs_rxvl_get_entry_by_id(server, volid, voltype, vldb); 194 switch (ret) { 195 case 0: 196 afs_put_server(server); 197 goto out; 198 case -ENOMEM: 199 case -ENONET: 200 case -ENETUNREACH: 201 case -EHOSTUNREACH: 202 case -ECONNREFUSED: 203 down_write(&server->sem); 204 if (server->vlserver) { 205 rxrpc_put_connection(server->vlserver); 206 server->vlserver = NULL; 207 } 208 up_write(&server->sem); 209 afs_put_server(server); 210 if (ret == -ENOMEM || ret == -ENONET) 211 goto out; 212 goto rotate; 213 case -ENOMEDIUM: 214 afs_put_server(server); 215 goto out; 216 default: 217 afs_put_server(server); 218 ret = -ENOMEDIUM; 219 goto rotate; 220 } 221 222 /* rotate the server records upon lookup failure */ 223 rotate: 224 cell->vl_curr_svix++; 225 cell->vl_curr_svix %= cell->vl_naddrs; 226 } 227 228 out: 229 _leave(" = %d", ret); 230 return ret; 231 232} /* end afs_vlocation_access_vl_by_id() */ 233 234/*****************************************************************************/ 235/* 236 * lookup volume location 237 * - caller must have cell->vol_sem write-locked 238 * - iterate through the VL servers in a cell until one of them admits knowing 239 * about the volume in question 240 * - lookup in the local cache if not able to find on the VL server 241 * - insert/update in the local cache if did get a VL response 242 */ 243int afs_vlocation_lookup(struct afs_cell *cell, 244 const char *name, 245 unsigned namesz, 246 struct afs_vlocation **_vlocation) 247{ 248 struct afs_cache_vlocation vldb; 249 struct afs_vlocation *vlocation; 250 afs_voltype_t voltype; 251 afs_volid_t vid; 252 int active = 0, ret; 253 254 _enter("{%s},%*.*s,%u,", cell->name, namesz, namesz, name, namesz); 255 256 if (namesz > sizeof(vlocation->vldb.name)) { 257 _leave(" = -ENAMETOOLONG"); 258 return -ENAMETOOLONG; 259 } 260 261 /* search the cell's active list first */ 262 list_for_each_entry(vlocation, &cell->vl_list, link) { 263 if (namesz < sizeof(vlocation->vldb.name) && 264 vlocation->vldb.name[namesz] != '\0') 265 continue; 266 267 if (memcmp(vlocation->vldb.name, name, namesz) == 0) 268 goto found_in_memory; 269 } 270 271 /* search the cell's graveyard list second */ 272 spin_lock(&cell->vl_gylock); 273 list_for_each_entry(vlocation, &cell->vl_graveyard, link) { 274 if (namesz < sizeof(vlocation->vldb.name) && 275 vlocation->vldb.name[namesz] != '\0') 276 continue; 277 278 if (memcmp(vlocation->vldb.name, name, namesz) == 0) 279 goto found_in_graveyard; 280 } 281 spin_unlock(&cell->vl_gylock); 282 283 /* not in the cell's in-memory lists - create a new record */ 284 vlocation = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL); 285 if (!vlocation) 286 return -ENOMEM; 287 288 atomic_set(&vlocation->usage, 1); 289 INIT_LIST_HEAD(&vlocation->link); 290 rwlock_init(&vlocation->lock); 291 memcpy(vlocation->vldb.name, name, namesz); 292 293 afs_timer_init(&vlocation->timeout, &afs_vlocation_timer_ops); 294 afs_timer_init(&vlocation->upd_timer, &afs_vlocation_update_timer_ops); 295 afs_async_op_init(&vlocation->upd_op, &afs_vlocation_update_op_ops); 296 297 afs_get_cell(cell); 298 vlocation->cell = cell; 299 300 list_add_tail(&vlocation->link, &cell->vl_list); 301 302#ifdef AFS_CACHING_SUPPORT 303 /* we want to store it in the cache, plus it might already be 304 * encached */ 305 cachefs_acquire_cookie(cell->cache, 306 &afs_volume_cache_index_def, 307 vlocation, 308 &vlocation->cache); 309 310 if (vlocation->valid) 311 goto found_in_cache; 312#endif 313 314 /* try to look up an unknown volume in the cell VL databases by name */ 315 ret = afs_vlocation_access_vl_by_name(vlocation, name, namesz, &vldb); 316 if (ret < 0) { 317 printk("kAFS: failed to locate '%*.*s' in cell '%s'\n", 318 namesz, namesz, name, cell->name); 319 goto error; 320 } 321 322 goto found_on_vlserver; 323 324 found_in_graveyard: 325 /* found in the graveyard - resurrect */ 326 _debug("found in graveyard"); 327 atomic_inc(&vlocation->usage); 328 list_move_tail(&vlocation->link, &cell->vl_list); 329 spin_unlock(&cell->vl_gylock); 330 331 afs_kafstimod_del_timer(&vlocation->timeout); 332 goto active; 333 334 found_in_memory: 335 /* found in memory - check to see if it's active */ 336 _debug("found in memory"); 337 atomic_inc(&vlocation->usage); 338 339 active: 340 active = 1; 341 342#ifdef AFS_CACHING_SUPPORT 343 found_in_cache: 344#endif 345 /* try to look up a cached volume in the cell VL databases by ID */ 346 _debug("found in cache"); 347 348 _debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }", 349 vlocation->vldb.name, 350 vlocation->vldb.vidmask, 351 ntohl(vlocation->vldb.servers[0].s_addr), 352 vlocation->vldb.srvtmask[0], 353 ntohl(vlocation->vldb.servers[1].s_addr), 354 vlocation->vldb.srvtmask[1], 355 ntohl(vlocation->vldb.servers[2].s_addr), 356 vlocation->vldb.srvtmask[2] 357 ); 358 359 _debug("Vids: %08x %08x %08x", 360 vlocation->vldb.vid[0], 361 vlocation->vldb.vid[1], 362 vlocation->vldb.vid[2]); 363 364 if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) { 365 vid = vlocation->vldb.vid[0]; 366 voltype = AFSVL_RWVOL; 367 } 368 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) { 369 vid = vlocation->vldb.vid[1]; 370 voltype = AFSVL_ROVOL; 371 } 372 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) { 373 vid = vlocation->vldb.vid[2]; 374 voltype = AFSVL_BACKVOL; 375 } 376 else { 377 BUG(); 378 vid = 0; 379 voltype = 0; 380 } 381 382 ret = afs_vlocation_access_vl_by_id(vlocation, vid, voltype, &vldb); 383 switch (ret) { 384 /* net error */ 385 default: 386 printk("kAFS: failed to volume '%*.*s' (%x) up in '%s': %d\n", 387 namesz, namesz, name, vid, cell->name, ret); 388 goto error; 389 390 /* pulled from local cache into memory */ 391 case 0: 392 goto found_on_vlserver; 393 394 /* uh oh... looks like the volume got deleted */ 395 case -ENOMEDIUM: 396 printk("kAFS: volume '%*.*s' (%x) does not exist '%s'\n", 397 namesz, namesz, name, vid, cell->name); 398 399 /* TODO: make existing record unavailable */ 400 goto error; 401 } 402 403 found_on_vlserver: 404 _debug("Done VL Lookup: %*.*s %02x { %08x(%x) %08x(%x) %08x(%x) }", 405 namesz, namesz, name, 406 vldb.vidmask, 407 ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0], 408 ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1], 409 ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2] 410 ); 411 412 _debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]); 413 414 if ((namesz < sizeof(vlocation->vldb.name) && 415 vlocation->vldb.name[namesz] != '\0') || 416 memcmp(vldb.name, name, namesz) != 0) 417 printk("kAFS: name of volume '%*.*s' changed to '%s' on server\n", 418 namesz, namesz, name, vldb.name); 419 420 memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb)); 421 422 afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ); 423 424#ifdef AFS_CACHING_SUPPORT 425 /* update volume entry in local cache */ 426 cachefs_update_cookie(vlocation->cache); 427#endif 428 429 *_vlocation = vlocation; 430 _leave(" = 0 (%p)",vlocation); 431 return 0; 432 433 error: 434 if (vlocation) { 435 if (active) { 436 __afs_put_vlocation(vlocation); 437 } 438 else { 439 list_del(&vlocation->link); 440#ifdef AFS_CACHING_SUPPORT 441 cachefs_relinquish_cookie(vlocation->cache, 0); 442#endif 443 afs_put_cell(vlocation->cell); 444 kfree(vlocation); 445 } 446 } 447 448 _leave(" = %d", ret); 449 return ret; 450} /* end afs_vlocation_lookup() */ 451 452/*****************************************************************************/ 453/* 454 * finish using a volume location record 455 * - caller must have cell->vol_sem write-locked 456 */ 457static void __afs_put_vlocation(struct afs_vlocation *vlocation) 458{ 459 struct afs_cell *cell; 460 461 if (!vlocation) 462 return; 463 464 _enter("%s", vlocation->vldb.name); 465 466 cell = vlocation->cell; 467 468 /* sanity check */ 469 BUG_ON(atomic_read(&vlocation->usage) <= 0); 470 471 spin_lock(&cell->vl_gylock); 472 if (likely(!atomic_dec_and_test(&vlocation->usage))) { 473 spin_unlock(&cell->vl_gylock); 474 _leave(""); 475 return; 476 } 477 478 /* move to graveyard queue */ 479 list_move_tail(&vlocation->link,&cell->vl_graveyard); 480 481 /* remove from pending timeout queue (refcounted if actually being 482 * updated) */ 483 list_del_init(&vlocation->upd_op.link); 484 485 /* time out in 10 secs */ 486 afs_kafstimod_del_timer(&vlocation->upd_timer); 487 afs_kafstimod_add_timer(&vlocation->timeout, 10 * HZ); 488 489 spin_unlock(&cell->vl_gylock); 490 491 _leave(" [killed]"); 492} /* end __afs_put_vlocation() */ 493 494/*****************************************************************************/ 495/* 496 * finish using a volume location record 497 */ 498void afs_put_vlocation(struct afs_vlocation *vlocation) 499{ 500 if (vlocation) { 501 struct afs_cell *cell = vlocation->cell; 502 503 down_write(&cell->vl_sem); 504 __afs_put_vlocation(vlocation); 505 up_write(&cell->vl_sem); 506 } 507} /* end afs_put_vlocation() */ 508 509/*****************************************************************************/ 510/* 511 * timeout vlocation record 512 * - removes from the cell's graveyard if the usage count is zero 513 */ 514void afs_vlocation_do_timeout(struct afs_vlocation *vlocation) 515{ 516 struct afs_cell *cell; 517 518 _enter("%s", vlocation->vldb.name); 519 520 cell = vlocation->cell; 521 522 BUG_ON(atomic_read(&vlocation->usage) < 0); 523 524 /* remove from graveyard if still dead */ 525 spin_lock(&cell->vl_gylock); 526 if (atomic_read(&vlocation->usage) == 0) 527 list_del_init(&vlocation->link); 528 else 529 vlocation = NULL; 530 spin_unlock(&cell->vl_gylock); 531 532 if (!vlocation) { 533 _leave(""); 534 return; /* resurrected */ 535 } 536 537 /* we can now destroy it properly */ 538#ifdef AFS_CACHING_SUPPORT 539 cachefs_relinquish_cookie(vlocation->cache, 0); 540#endif 541 afs_put_cell(cell); 542 543 kfree(vlocation); 544 545 _leave(" [destroyed]"); 546} /* end afs_vlocation_do_timeout() */ 547 548/*****************************************************************************/ 549/* 550 * send an update operation to the currently selected server 551 */ 552static int afs_vlocation_update_begin(struct afs_vlocation *vlocation) 553{ 554 afs_voltype_t voltype; 555 afs_volid_t vid; 556 int ret; 557 558 _enter("%s{ufs=%u ucs=%u}", 559 vlocation->vldb.name, 560 vlocation->upd_first_svix, 561 vlocation->upd_curr_svix); 562 563 /* try to look up a cached volume in the cell VL databases by ID */ 564 if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) { 565 vid = vlocation->vldb.vid[0]; 566 voltype = AFSVL_RWVOL; 567 } 568 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) { 569 vid = vlocation->vldb.vid[1]; 570 voltype = AFSVL_ROVOL; 571 } 572 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) { 573 vid = vlocation->vldb.vid[2]; 574 voltype = AFSVL_BACKVOL; 575 } 576 else { 577 BUG(); 578 vid = 0; 579 voltype = 0; 580 } 581 582 /* contact the chosen server */ 583 ret = afs_server_lookup( 584 vlocation->cell, 585 &vlocation->cell->vl_addrs[vlocation->upd_curr_svix], 586 &vlocation->upd_op.server); 587 588 switch (ret) { 589 case 0: 590 break; 591 case -ENOMEM: 592 case -ENONET: 593 default: 594 _leave(" = %d", ret); 595 return ret; 596 } 597 598 /* initiate the update operation */ 599 ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op, vid, voltype); 600 if (ret < 0) { 601 _leave(" = %d", ret); 602 return ret; 603 } 604 605 _leave(" = %d", ret); 606 return ret; 607} /* end afs_vlocation_update_begin() */ 608 609/*****************************************************************************/ 610/* 611 * abandon updating a VL record 612 * - does not restart the update timer 613 */ 614static void afs_vlocation_update_abandon(struct afs_vlocation *vlocation, 615 afs_vlocation_upd_t state, 616 int ret) 617{ 618 _enter("%s,%u", vlocation->vldb.name, state); 619 620 if (ret < 0) 621 printk("kAFS: Abandoning VL update '%s': %d\n", 622 vlocation->vldb.name, ret); 623 624 /* discard the server record */ 625 afs_put_server(vlocation->upd_op.server); 626 vlocation->upd_op.server = NULL; 627 628 spin_lock(&afs_vlocation_update_lock); 629 afs_vlocation_update = NULL; 630 vlocation->upd_state = state; 631 632 /* TODO: start updating next VL record on pending list */ 633 634 spin_unlock(&afs_vlocation_update_lock); 635 636 _leave(""); 637} /* end afs_vlocation_update_abandon() */ 638 639/*****************************************************************************/ 640/* 641 * handle periodic update timeouts and busy retry timeouts 642 * - called from kafstimod 643 */ 644static void afs_vlocation_update_timer(struct afs_timer *timer) 645{ 646 struct afs_vlocation *vlocation = 647 list_entry(timer, struct afs_vlocation, upd_timer); 648 int ret; 649 650 _enter("%s", vlocation->vldb.name); 651 652 /* only update if not in the graveyard (defend against putting too) */ 653 spin_lock(&vlocation->cell->vl_gylock); 654 655 if (!atomic_read(&vlocation->usage)) 656 goto out_unlock1; 657 658 spin_lock(&afs_vlocation_update_lock); 659 660 /* if we were woken up due to EBUSY sleep then restart immediately if 661 * possible or else jump to front of pending queue */ 662 if (vlocation->upd_state == AFS_VLUPD_BUSYSLEEP) { 663 if (afs_vlocation_update) { 664 list_add(&vlocation->upd_op.link, 665 &afs_vlocation_update_pendq); 666 } 667 else { 668 afs_get_vlocation(vlocation); 669 afs_vlocation_update = vlocation; 670 vlocation->upd_state = AFS_VLUPD_INPROGRESS; 671 } 672 goto out_unlock2; 673 } 674 675 /* put on pending queue if there's already another update in progress */ 676 if (afs_vlocation_update) { 677 vlocation->upd_state = AFS_VLUPD_PENDING; 678 list_add_tail(&vlocation->upd_op.link, 679 &afs_vlocation_update_pendq); 680 goto out_unlock2; 681 } 682 683 /* hold a ref on it while actually updating */ 684 afs_get_vlocation(vlocation); 685 afs_vlocation_update = vlocation; 686 vlocation->upd_state = AFS_VLUPD_INPROGRESS; 687 688 spin_unlock(&afs_vlocation_update_lock); 689 spin_unlock(&vlocation->cell->vl_gylock); 690 691 /* okay... we can start the update */ 692 _debug("BEGIN VL UPDATE [%s]", vlocation->vldb.name); 693 vlocation->upd_first_svix = vlocation->cell->vl_curr_svix; 694 vlocation->upd_curr_svix = vlocation->upd_first_svix; 695 vlocation->upd_rej_cnt = 0; 696 vlocation->upd_busy_cnt = 0; 697 698 ret = afs_vlocation_update_begin(vlocation); 699 if (ret < 0) { 700 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret); 701 afs_kafstimod_add_timer(&vlocation->upd_timer, 702 AFS_VLDB_TIMEOUT); 703 afs_put_vlocation(vlocation); 704 } 705 706 _leave(""); 707 return; 708 709 out_unlock2: 710 spin_unlock(&afs_vlocation_update_lock); 711 out_unlock1: 712 spin_unlock(&vlocation->cell->vl_gylock); 713 _leave(""); 714 return; 715 716} /* end afs_vlocation_update_timer() */ 717 718/*****************************************************************************/ 719/* 720 * attend to an update operation upon which an event happened 721 * - called in kafsasyncd context 722 */ 723static void afs_vlocation_update_attend(struct afs_async_op *op) 724{ 725 struct afs_cache_vlocation vldb; 726 struct afs_vlocation *vlocation = 727 list_entry(op, struct afs_vlocation, upd_op); 728 unsigned tmp; 729 int ret; 730 731 _enter("%s", vlocation->vldb.name); 732 733 ret = afs_rxvl_get_entry_by_id_async2(op, &vldb); 734 switch (ret) { 735 case -EAGAIN: 736 _leave(" [unfinished]"); 737 return; 738 739 case 0: 740 _debug("END VL UPDATE: %d\n", ret); 741 vlocation->valid = 1; 742 743 _debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }", 744 vldb.vidmask, 745 ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0], 746 ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1], 747 ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2] 748 ); 749 750 _debug("Vids: %08x %08x %08x", 751 vldb.vid[0], vldb.vid[1], vldb.vid[2]); 752 753 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0); 754 755 down_write(&vlocation->cell->vl_sem); 756 757 /* actually update the cache */ 758 if (strncmp(vldb.name, vlocation->vldb.name, 759 sizeof(vlocation->vldb.name)) != 0) 760 printk("kAFS: name of volume '%s'" 761 " changed to '%s' on server\n", 762 vlocation->vldb.name, vldb.name); 763 764 memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb)); 765 766#if 0 767 /* TODO update volume entry in local cache */ 768#endif 769 770 up_write(&vlocation->cell->vl_sem); 771 772 if (ret < 0) 773 printk("kAFS: failed to update local cache: %d\n", ret); 774 775 afs_kafstimod_add_timer(&vlocation->upd_timer, 776 AFS_VLDB_TIMEOUT); 777 afs_put_vlocation(vlocation); 778 _leave(" [found]"); 779 return; 780 781 case -ENOMEDIUM: 782 vlocation->upd_rej_cnt++; 783 goto try_next; 784 785 /* the server is locked - retry in a very short while */ 786 case -EBUSY: 787 vlocation->upd_busy_cnt++; 788 if (vlocation->upd_busy_cnt > 3) 789 goto try_next; /* too many retries */ 790 791 afs_vlocation_update_abandon(vlocation, 792 AFS_VLUPD_BUSYSLEEP, 0); 793 afs_kafstimod_add_timer(&vlocation->upd_timer, HZ / 2); 794 afs_put_vlocation(vlocation); 795 _leave(" [busy]"); 796 return; 797 798 case -ENETUNREACH: 799 case -EHOSTUNREACH: 800 case -ECONNREFUSED: 801 case -EREMOTEIO: 802 /* record bad vlserver info in the cell too 803 * - TODO: use down_write_trylock() if available 804 */ 805 if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix) 806 vlocation->cell->vl_curr_svix = 807 vlocation->cell->vl_curr_svix % 808 vlocation->cell->vl_naddrs; 809 810 case -EBADRQC: 811 case -EINVAL: 812 case -EACCES: 813 case -EBADMSG: 814 goto try_next; 815 816 default: 817 goto abandon; 818 } 819 820 /* try contacting the next server */ 821 try_next: 822 vlocation->upd_busy_cnt = 0; 823 824 /* discard the server record */ 825 afs_put_server(vlocation->upd_op.server); 826 vlocation->upd_op.server = NULL; 827 828 tmp = vlocation->cell->vl_naddrs; 829 if (tmp == 0) 830 goto abandon; 831 832 vlocation->upd_curr_svix++; 833 if (vlocation->upd_curr_svix >= tmp) 834 vlocation->upd_curr_svix = 0; 835 if (vlocation->upd_first_svix >= tmp) 836 vlocation->upd_first_svix = tmp - 1; 837 838 /* move to the next server */ 839 if (vlocation->upd_curr_svix != vlocation->upd_first_svix) { 840 afs_vlocation_update_begin(vlocation); 841 _leave(" [next]"); 842 return; 843 } 844 845 /* run out of servers to try - was the volume rejected? */ 846 if (vlocation->upd_rej_cnt > 0) { 847 printk("kAFS: Active volume no longer valid '%s'\n", 848 vlocation->vldb.name); 849 vlocation->valid = 0; 850 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0); 851 afs_kafstimod_add_timer(&vlocation->upd_timer, 852 AFS_VLDB_TIMEOUT); 853 afs_put_vlocation(vlocation); 854 _leave(" [invalidated]"); 855 return; 856 } 857 858 /* abandon the update */ 859 abandon: 860 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret); 861 afs_kafstimod_add_timer(&vlocation->upd_timer, HZ * 10); 862 afs_put_vlocation(vlocation); 863 _leave(" [abandoned]"); 864 865} /* end afs_vlocation_update_attend() */ 866 867/*****************************************************************************/ 868/* 869 * deal with an update operation being discarded 870 * - called in kafsasyncd context when it's dying due to rmmod 871 * - the call has already been aborted and put()'d 872 */ 873static void afs_vlocation_update_discard(struct afs_async_op *op) 874{ 875 struct afs_vlocation *vlocation = 876 list_entry(op, struct afs_vlocation, upd_op); 877 878 _enter("%s", vlocation->vldb.name); 879 880 afs_put_server(op->server); 881 op->server = NULL; 882 883 afs_put_vlocation(vlocation); 884 885 _leave(""); 886} /* end afs_vlocation_update_discard() */ 887 888/*****************************************************************************/ 889/* 890 * match a VLDB record stored in the cache 891 * - may also load target from entry 892 */ 893#ifdef AFS_CACHING_SUPPORT 894static cachefs_match_val_t afs_vlocation_cache_match(void *target, 895 const void *entry) 896{ 897 const struct afs_cache_vlocation *vldb = entry; 898 struct afs_vlocation *vlocation = target; 899 900 _enter("{%s},{%s}", vlocation->vldb.name, vldb->name); 901 902 if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0 903 ) { 904 if (!vlocation->valid || 905 vlocation->vldb.rtime == vldb->rtime 906 ) { 907 vlocation->vldb = *vldb; 908 vlocation->valid = 1; 909 _leave(" = SUCCESS [c->m]"); 910 return CACHEFS_MATCH_SUCCESS; 911 } 912 /* need to update cache if cached info differs */ 913 else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) { 914 /* delete if VIDs for this name differ */ 915 if (memcmp(&vlocation->vldb.vid, 916 &vldb->vid, 917 sizeof(vldb->vid)) != 0) { 918 _leave(" = DELETE"); 919 return CACHEFS_MATCH_SUCCESS_DELETE; 920 } 921 922 _leave(" = UPDATE"); 923 return CACHEFS_MATCH_SUCCESS_UPDATE; 924 } 925 else { 926 _leave(" = SUCCESS"); 927 return CACHEFS_MATCH_SUCCESS; 928 } 929 } 930 931 _leave(" = FAILED"); 932 return CACHEFS_MATCH_FAILED; 933} /* end afs_vlocation_cache_match() */ 934#endif 935 936/*****************************************************************************/ 937/* 938 * update a VLDB record stored in the cache 939 */ 940#ifdef AFS_CACHING_SUPPORT 941static void afs_vlocation_cache_update(void *source, void *entry) 942{ 943 struct afs_cache_vlocation *vldb = entry; 944 struct afs_vlocation *vlocation = source; 945 946 _enter(""); 947 948 *vldb = vlocation->vldb; 949 950} /* end afs_vlocation_cache_update() */ 951#endif