• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
21 static 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 
49 static 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  */
afs_install_vnode(struct afs_vnode * vnode,struct afs_server * server)60 static 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  */
afs_vnode_note_promise(struct afs_vnode * vnode,struct afs_server * server)114 static 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  */
afs_vnode_deleted_remotely(struct afs_vnode * vnode)175 static 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  */
afs_vnode_finalise_status_update(struct afs_vnode * vnode,struct afs_server * server)214 void 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  */
afs_vnode_status_update_failed(struct afs_vnode * vnode,int ret)236 static 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  */
afs_vnode_fetch_status(struct afs_vnode * vnode,struct afs_vnode * auth_vnode,struct key * key)265 int 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 
344 get_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 
383 no_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  */
afs_vnode_fetch_data(struct afs_vnode * vnode,struct key * key,off_t offset,size_t length,struct page * page)396 int 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 
440 no_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  */
afs_vnode_create(struct afs_vnode * vnode,struct key * key,const char * name,umode_t mode,struct afs_fid * newfid,struct afs_file_status * newstatus,struct afs_callback * newcb,struct afs_server ** _server)451 int 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 
497 no_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  */
afs_vnode_remove(struct afs_vnode * vnode,struct key * key,const char * name,bool isdir)509 int 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 
552 no_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  */
afs_vnode_link(struct afs_vnode * dvnode,struct afs_vnode * vnode,struct key * key,const char * name)564 int 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 
616 no_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  */
afs_vnode_symlink(struct afs_vnode * vnode,struct key * key,const char * name,const char * content,struct afs_fid * newfid,struct afs_file_status * newstatus,struct afs_server ** _server)632 int 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 
679 no_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  */
afs_vnode_rename(struct afs_vnode * orig_dvnode,struct afs_vnode * new_dvnode,struct key * key,const char * orig_name,const char * new_name)691 int 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 
752 no_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  */
afs_vnode_store_data(struct afs_writeback * wb,pgoff_t first,pgoff_t last,unsigned offset,unsigned to)770 int 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 
814 no_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  */
afs_vnode_setattr(struct afs_vnode * vnode,struct key * key,struct iattr * attr)825 int 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 
866 no_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  */
afs_vnode_get_volume_status(struct afs_vnode * vnode,struct key * key,struct afs_volume_status * vs)877 int 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 
909 no_server:
910 	return PTR_ERR(server);
911 }
912 
913 /*
914  * get a lock on a file
915  */
afs_vnode_set_lock(struct afs_vnode * vnode,struct key * key,afs_lock_type_t type)916 int 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 
948 no_server:
949 	return PTR_ERR(server);
950 }
951 
952 /*
953  * extend a lock on a file
954  */
afs_vnode_extend_lock(struct afs_vnode * vnode,struct key * key)955 int 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 
986 no_server:
987 	return PTR_ERR(server);
988 }
989 
990 /*
991  * release a lock on a file
992  */
afs_vnode_release_lock(struct afs_vnode * vnode,struct key * key)993 int 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 
1024 no_server:
1025 	return PTR_ERR(server);
1026 }
1027