at v2.6.12 954 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 = kmalloc(sizeof(struct afs_vlocation), GFP_KERNEL); 285 if (!vlocation) 286 return -ENOMEM; 287 288 memset(vlocation, 0, sizeof(struct afs_vlocation)); 289 atomic_set(&vlocation->usage, 1); 290 INIT_LIST_HEAD(&vlocation->link); 291 rwlock_init(&vlocation->lock); 292 memcpy(vlocation->vldb.name, name, namesz); 293 294 afs_timer_init(&vlocation->timeout, &afs_vlocation_timer_ops); 295 afs_timer_init(&vlocation->upd_timer, &afs_vlocation_update_timer_ops); 296 afs_async_op_init(&vlocation->upd_op, &afs_vlocation_update_op_ops); 297 298 afs_get_cell(cell); 299 vlocation->cell = cell; 300 301 list_add_tail(&vlocation->link, &cell->vl_list); 302 303#ifdef AFS_CACHING_SUPPORT 304 /* we want to store it in the cache, plus it might already be 305 * encached */ 306 cachefs_acquire_cookie(cell->cache, 307 &afs_volume_cache_index_def, 308 vlocation, 309 &vlocation->cache); 310 311 if (vlocation->valid) 312 goto found_in_cache; 313#endif 314 315 /* try to look up an unknown volume in the cell VL databases by name */ 316 ret = afs_vlocation_access_vl_by_name(vlocation, name, namesz, &vldb); 317 if (ret < 0) { 318 printk("kAFS: failed to locate '%*.*s' in cell '%s'\n", 319 namesz, namesz, name, cell->name); 320 goto error; 321 } 322 323 goto found_on_vlserver; 324 325 found_in_graveyard: 326 /* found in the graveyard - resurrect */ 327 _debug("found in graveyard"); 328 atomic_inc(&vlocation->usage); 329 list_del(&vlocation->link); 330 list_add_tail(&vlocation->link, &cell->vl_list); 331 spin_unlock(&cell->vl_gylock); 332 333 afs_kafstimod_del_timer(&vlocation->timeout); 334 goto active; 335 336 found_in_memory: 337 /* found in memory - check to see if it's active */ 338 _debug("found in memory"); 339 atomic_inc(&vlocation->usage); 340 341 active: 342 active = 1; 343 344#ifdef AFS_CACHING_SUPPORT 345 found_in_cache: 346#endif 347 /* try to look up a cached volume in the cell VL databases by ID */ 348 _debug("found in cache"); 349 350 _debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }", 351 vlocation->vldb.name, 352 vlocation->vldb.vidmask, 353 ntohl(vlocation->vldb.servers[0].s_addr), 354 vlocation->vldb.srvtmask[0], 355 ntohl(vlocation->vldb.servers[1].s_addr), 356 vlocation->vldb.srvtmask[1], 357 ntohl(vlocation->vldb.servers[2].s_addr), 358 vlocation->vldb.srvtmask[2] 359 ); 360 361 _debug("Vids: %08x %08x %08x", 362 vlocation->vldb.vid[0], 363 vlocation->vldb.vid[1], 364 vlocation->vldb.vid[2]); 365 366 if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) { 367 vid = vlocation->vldb.vid[0]; 368 voltype = AFSVL_RWVOL; 369 } 370 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) { 371 vid = vlocation->vldb.vid[1]; 372 voltype = AFSVL_ROVOL; 373 } 374 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) { 375 vid = vlocation->vldb.vid[2]; 376 voltype = AFSVL_BACKVOL; 377 } 378 else { 379 BUG(); 380 vid = 0; 381 voltype = 0; 382 } 383 384 ret = afs_vlocation_access_vl_by_id(vlocation, vid, voltype, &vldb); 385 switch (ret) { 386 /* net error */ 387 default: 388 printk("kAFS: failed to volume '%*.*s' (%x) up in '%s': %d\n", 389 namesz, namesz, name, vid, cell->name, ret); 390 goto error; 391 392 /* pulled from local cache into memory */ 393 case 0: 394 goto found_on_vlserver; 395 396 /* uh oh... looks like the volume got deleted */ 397 case -ENOMEDIUM: 398 printk("kAFS: volume '%*.*s' (%x) does not exist '%s'\n", 399 namesz, namesz, name, vid, cell->name); 400 401 /* TODO: make existing record unavailable */ 402 goto error; 403 } 404 405 found_on_vlserver: 406 _debug("Done VL Lookup: %*.*s %02x { %08x(%x) %08x(%x) %08x(%x) }", 407 namesz, namesz, name, 408 vldb.vidmask, 409 ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0], 410 ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1], 411 ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2] 412 ); 413 414 _debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]); 415 416 if ((namesz < sizeof(vlocation->vldb.name) && 417 vlocation->vldb.name[namesz] != '\0') || 418 memcmp(vldb.name, name, namesz) != 0) 419 printk("kAFS: name of volume '%*.*s' changed to '%s' on server\n", 420 namesz, namesz, name, vldb.name); 421 422 memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb)); 423 424 afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ); 425 426#ifdef AFS_CACHING_SUPPORT 427 /* update volume entry in local cache */ 428 cachefs_update_cookie(vlocation->cache); 429#endif 430 431 *_vlocation = vlocation; 432 _leave(" = 0 (%p)",vlocation); 433 return 0; 434 435 error: 436 if (vlocation) { 437 if (active) { 438 __afs_put_vlocation(vlocation); 439 } 440 else { 441 list_del(&vlocation->link); 442#ifdef AFS_CACHING_SUPPORT 443 cachefs_relinquish_cookie(vlocation->cache, 0); 444#endif 445 afs_put_cell(vlocation->cell); 446 kfree(vlocation); 447 } 448 } 449 450 _leave(" = %d", ret); 451 return ret; 452} /* end afs_vlocation_lookup() */ 453 454/*****************************************************************************/ 455/* 456 * finish using a volume location record 457 * - caller must have cell->vol_sem write-locked 458 */ 459static void __afs_put_vlocation(struct afs_vlocation *vlocation) 460{ 461 struct afs_cell *cell; 462 463 if (!vlocation) 464 return; 465 466 _enter("%s", vlocation->vldb.name); 467 468 cell = vlocation->cell; 469 470 /* sanity check */ 471 BUG_ON(atomic_read(&vlocation->usage) <= 0); 472 473 spin_lock(&cell->vl_gylock); 474 if (likely(!atomic_dec_and_test(&vlocation->usage))) { 475 spin_unlock(&cell->vl_gylock); 476 _leave(""); 477 return; 478 } 479 480 /* move to graveyard queue */ 481 list_del(&vlocation->link); 482 list_add_tail(&vlocation->link,&cell->vl_graveyard); 483 484 /* remove from pending timeout queue (refcounted if actually being 485 * updated) */ 486 list_del_init(&vlocation->upd_op.link); 487 488 /* time out in 10 secs */ 489 afs_kafstimod_del_timer(&vlocation->upd_timer); 490 afs_kafstimod_add_timer(&vlocation->timeout, 10 * HZ); 491 492 spin_unlock(&cell->vl_gylock); 493 494 _leave(" [killed]"); 495} /* end __afs_put_vlocation() */ 496 497/*****************************************************************************/ 498/* 499 * finish using a volume location record 500 */ 501void afs_put_vlocation(struct afs_vlocation *vlocation) 502{ 503 if (vlocation) { 504 struct afs_cell *cell = vlocation->cell; 505 506 down_write(&cell->vl_sem); 507 __afs_put_vlocation(vlocation); 508 up_write(&cell->vl_sem); 509 } 510} /* end afs_put_vlocation() */ 511 512/*****************************************************************************/ 513/* 514 * timeout vlocation record 515 * - removes from the cell's graveyard if the usage count is zero 516 */ 517void afs_vlocation_do_timeout(struct afs_vlocation *vlocation) 518{ 519 struct afs_cell *cell; 520 521 _enter("%s", vlocation->vldb.name); 522 523 cell = vlocation->cell; 524 525 BUG_ON(atomic_read(&vlocation->usage) < 0); 526 527 /* remove from graveyard if still dead */ 528 spin_lock(&cell->vl_gylock); 529 if (atomic_read(&vlocation->usage) == 0) 530 list_del_init(&vlocation->link); 531 else 532 vlocation = NULL; 533 spin_unlock(&cell->vl_gylock); 534 535 if (!vlocation) { 536 _leave(""); 537 return; /* resurrected */ 538 } 539 540 /* we can now destroy it properly */ 541#ifdef AFS_CACHING_SUPPORT 542 cachefs_relinquish_cookie(vlocation->cache, 0); 543#endif 544 afs_put_cell(cell); 545 546 kfree(vlocation); 547 548 _leave(" [destroyed]"); 549} /* end afs_vlocation_do_timeout() */ 550 551/*****************************************************************************/ 552/* 553 * send an update operation to the currently selected server 554 */ 555static int afs_vlocation_update_begin(struct afs_vlocation *vlocation) 556{ 557 afs_voltype_t voltype; 558 afs_volid_t vid; 559 int ret; 560 561 _enter("%s{ufs=%u ucs=%u}", 562 vlocation->vldb.name, 563 vlocation->upd_first_svix, 564 vlocation->upd_curr_svix); 565 566 /* try to look up a cached volume in the cell VL databases by ID */ 567 if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) { 568 vid = vlocation->vldb.vid[0]; 569 voltype = AFSVL_RWVOL; 570 } 571 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) { 572 vid = vlocation->vldb.vid[1]; 573 voltype = AFSVL_ROVOL; 574 } 575 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) { 576 vid = vlocation->vldb.vid[2]; 577 voltype = AFSVL_BACKVOL; 578 } 579 else { 580 BUG(); 581 vid = 0; 582 voltype = 0; 583 } 584 585 /* contact the chosen server */ 586 ret = afs_server_lookup( 587 vlocation->cell, 588 &vlocation->cell->vl_addrs[vlocation->upd_curr_svix], 589 &vlocation->upd_op.server); 590 591 switch (ret) { 592 case 0: 593 break; 594 case -ENOMEM: 595 case -ENONET: 596 default: 597 _leave(" = %d", ret); 598 return ret; 599 } 600 601 /* initiate the update operation */ 602 ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op, vid, voltype); 603 if (ret < 0) { 604 _leave(" = %d", ret); 605 return ret; 606 } 607 608 _leave(" = %d", ret); 609 return ret; 610} /* end afs_vlocation_update_begin() */ 611 612/*****************************************************************************/ 613/* 614 * abandon updating a VL record 615 * - does not restart the update timer 616 */ 617static void afs_vlocation_update_abandon(struct afs_vlocation *vlocation, 618 afs_vlocation_upd_t state, 619 int ret) 620{ 621 _enter("%s,%u", vlocation->vldb.name, state); 622 623 if (ret < 0) 624 printk("kAFS: Abandoning VL update '%s': %d\n", 625 vlocation->vldb.name, ret); 626 627 /* discard the server record */ 628 afs_put_server(vlocation->upd_op.server); 629 vlocation->upd_op.server = NULL; 630 631 spin_lock(&afs_vlocation_update_lock); 632 afs_vlocation_update = NULL; 633 vlocation->upd_state = state; 634 635 /* TODO: start updating next VL record on pending list */ 636 637 spin_unlock(&afs_vlocation_update_lock); 638 639 _leave(""); 640} /* end afs_vlocation_update_abandon() */ 641 642/*****************************************************************************/ 643/* 644 * handle periodic update timeouts and busy retry timeouts 645 * - called from kafstimod 646 */ 647static void afs_vlocation_update_timer(struct afs_timer *timer) 648{ 649 struct afs_vlocation *vlocation = 650 list_entry(timer, struct afs_vlocation, upd_timer); 651 int ret; 652 653 _enter("%s", vlocation->vldb.name); 654 655 /* only update if not in the graveyard (defend against putting too) */ 656 spin_lock(&vlocation->cell->vl_gylock); 657 658 if (!atomic_read(&vlocation->usage)) 659 goto out_unlock1; 660 661 spin_lock(&afs_vlocation_update_lock); 662 663 /* if we were woken up due to EBUSY sleep then restart immediately if 664 * possible or else jump to front of pending queue */ 665 if (vlocation->upd_state == AFS_VLUPD_BUSYSLEEP) { 666 if (afs_vlocation_update) { 667 list_add(&vlocation->upd_op.link, 668 &afs_vlocation_update_pendq); 669 } 670 else { 671 afs_get_vlocation(vlocation); 672 afs_vlocation_update = vlocation; 673 vlocation->upd_state = AFS_VLUPD_INPROGRESS; 674 } 675 goto out_unlock2; 676 } 677 678 /* put on pending queue if there's already another update in progress */ 679 if (afs_vlocation_update) { 680 vlocation->upd_state = AFS_VLUPD_PENDING; 681 list_add_tail(&vlocation->upd_op.link, 682 &afs_vlocation_update_pendq); 683 goto out_unlock2; 684 } 685 686 /* hold a ref on it while actually updating */ 687 afs_get_vlocation(vlocation); 688 afs_vlocation_update = vlocation; 689 vlocation->upd_state = AFS_VLUPD_INPROGRESS; 690 691 spin_unlock(&afs_vlocation_update_lock); 692 spin_unlock(&vlocation->cell->vl_gylock); 693 694 /* okay... we can start the update */ 695 _debug("BEGIN VL UPDATE [%s]", vlocation->vldb.name); 696 vlocation->upd_first_svix = vlocation->cell->vl_curr_svix; 697 vlocation->upd_curr_svix = vlocation->upd_first_svix; 698 vlocation->upd_rej_cnt = 0; 699 vlocation->upd_busy_cnt = 0; 700 701 ret = afs_vlocation_update_begin(vlocation); 702 if (ret < 0) { 703 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret); 704 afs_kafstimod_add_timer(&vlocation->upd_timer, 705 AFS_VLDB_TIMEOUT); 706 afs_put_vlocation(vlocation); 707 } 708 709 _leave(""); 710 return; 711 712 out_unlock2: 713 spin_unlock(&afs_vlocation_update_lock); 714 out_unlock1: 715 spin_unlock(&vlocation->cell->vl_gylock); 716 _leave(""); 717 return; 718 719} /* end afs_vlocation_update_timer() */ 720 721/*****************************************************************************/ 722/* 723 * attend to an update operation upon which an event happened 724 * - called in kafsasyncd context 725 */ 726static void afs_vlocation_update_attend(struct afs_async_op *op) 727{ 728 struct afs_cache_vlocation vldb; 729 struct afs_vlocation *vlocation = 730 list_entry(op, struct afs_vlocation, upd_op); 731 unsigned tmp; 732 int ret; 733 734 _enter("%s", vlocation->vldb.name); 735 736 ret = afs_rxvl_get_entry_by_id_async2(op, &vldb); 737 switch (ret) { 738 case -EAGAIN: 739 _leave(" [unfinished]"); 740 return; 741 742 case 0: 743 _debug("END VL UPDATE: %d\n", ret); 744 vlocation->valid = 1; 745 746 _debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }", 747 vldb.vidmask, 748 ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0], 749 ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1], 750 ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2] 751 ); 752 753 _debug("Vids: %08x %08x %08x", 754 vldb.vid[0], vldb.vid[1], vldb.vid[2]); 755 756 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0); 757 758 down_write(&vlocation->cell->vl_sem); 759 760 /* actually update the cache */ 761 if (strncmp(vldb.name, vlocation->vldb.name, 762 sizeof(vlocation->vldb.name)) != 0) 763 printk("kAFS: name of volume '%s'" 764 " changed to '%s' on server\n", 765 vlocation->vldb.name, vldb.name); 766 767 memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb)); 768 769#if 0 770 /* TODO update volume entry in local cache */ 771#endif 772 773 up_write(&vlocation->cell->vl_sem); 774 775 if (ret < 0) 776 printk("kAFS: failed to update local cache: %d\n", ret); 777 778 afs_kafstimod_add_timer(&vlocation->upd_timer, 779 AFS_VLDB_TIMEOUT); 780 afs_put_vlocation(vlocation); 781 _leave(" [found]"); 782 return; 783 784 case -ENOMEDIUM: 785 vlocation->upd_rej_cnt++; 786 goto try_next; 787 788 /* the server is locked - retry in a very short while */ 789 case -EBUSY: 790 vlocation->upd_busy_cnt++; 791 if (vlocation->upd_busy_cnt > 3) 792 goto try_next; /* too many retries */ 793 794 afs_vlocation_update_abandon(vlocation, 795 AFS_VLUPD_BUSYSLEEP, 0); 796 afs_kafstimod_add_timer(&vlocation->upd_timer, HZ / 2); 797 afs_put_vlocation(vlocation); 798 _leave(" [busy]"); 799 return; 800 801 case -ENETUNREACH: 802 case -EHOSTUNREACH: 803 case -ECONNREFUSED: 804 case -EREMOTEIO: 805 /* record bad vlserver info in the cell too 806 * - TODO: use down_write_trylock() if available 807 */ 808 if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix) 809 vlocation->cell->vl_curr_svix = 810 vlocation->cell->vl_curr_svix % 811 vlocation->cell->vl_naddrs; 812 813 case -EBADRQC: 814 case -EINVAL: 815 case -EACCES: 816 case -EBADMSG: 817 goto try_next; 818 819 default: 820 goto abandon; 821 } 822 823 /* try contacting the next server */ 824 try_next: 825 vlocation->upd_busy_cnt = 0; 826 827 /* discard the server record */ 828 afs_put_server(vlocation->upd_op.server); 829 vlocation->upd_op.server = NULL; 830 831 tmp = vlocation->cell->vl_naddrs; 832 if (tmp == 0) 833 goto abandon; 834 835 vlocation->upd_curr_svix++; 836 if (vlocation->upd_curr_svix >= tmp) 837 vlocation->upd_curr_svix = 0; 838 if (vlocation->upd_first_svix >= tmp) 839 vlocation->upd_first_svix = tmp - 1; 840 841 /* move to the next server */ 842 if (vlocation->upd_curr_svix != vlocation->upd_first_svix) { 843 afs_vlocation_update_begin(vlocation); 844 _leave(" [next]"); 845 return; 846 } 847 848 /* run out of servers to try - was the volume rejected? */ 849 if (vlocation->upd_rej_cnt > 0) { 850 printk("kAFS: Active volume no longer valid '%s'\n", 851 vlocation->vldb.name); 852 vlocation->valid = 0; 853 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0); 854 afs_kafstimod_add_timer(&vlocation->upd_timer, 855 AFS_VLDB_TIMEOUT); 856 afs_put_vlocation(vlocation); 857 _leave(" [invalidated]"); 858 return; 859 } 860 861 /* abandon the update */ 862 abandon: 863 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret); 864 afs_kafstimod_add_timer(&vlocation->upd_timer, HZ * 10); 865 afs_put_vlocation(vlocation); 866 _leave(" [abandoned]"); 867 868} /* end afs_vlocation_update_attend() */ 869 870/*****************************************************************************/ 871/* 872 * deal with an update operation being discarded 873 * - called in kafsasyncd context when it's dying due to rmmod 874 * - the call has already been aborted and put()'d 875 */ 876static void afs_vlocation_update_discard(struct afs_async_op *op) 877{ 878 struct afs_vlocation *vlocation = 879 list_entry(op, struct afs_vlocation, upd_op); 880 881 _enter("%s", vlocation->vldb.name); 882 883 afs_put_server(op->server); 884 op->server = NULL; 885 886 afs_put_vlocation(vlocation); 887 888 _leave(""); 889} /* end afs_vlocation_update_discard() */ 890 891/*****************************************************************************/ 892/* 893 * match a VLDB record stored in the cache 894 * - may also load target from entry 895 */ 896#ifdef AFS_CACHING_SUPPORT 897static cachefs_match_val_t afs_vlocation_cache_match(void *target, 898 const void *entry) 899{ 900 const struct afs_cache_vlocation *vldb = entry; 901 struct afs_vlocation *vlocation = target; 902 903 _enter("{%s},{%s}", vlocation->vldb.name, vldb->name); 904 905 if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0 906 ) { 907 if (!vlocation->valid || 908 vlocation->vldb.rtime == vldb->rtime 909 ) { 910 vlocation->vldb = *vldb; 911 vlocation->valid = 1; 912 _leave(" = SUCCESS [c->m]"); 913 return CACHEFS_MATCH_SUCCESS; 914 } 915 /* need to update cache if cached info differs */ 916 else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) { 917 /* delete if VIDs for this name differ */ 918 if (memcmp(&vlocation->vldb.vid, 919 &vldb->vid, 920 sizeof(vldb->vid)) != 0) { 921 _leave(" = DELETE"); 922 return CACHEFS_MATCH_SUCCESS_DELETE; 923 } 924 925 _leave(" = UPDATE"); 926 return CACHEFS_MATCH_SUCCESS_UPDATE; 927 } 928 else { 929 _leave(" = SUCCESS"); 930 return CACHEFS_MATCH_SUCCESS; 931 } 932 } 933 934 _leave(" = FAILED"); 935 return CACHEFS_MATCH_FAILED; 936} /* end afs_vlocation_cache_match() */ 937#endif 938 939/*****************************************************************************/ 940/* 941 * update a VLDB record stored in the cache 942 */ 943#ifdef AFS_CACHING_SUPPORT 944static void afs_vlocation_cache_update(void *source, void *entry) 945{ 946 struct afs_cache_vlocation *vldb = entry; 947 struct afs_vlocation *vlocation = source; 948 949 _enter(""); 950 951 *vldb = vlocation->vldb; 952 953} /* end afs_vlocation_cache_update() */ 954#endif