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/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}
1027