linux/fs/afs/vnode.c
<<
>>
Prefs
   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