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