at v2.6.26 1026 lines 25 kB view raw
1/* AFS vnode management 2 * 3 * Copyright (C) 2002, 2007 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/sched.h> 18#include "internal.h" 19 20#if 0 21static noinline bool dump_tree_aux(struct rb_node *node, struct rb_node *parent, 22 int depth, char lr) 23{ 24 struct afs_vnode *vnode; 25 bool bad = false; 26 27 if (!node) 28 return false; 29 30 if (node->rb_left) 31 bad = dump_tree_aux(node->rb_left, node, depth + 2, '/'); 32 33 vnode = rb_entry(node, struct afs_vnode, cb_promise); 34 _debug("%c %*.*s%c%p {%d}", 35 rb_is_red(node) ? 'R' : 'B', 36 depth, depth, "", lr, 37 vnode, vnode->cb_expires_at); 38 if (rb_parent(node) != parent) { 39 printk("BAD: %p != %p\n", rb_parent(node), parent); 40 bad = true; 41 } 42 43 if (node->rb_right) 44 bad |= dump_tree_aux(node->rb_right, node, depth + 2, '\\'); 45 46 return bad; 47} 48 49static noinline void dump_tree(const char *name, struct afs_server *server) 50{ 51 _enter("%s", name); 52 if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-')) 53 BUG(); 54} 55#endif 56 57/* 58 * insert a vnode into the backing server's vnode tree 59 */ 60static void afs_install_vnode(struct afs_vnode *vnode, 61 struct afs_server *server) 62{ 63 struct afs_server *old_server = vnode->server; 64 struct afs_vnode *xvnode; 65 struct rb_node *parent, **p; 66 67 _enter("%p,%p", vnode, server); 68 69 if (old_server) { 70 spin_lock(&old_server->fs_lock); 71 rb_erase(&vnode->server_rb, &old_server->fs_vnodes); 72 spin_unlock(&old_server->fs_lock); 73 } 74 75 afs_get_server(server); 76 vnode->server = server; 77 afs_put_server(old_server); 78 79 /* insert into the server's vnode tree in FID order */ 80 spin_lock(&server->fs_lock); 81 82 parent = NULL; 83 p = &server->fs_vnodes.rb_node; 84 while (*p) { 85 parent = *p; 86 xvnode = rb_entry(parent, struct afs_vnode, server_rb); 87 if (vnode->fid.vid < xvnode->fid.vid) 88 p = &(*p)->rb_left; 89 else if (vnode->fid.vid > xvnode->fid.vid) 90 p = &(*p)->rb_right; 91 else if (vnode->fid.vnode < xvnode->fid.vnode) 92 p = &(*p)->rb_left; 93 else if (vnode->fid.vnode > xvnode->fid.vnode) 94 p = &(*p)->rb_right; 95 else if (vnode->fid.unique < xvnode->fid.unique) 96 p = &(*p)->rb_left; 97 else if (vnode->fid.unique > xvnode->fid.unique) 98 p = &(*p)->rb_right; 99 else 100 BUG(); /* can't happen unless afs_iget() malfunctions */ 101 } 102 103 rb_link_node(&vnode->server_rb, parent, p); 104 rb_insert_color(&vnode->server_rb, &server->fs_vnodes); 105 106 spin_unlock(&server->fs_lock); 107 _leave(""); 108} 109 110/* 111 * insert a vnode into the promising server's update/expiration tree 112 * - caller must hold vnode->lock 113 */ 114static void afs_vnode_note_promise(struct afs_vnode *vnode, 115 struct afs_server *server) 116{ 117 struct afs_server *old_server; 118 struct afs_vnode *xvnode; 119 struct rb_node *parent, **p; 120 121 _enter("%p,%p", vnode, server); 122 123 ASSERT(server != NULL); 124 125 old_server = vnode->server; 126 if (vnode->cb_promised) { 127 if (server == old_server && 128 vnode->cb_expires == vnode->cb_expires_at) { 129 _leave(" [no change]"); 130 return; 131 } 132 133 spin_lock(&old_server->cb_lock); 134 if (vnode->cb_promised) { 135 _debug("delete"); 136 rb_erase(&vnode->cb_promise, &old_server->cb_promises); 137 vnode->cb_promised = false; 138 } 139 spin_unlock(&old_server->cb_lock); 140 } 141 142 if (vnode->server != server) 143 afs_install_vnode(vnode, server); 144 145 vnode->cb_expires_at = vnode->cb_expires; 146 _debug("PROMISE on %p {%lu}", 147 vnode, (unsigned long) vnode->cb_expires_at); 148 149 /* abuse an RB-tree to hold the expiration order (we may have multiple 150 * items with the same expiration time) */ 151 spin_lock(&server->cb_lock); 152 153 parent = NULL; 154 p = &server->cb_promises.rb_node; 155 while (*p) { 156 parent = *p; 157 xvnode = rb_entry(parent, struct afs_vnode, cb_promise); 158 if (vnode->cb_expires_at < xvnode->cb_expires_at) 159 p = &(*p)->rb_left; 160 else 161 p = &(*p)->rb_right; 162 } 163 164 rb_link_node(&vnode->cb_promise, parent, p); 165 rb_insert_color(&vnode->cb_promise, &server->cb_promises); 166 vnode->cb_promised = true; 167 168 spin_unlock(&server->cb_lock); 169 _leave(""); 170} 171 172/* 173 * handle remote file deletion by discarding the callback promise 174 */ 175static void afs_vnode_deleted_remotely(struct afs_vnode *vnode) 176{ 177 struct afs_server *server; 178 179 _enter("{%p}", vnode->server); 180 181 set_bit(AFS_VNODE_DELETED, &vnode->flags); 182 183 server = vnode->server; 184 if (server) { 185 if (vnode->cb_promised) { 186 spin_lock(&server->cb_lock); 187 if (vnode->cb_promised) { 188 rb_erase(&vnode->cb_promise, 189 &server->cb_promises); 190 vnode->cb_promised = false; 191 } 192 spin_unlock(&server->cb_lock); 193 } 194 195 spin_lock(&server->fs_lock); 196 rb_erase(&vnode->server_rb, &server->fs_vnodes); 197 spin_unlock(&server->fs_lock); 198 199 vnode->server = NULL; 200 afs_put_server(server); 201 } else { 202 ASSERT(!vnode->cb_promised); 203 } 204 205 _leave(""); 206} 207 208/* 209 * finish off updating the recorded status of a file after a successful 210 * operation completion 211 * - starts callback expiry timer 212 * - adds to server's callback list 213 */ 214void afs_vnode_finalise_status_update(struct afs_vnode *vnode, 215 struct afs_server *server) 216{ 217 struct afs_server *oldserver = NULL; 218 219 _enter("%p,%p", vnode, server); 220 221 spin_lock(&vnode->lock); 222 clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); 223 afs_vnode_note_promise(vnode, server); 224 vnode->update_cnt--; 225 ASSERTCMP(vnode->update_cnt, >=, 0); 226 spin_unlock(&vnode->lock); 227 228 wake_up_all(&vnode->update_waitq); 229 afs_put_server(oldserver); 230 _leave(""); 231} 232 233/* 234 * finish off updating the recorded status of a file after an operation failed 235 */ 236static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret) 237{ 238 _enter("{%x:%u},%d", vnode->fid.vid, vnode->fid.vnode, ret); 239 240 spin_lock(&vnode->lock); 241 242 clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); 243 244 if (ret == -ENOENT) { 245 /* the file was deleted on the server */ 246 _debug("got NOENT from server - marking file deleted"); 247 afs_vnode_deleted_remotely(vnode); 248 } 249 250 vnode->update_cnt--; 251 ASSERTCMP(vnode->update_cnt, >=, 0); 252 spin_unlock(&vnode->lock); 253 254 wake_up_all(&vnode->update_waitq); 255 _leave(""); 256} 257 258/* 259 * fetch file status from the volume 260 * - don't issue a fetch if: 261 * - the changed bit is not set and there's a valid callback 262 * - there are any outstanding ops that will fetch the status 263 * - TODO implement local caching 264 */ 265int afs_vnode_fetch_status(struct afs_vnode *vnode, 266 struct afs_vnode *auth_vnode, struct key *key) 267{ 268 struct afs_server *server; 269 unsigned long acl_order; 270 int ret; 271 272 DECLARE_WAITQUEUE(myself, current); 273 274 _enter("%s,{%x:%u.%u}", 275 vnode->volume->vlocation->vldb.name, 276 vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); 277 278 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && 279 vnode->cb_promised) { 280 _leave(" [unchanged]"); 281 return 0; 282 } 283 284 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 285 _leave(" [deleted]"); 286 return -ENOENT; 287 } 288 289 acl_order = 0; 290 if (auth_vnode) 291 acl_order = auth_vnode->acl_order; 292 293 spin_lock(&vnode->lock); 294 295 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) && 296 vnode->cb_promised) { 297 spin_unlock(&vnode->lock); 298 _leave(" [unchanged]"); 299 return 0; 300 } 301 302 ASSERTCMP(vnode->update_cnt, >=, 0); 303 304 if (vnode->update_cnt > 0) { 305 /* someone else started a fetch */ 306 _debug("wait on fetch %d", vnode->update_cnt); 307 308 set_current_state(TASK_UNINTERRUPTIBLE); 309 ASSERT(myself.func != NULL); 310 add_wait_queue(&vnode->update_waitq, &myself); 311 312 /* wait for the status to be updated */ 313 for (;;) { 314 if (!test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) 315 break; 316 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 317 break; 318 319 /* check to see if it got updated and invalidated all 320 * before we saw it */ 321 if (vnode->update_cnt == 0) { 322 remove_wait_queue(&vnode->update_waitq, 323 &myself); 324 set_current_state(TASK_RUNNING); 325 goto get_anyway; 326 } 327 328 spin_unlock(&vnode->lock); 329 330 schedule(); 331 set_current_state(TASK_UNINTERRUPTIBLE); 332 333 spin_lock(&vnode->lock); 334 } 335 336 remove_wait_queue(&vnode->update_waitq, &myself); 337 spin_unlock(&vnode->lock); 338 set_current_state(TASK_RUNNING); 339 340 return test_bit(AFS_VNODE_DELETED, &vnode->flags) ? 341 -ENOENT : 0; 342 } 343 344get_anyway: 345 /* okay... we're going to have to initiate the op */ 346 vnode->update_cnt++; 347 348 spin_unlock(&vnode->lock); 349 350 /* merge AFS status fetches and clear outstanding callback on this 351 * vnode */ 352 do { 353 /* pick a server to query */ 354 server = afs_volume_pick_fileserver(vnode); 355 if (IS_ERR(server)) 356 goto no_server; 357 358 _debug("USING SERVER: %p{%08x}", 359 server, ntohl(server->addr.s_addr)); 360 361 ret = afs_fs_fetch_file_status(server, key, vnode, NULL, 362 &afs_sync_call); 363 364 } while (!afs_volume_release_fileserver(vnode, server, ret)); 365 366 /* adjust the flags */ 367 if (ret == 0) { 368 _debug("adjust"); 369 if (auth_vnode) 370 afs_cache_permit(vnode, key, acl_order); 371 afs_vnode_finalise_status_update(vnode, server); 372 afs_put_server(server); 373 } else { 374 _debug("failed [%d]", ret); 375 afs_vnode_status_update_failed(vnode, ret); 376 } 377 378 ASSERTCMP(vnode->update_cnt, >=, 0); 379 380 _leave(" = %d [cnt %d]", ret, vnode->update_cnt); 381 return ret; 382 383no_server: 384 spin_lock(&vnode->lock); 385 vnode->update_cnt--; 386 ASSERTCMP(vnode->update_cnt, >=, 0); 387 spin_unlock(&vnode->lock); 388 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); 389 return PTR_ERR(server); 390} 391 392/* 393 * fetch file data from the volume 394 * - TODO implement caching 395 */ 396int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, 397 off_t offset, size_t length, struct page *page) 398{ 399 struct afs_server *server; 400 int ret; 401 402 _enter("%s{%x:%u.%u},%x,,,", 403 vnode->volume->vlocation->vldb.name, 404 vnode->fid.vid, 405 vnode->fid.vnode, 406 vnode->fid.unique, 407 key_serial(key)); 408 409 /* this op will fetch the status */ 410 spin_lock(&vnode->lock); 411 vnode->update_cnt++; 412 spin_unlock(&vnode->lock); 413 414 /* merge in AFS status fetches and clear outstanding callback on this 415 * vnode */ 416 do { 417 /* pick a server to query */ 418 server = afs_volume_pick_fileserver(vnode); 419 if (IS_ERR(server)) 420 goto no_server; 421 422 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 423 424 ret = afs_fs_fetch_data(server, key, vnode, offset, length, 425 page, &afs_sync_call); 426 427 } while (!afs_volume_release_fileserver(vnode, server, ret)); 428 429 /* adjust the flags */ 430 if (ret == 0) { 431 afs_vnode_finalise_status_update(vnode, server); 432 afs_put_server(server); 433 } else { 434 afs_vnode_status_update_failed(vnode, ret); 435 } 436 437 _leave(" = %d", ret); 438 return ret; 439 440no_server: 441 spin_lock(&vnode->lock); 442 vnode->update_cnt--; 443 ASSERTCMP(vnode->update_cnt, >=, 0); 444 spin_unlock(&vnode->lock); 445 return PTR_ERR(server); 446} 447 448/* 449 * make a file or a directory 450 */ 451int afs_vnode_create(struct afs_vnode *vnode, struct key *key, 452 const char *name, umode_t mode, struct afs_fid *newfid, 453 struct afs_file_status *newstatus, 454 struct afs_callback *newcb, struct afs_server **_server) 455{ 456 struct afs_server *server; 457 int ret; 458 459 _enter("%s{%x:%u.%u},%x,%s,,", 460 vnode->volume->vlocation->vldb.name, 461 vnode->fid.vid, 462 vnode->fid.vnode, 463 vnode->fid.unique, 464 key_serial(key), 465 name); 466 467 /* this op will fetch the status on the directory we're creating in */ 468 spin_lock(&vnode->lock); 469 vnode->update_cnt++; 470 spin_unlock(&vnode->lock); 471 472 do { 473 /* pick a server to query */ 474 server = afs_volume_pick_fileserver(vnode); 475 if (IS_ERR(server)) 476 goto no_server; 477 478 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 479 480 ret = afs_fs_create(server, key, vnode, name, mode, newfid, 481 newstatus, newcb, &afs_sync_call); 482 483 } while (!afs_volume_release_fileserver(vnode, server, ret)); 484 485 /* adjust the flags */ 486 if (ret == 0) { 487 afs_vnode_finalise_status_update(vnode, server); 488 *_server = server; 489 } else { 490 afs_vnode_status_update_failed(vnode, ret); 491 *_server = NULL; 492 } 493 494 _leave(" = %d [cnt %d]", ret, vnode->update_cnt); 495 return ret; 496 497no_server: 498 spin_lock(&vnode->lock); 499 vnode->update_cnt--; 500 ASSERTCMP(vnode->update_cnt, >=, 0); 501 spin_unlock(&vnode->lock); 502 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); 503 return PTR_ERR(server); 504} 505 506/* 507 * remove a file or directory 508 */ 509int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name, 510 bool isdir) 511{ 512 struct afs_server *server; 513 int ret; 514 515 _enter("%s{%x:%u.%u},%x,%s", 516 vnode->volume->vlocation->vldb.name, 517 vnode->fid.vid, 518 vnode->fid.vnode, 519 vnode->fid.unique, 520 key_serial(key), 521 name); 522 523 /* this op will fetch the status on the directory we're removing from */ 524 spin_lock(&vnode->lock); 525 vnode->update_cnt++; 526 spin_unlock(&vnode->lock); 527 528 do { 529 /* pick a server to query */ 530 server = afs_volume_pick_fileserver(vnode); 531 if (IS_ERR(server)) 532 goto no_server; 533 534 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 535 536 ret = afs_fs_remove(server, key, vnode, name, isdir, 537 &afs_sync_call); 538 539 } while (!afs_volume_release_fileserver(vnode, server, ret)); 540 541 /* adjust the flags */ 542 if (ret == 0) { 543 afs_vnode_finalise_status_update(vnode, server); 544 afs_put_server(server); 545 } else { 546 afs_vnode_status_update_failed(vnode, ret); 547 } 548 549 _leave(" = %d [cnt %d]", ret, vnode->update_cnt); 550 return ret; 551 552no_server: 553 spin_lock(&vnode->lock); 554 vnode->update_cnt--; 555 ASSERTCMP(vnode->update_cnt, >=, 0); 556 spin_unlock(&vnode->lock); 557 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); 558 return PTR_ERR(server); 559} 560 561/* 562 * create a hard link 563 */ 564int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode, 565 struct key *key, const char *name) 566{ 567 struct afs_server *server; 568 int ret; 569 570 _enter("%s{%x:%u.%u},%s{%x:%u.%u},%x,%s", 571 dvnode->volume->vlocation->vldb.name, 572 dvnode->fid.vid, 573 dvnode->fid.vnode, 574 dvnode->fid.unique, 575 vnode->volume->vlocation->vldb.name, 576 vnode->fid.vid, 577 vnode->fid.vnode, 578 vnode->fid.unique, 579 key_serial(key), 580 name); 581 582 /* this op will fetch the status on the directory we're removing from */ 583 spin_lock(&vnode->lock); 584 vnode->update_cnt++; 585 spin_unlock(&vnode->lock); 586 spin_lock(&dvnode->lock); 587 dvnode->update_cnt++; 588 spin_unlock(&dvnode->lock); 589 590 do { 591 /* pick a server to query */ 592 server = afs_volume_pick_fileserver(dvnode); 593 if (IS_ERR(server)) 594 goto no_server; 595 596 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 597 598 ret = afs_fs_link(server, key, dvnode, vnode, name, 599 &afs_sync_call); 600 601 } while (!afs_volume_release_fileserver(dvnode, server, ret)); 602 603 /* adjust the flags */ 604 if (ret == 0) { 605 afs_vnode_finalise_status_update(vnode, server); 606 afs_vnode_finalise_status_update(dvnode, server); 607 afs_put_server(server); 608 } else { 609 afs_vnode_status_update_failed(vnode, ret); 610 afs_vnode_status_update_failed(dvnode, ret); 611 } 612 613 _leave(" = %d [cnt %d]", ret, vnode->update_cnt); 614 return ret; 615 616no_server: 617 spin_lock(&vnode->lock); 618 vnode->update_cnt--; 619 ASSERTCMP(vnode->update_cnt, >=, 0); 620 spin_unlock(&vnode->lock); 621 spin_lock(&dvnode->lock); 622 dvnode->update_cnt--; 623 ASSERTCMP(dvnode->update_cnt, >=, 0); 624 spin_unlock(&dvnode->lock); 625 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); 626 return PTR_ERR(server); 627} 628 629/* 630 * create a symbolic link 631 */ 632int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key, 633 const char *name, const char *content, 634 struct afs_fid *newfid, 635 struct afs_file_status *newstatus, 636 struct afs_server **_server) 637{ 638 struct afs_server *server; 639 int ret; 640 641 _enter("%s{%x:%u.%u},%x,%s,%s,,,", 642 vnode->volume->vlocation->vldb.name, 643 vnode->fid.vid, 644 vnode->fid.vnode, 645 vnode->fid.unique, 646 key_serial(key), 647 name, content); 648 649 /* this op will fetch the status on the directory we're creating in */ 650 spin_lock(&vnode->lock); 651 vnode->update_cnt++; 652 spin_unlock(&vnode->lock); 653 654 do { 655 /* pick a server to query */ 656 server = afs_volume_pick_fileserver(vnode); 657 if (IS_ERR(server)) 658 goto no_server; 659 660 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 661 662 ret = afs_fs_symlink(server, key, vnode, name, content, 663 newfid, newstatus, &afs_sync_call); 664 665 } while (!afs_volume_release_fileserver(vnode, server, ret)); 666 667 /* adjust the flags */ 668 if (ret == 0) { 669 afs_vnode_finalise_status_update(vnode, server); 670 *_server = server; 671 } else { 672 afs_vnode_status_update_failed(vnode, ret); 673 *_server = NULL; 674 } 675 676 _leave(" = %d [cnt %d]", ret, vnode->update_cnt); 677 return ret; 678 679no_server: 680 spin_lock(&vnode->lock); 681 vnode->update_cnt--; 682 ASSERTCMP(vnode->update_cnt, >=, 0); 683 spin_unlock(&vnode->lock); 684 _leave(" = %ld [cnt %d]", PTR_ERR(server), vnode->update_cnt); 685 return PTR_ERR(server); 686} 687 688/* 689 * rename a file 690 */ 691int afs_vnode_rename(struct afs_vnode *orig_dvnode, 692 struct afs_vnode *new_dvnode, 693 struct key *key, 694 const char *orig_name, 695 const char *new_name) 696{ 697 struct afs_server *server; 698 int ret; 699 700 _enter("%s{%x:%u.%u},%s{%u,%u,%u},%x,%s,%s", 701 orig_dvnode->volume->vlocation->vldb.name, 702 orig_dvnode->fid.vid, 703 orig_dvnode->fid.vnode, 704 orig_dvnode->fid.unique, 705 new_dvnode->volume->vlocation->vldb.name, 706 new_dvnode->fid.vid, 707 new_dvnode->fid.vnode, 708 new_dvnode->fid.unique, 709 key_serial(key), 710 orig_name, 711 new_name); 712 713 /* this op will fetch the status on both the directories we're dealing 714 * with */ 715 spin_lock(&orig_dvnode->lock); 716 orig_dvnode->update_cnt++; 717 spin_unlock(&orig_dvnode->lock); 718 if (new_dvnode != orig_dvnode) { 719 spin_lock(&new_dvnode->lock); 720 new_dvnode->update_cnt++; 721 spin_unlock(&new_dvnode->lock); 722 } 723 724 do { 725 /* pick a server to query */ 726 server = afs_volume_pick_fileserver(orig_dvnode); 727 if (IS_ERR(server)) 728 goto no_server; 729 730 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 731 732 ret = afs_fs_rename(server, key, orig_dvnode, orig_name, 733 new_dvnode, new_name, &afs_sync_call); 734 735 } while (!afs_volume_release_fileserver(orig_dvnode, server, ret)); 736 737 /* adjust the flags */ 738 if (ret == 0) { 739 afs_vnode_finalise_status_update(orig_dvnode, server); 740 if (new_dvnode != orig_dvnode) 741 afs_vnode_finalise_status_update(new_dvnode, server); 742 afs_put_server(server); 743 } else { 744 afs_vnode_status_update_failed(orig_dvnode, ret); 745 if (new_dvnode != orig_dvnode) 746 afs_vnode_status_update_failed(new_dvnode, ret); 747 } 748 749 _leave(" = %d [cnt %d]", ret, orig_dvnode->update_cnt); 750 return ret; 751 752no_server: 753 spin_lock(&orig_dvnode->lock); 754 orig_dvnode->update_cnt--; 755 ASSERTCMP(orig_dvnode->update_cnt, >=, 0); 756 spin_unlock(&orig_dvnode->lock); 757 if (new_dvnode != orig_dvnode) { 758 spin_lock(&new_dvnode->lock); 759 new_dvnode->update_cnt--; 760 ASSERTCMP(new_dvnode->update_cnt, >=, 0); 761 spin_unlock(&new_dvnode->lock); 762 } 763 _leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt); 764 return PTR_ERR(server); 765} 766 767/* 768 * write to a file 769 */ 770int afs_vnode_store_data(struct afs_writeback *wb, pgoff_t first, pgoff_t last, 771 unsigned offset, unsigned to) 772{ 773 struct afs_server *server; 774 struct afs_vnode *vnode = wb->vnode; 775 int ret; 776 777 _enter("%s{%x:%u.%u},%x,%lx,%lx,%x,%x", 778 vnode->volume->vlocation->vldb.name, 779 vnode->fid.vid, 780 vnode->fid.vnode, 781 vnode->fid.unique, 782 key_serial(wb->key), 783 first, last, offset, to); 784 785 /* this op will fetch the status */ 786 spin_lock(&vnode->lock); 787 vnode->update_cnt++; 788 spin_unlock(&vnode->lock); 789 790 do { 791 /* pick a server to query */ 792 server = afs_volume_pick_fileserver(vnode); 793 if (IS_ERR(server)) 794 goto no_server; 795 796 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 797 798 ret = afs_fs_store_data(server, wb, first, last, offset, to, 799 &afs_sync_call); 800 801 } while (!afs_volume_release_fileserver(vnode, server, ret)); 802 803 /* adjust the flags */ 804 if (ret == 0) { 805 afs_vnode_finalise_status_update(vnode, server); 806 afs_put_server(server); 807 } else { 808 afs_vnode_status_update_failed(vnode, ret); 809 } 810 811 _leave(" = %d", ret); 812 return ret; 813 814no_server: 815 spin_lock(&vnode->lock); 816 vnode->update_cnt--; 817 ASSERTCMP(vnode->update_cnt, >=, 0); 818 spin_unlock(&vnode->lock); 819 return PTR_ERR(server); 820} 821 822/* 823 * set the attributes on a file 824 */ 825int afs_vnode_setattr(struct afs_vnode *vnode, struct key *key, 826 struct iattr *attr) 827{ 828 struct afs_server *server; 829 int ret; 830 831 _enter("%s{%x:%u.%u},%x", 832 vnode->volume->vlocation->vldb.name, 833 vnode->fid.vid, 834 vnode->fid.vnode, 835 vnode->fid.unique, 836 key_serial(key)); 837 838 /* this op will fetch the status */ 839 spin_lock(&vnode->lock); 840 vnode->update_cnt++; 841 spin_unlock(&vnode->lock); 842 843 do { 844 /* pick a server to query */ 845 server = afs_volume_pick_fileserver(vnode); 846 if (IS_ERR(server)) 847 goto no_server; 848 849 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 850 851 ret = afs_fs_setattr(server, key, vnode, attr, &afs_sync_call); 852 853 } while (!afs_volume_release_fileserver(vnode, server, ret)); 854 855 /* adjust the flags */ 856 if (ret == 0) { 857 afs_vnode_finalise_status_update(vnode, server); 858 afs_put_server(server); 859 } else { 860 afs_vnode_status_update_failed(vnode, ret); 861 } 862 863 _leave(" = %d", ret); 864 return ret; 865 866no_server: 867 spin_lock(&vnode->lock); 868 vnode->update_cnt--; 869 ASSERTCMP(vnode->update_cnt, >=, 0); 870 spin_unlock(&vnode->lock); 871 return PTR_ERR(server); 872} 873 874/* 875 * get the status of a volume 876 */ 877int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key, 878 struct afs_volume_status *vs) 879{ 880 struct afs_server *server; 881 int ret; 882 883 _enter("%s{%x:%u.%u},%x,", 884 vnode->volume->vlocation->vldb.name, 885 vnode->fid.vid, 886 vnode->fid.vnode, 887 vnode->fid.unique, 888 key_serial(key)); 889 890 do { 891 /* pick a server to query */ 892 server = afs_volume_pick_fileserver(vnode); 893 if (IS_ERR(server)) 894 goto no_server; 895 896 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 897 898 ret = afs_fs_get_volume_status(server, key, vnode, vs, &afs_sync_call); 899 900 } while (!afs_volume_release_fileserver(vnode, server, ret)); 901 902 /* adjust the flags */ 903 if (ret == 0) 904 afs_put_server(server); 905 906 _leave(" = %d", ret); 907 return ret; 908 909no_server: 910 return PTR_ERR(server); 911} 912 913/* 914 * get a lock on a file 915 */ 916int afs_vnode_set_lock(struct afs_vnode *vnode, struct key *key, 917 afs_lock_type_t type) 918{ 919 struct afs_server *server; 920 int ret; 921 922 _enter("%s{%x:%u.%u},%x,%u", 923 vnode->volume->vlocation->vldb.name, 924 vnode->fid.vid, 925 vnode->fid.vnode, 926 vnode->fid.unique, 927 key_serial(key), type); 928 929 do { 930 /* pick a server to query */ 931 server = afs_volume_pick_fileserver(vnode); 932 if (IS_ERR(server)) 933 goto no_server; 934 935 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 936 937 ret = afs_fs_set_lock(server, key, vnode, type, &afs_sync_call); 938 939 } while (!afs_volume_release_fileserver(vnode, server, ret)); 940 941 /* adjust the flags */ 942 if (ret == 0) 943 afs_put_server(server); 944 945 _leave(" = %d", ret); 946 return ret; 947 948no_server: 949 return PTR_ERR(server); 950} 951 952/* 953 * extend a lock on a file 954 */ 955int afs_vnode_extend_lock(struct afs_vnode *vnode, struct key *key) 956{ 957 struct afs_server *server; 958 int ret; 959 960 _enter("%s{%x:%u.%u},%x", 961 vnode->volume->vlocation->vldb.name, 962 vnode->fid.vid, 963 vnode->fid.vnode, 964 vnode->fid.unique, 965 key_serial(key)); 966 967 do { 968 /* pick a server to query */ 969 server = afs_volume_pick_fileserver(vnode); 970 if (IS_ERR(server)) 971 goto no_server; 972 973 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 974 975 ret = afs_fs_extend_lock(server, key, vnode, &afs_sync_call); 976 977 } while (!afs_volume_release_fileserver(vnode, server, ret)); 978 979 /* adjust the flags */ 980 if (ret == 0) 981 afs_put_server(server); 982 983 _leave(" = %d", ret); 984 return ret; 985 986no_server: 987 return PTR_ERR(server); 988} 989 990/* 991 * release a lock on a file 992 */ 993int afs_vnode_release_lock(struct afs_vnode *vnode, struct key *key) 994{ 995 struct afs_server *server; 996 int ret; 997 998 _enter("%s{%x:%u.%u},%x", 999 vnode->volume->vlocation->vldb.name, 1000 vnode->fid.vid, 1001 vnode->fid.vnode, 1002 vnode->fid.unique, 1003 key_serial(key)); 1004 1005 do { 1006 /* pick a server to query */ 1007 server = afs_volume_pick_fileserver(vnode); 1008 if (IS_ERR(server)) 1009 goto no_server; 1010 1011 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 1012 1013 ret = afs_fs_release_lock(server, key, vnode, &afs_sync_call); 1014 1015 } while (!afs_volume_release_fileserver(vnode, server, ret)); 1016 1017 /* adjust the flags */ 1018 if (ret == 0) 1019 afs_put_server(server); 1020 1021 _leave(" = %d", ret); 1022 return ret; 1023 1024no_server: 1025 return PTR_ERR(server); 1026}