Linux Audio

Check our new training course

Loading...
   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}