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