1 /* AFS vnode management
3 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/slab.h>
20 static noinline
bool dump_tree_aux(struct rb_node
*node
, struct rb_node
*parent
,
23 struct afs_vnode
*vnode
;
30 bad
= dump_tree_aux(node
->rb_left
, node
, depth
+ 2, '/');
32 vnode
= rb_entry(node
, struct afs_vnode
, cb_promise
);
33 _debug("%c %*.*s%c%p {%d}",
34 rb_is_red(node
) ? 'R' : 'B',
36 vnode
, vnode
->cb_expires_at
);
37 if (rb_parent(node
) != parent
) {
38 printk("BAD: %p != %p\n", rb_parent(node
), parent
);
43 bad
|= dump_tree_aux(node
->rb_right
, node
, depth
+ 2, '\\');
48 static noinline
void dump_tree(const char *name
, struct afs_server
*server
)
51 if (dump_tree_aux(server
->cb_promises
.rb_node
, NULL
, 0, '-'))
57 * insert a vnode into the backing server's vnode tree
59 static void afs_install_vnode(struct afs_vnode
*vnode
,
60 struct afs_server
*server
)
62 struct afs_server
*old_server
= vnode
->server
;
63 struct afs_vnode
*xvnode
;
64 struct rb_node
*parent
, **p
;
66 _enter("%p,%p", vnode
, 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
);
74 afs_get_server(server
);
75 vnode
->server
= server
;
76 afs_put_server(old_server
);
78 /* insert into the server's vnode tree in FID order */
79 spin_lock(&server
->fs_lock
);
82 p
= &server
->fs_vnodes
.rb_node
;
85 xvnode
= rb_entry(parent
, struct afs_vnode
, server_rb
);
86 if (vnode
->fid
.vid
< xvnode
->fid
.vid
)
88 else if (vnode
->fid
.vid
> xvnode
->fid
.vid
)
90 else if (vnode
->fid
.vnode
< xvnode
->fid
.vnode
)
92 else if (vnode
->fid
.vnode
> xvnode
->fid
.vnode
)
94 else if (vnode
->fid
.unique
< xvnode
->fid
.unique
)
96 else if (vnode
->fid
.unique
> xvnode
->fid
.unique
)
99 BUG(); /* can't happen unless afs_iget() malfunctions */
102 rb_link_node(&vnode
->server_rb
, parent
, p
);
103 rb_insert_color(&vnode
->server_rb
, &server
->fs_vnodes
);
105 spin_unlock(&server
->fs_lock
);
110 * insert a vnode into the promising server's update/expiration tree
111 * - caller must hold vnode->lock
113 static void afs_vnode_note_promise(struct afs_vnode
*vnode
,
114 struct afs_server
*server
)
116 struct afs_server
*old_server
;
117 struct afs_vnode
*xvnode
;
118 struct rb_node
*parent
, **p
;
120 _enter("%p,%p", vnode
, server
);
122 ASSERT(server
!= NULL
);
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]");
132 spin_lock(&old_server
->cb_lock
);
133 if (vnode
->cb_promised
) {
135 rb_erase(&vnode
->cb_promise
, &old_server
->cb_promises
);
136 vnode
->cb_promised
= false;
138 spin_unlock(&old_server
->cb_lock
);
141 if (vnode
->server
!= server
)
142 afs_install_vnode(vnode
, server
);
144 vnode
->cb_expires_at
= vnode
->cb_expires
;
145 _debug("PROMISE on %p {%lu}",
146 vnode
, (unsigned long) vnode
->cb_expires_at
);
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
);
153 p
= &server
->cb_promises
.rb_node
;
156 xvnode
= rb_entry(parent
, struct afs_vnode
, cb_promise
);
157 if (vnode
->cb_expires_at
< xvnode
->cb_expires_at
)
163 rb_link_node(&vnode
->cb_promise
, parent
, p
);
164 rb_insert_color(&vnode
->cb_promise
, &server
->cb_promises
);
165 vnode
->cb_promised
= true;
167 spin_unlock(&server
->cb_lock
);
172 * handle remote file deletion by discarding the callback promise
174 static void afs_vnode_deleted_remotely(struct afs_vnode
*vnode
)
176 struct afs_server
*server
;
178 set_bit(AFS_VNODE_DELETED
, &vnode
->flags
);
180 server
= vnode
->server
;
181 if (vnode
->cb_promised
) {
182 spin_lock(&server
->cb_lock
);
183 if (vnode
->cb_promised
) {
184 rb_erase(&vnode
->cb_promise
, &server
->cb_promises
);
185 vnode
->cb_promised
= false;
187 spin_unlock(&server
->cb_lock
);
190 spin_lock(&vnode
->server
->fs_lock
);
191 rb_erase(&vnode
->server_rb
, &vnode
->server
->fs_vnodes
);
192 spin_unlock(&vnode
->server
->fs_lock
);
194 vnode
->server
= NULL
;
195 afs_put_server(server
);
199 * finish off updating the recorded status of a file after a successful
200 * operation completion
201 * - starts callback expiry timer
202 * - adds to server's callback list
204 void afs_vnode_finalise_status_update(struct afs_vnode
*vnode
,
205 struct afs_server
*server
)
207 struct afs_server
*oldserver
= NULL
;
209 _enter("%p,%p", vnode
, server
);
211 spin_lock(&vnode
->lock
);
212 clear_bit(AFS_VNODE_CB_BROKEN
, &vnode
->flags
);
213 afs_vnode_note_promise(vnode
, server
);
215 ASSERTCMP(vnode
->update_cnt
, >=, 0);
216 spin_unlock(&vnode
->lock
);
218 wake_up_all(&vnode
->update_waitq
);
219 afs_put_server(oldserver
);
224 * finish off updating the recorded status of a file after an operation failed
226 static void afs_vnode_status_update_failed(struct afs_vnode
*vnode
, int ret
)
228 _enter("%p,%d", vnode
, ret
);
230 spin_lock(&vnode
->lock
);
232 clear_bit(AFS_VNODE_CB_BROKEN
, &vnode
->flags
);
234 if (ret
== -ENOENT
) {
235 /* the file was deleted on the server */
236 _debug("got NOENT from server - marking file deleted");
237 afs_vnode_deleted_remotely(vnode
);
241 ASSERTCMP(vnode
->update_cnt
, >=, 0);
242 spin_unlock(&vnode
->lock
);
244 wake_up_all(&vnode
->update_waitq
);
249 * fetch file status from the volume
250 * - don't issue a fetch if:
251 * - the changed bit is not set and there's a valid callback
252 * - there are any outstanding ops that will fetch the status
253 * - TODO implement local caching
255 int afs_vnode_fetch_status(struct afs_vnode
*vnode
,
256 struct afs_vnode
*auth_vnode
, struct key
*key
)
258 struct afs_server
*server
;
259 unsigned long acl_order
;
262 DECLARE_WAITQUEUE(myself
, current
);
264 _enter("%s,{%u,%u,%u}",
265 vnode
->volume
->vlocation
->vldb
.name
,
266 vnode
->fid
.vid
, vnode
->fid
.vnode
, vnode
->fid
.unique
);
268 if (!test_bit(AFS_VNODE_CB_BROKEN
, &vnode
->flags
) &&
269 vnode
->cb_promised
) {
270 _leave(" [unchanged]");
274 if (test_bit(AFS_VNODE_DELETED
, &vnode
->flags
)) {
275 _leave(" [deleted]");
281 acl_order
= auth_vnode
->acl_order
;
283 spin_lock(&vnode
->lock
);
285 if (!test_bit(AFS_VNODE_CB_BROKEN
, &vnode
->flags
) &&
286 vnode
->cb_promised
) {
287 spin_unlock(&vnode
->lock
);
288 _leave(" [unchanged]");
292 ASSERTCMP(vnode
->update_cnt
, >=, 0);
294 if (vnode
->update_cnt
> 0) {
295 /* someone else started a fetch */
296 _debug("wait on fetch %d", vnode
->update_cnt
);
298 set_current_state(TASK_UNINTERRUPTIBLE
);
299 ASSERT(myself
.func
!= NULL
);
300 add_wait_queue(&vnode
->update_waitq
, &myself
);
302 /* wait for the status to be updated */
304 if (!test_bit(AFS_VNODE_CB_BROKEN
, &vnode
->flags
))
306 if (test_bit(AFS_VNODE_DELETED
, &vnode
->flags
))
309 /* check to see if it got updated and invalidated all
310 * before we saw it */
311 if (vnode
->update_cnt
== 0) {
312 remove_wait_queue(&vnode
->update_waitq
,
314 set_current_state(TASK_RUNNING
);
318 spin_unlock(&vnode
->lock
);
321 set_current_state(TASK_UNINTERRUPTIBLE
);
323 spin_lock(&vnode
->lock
);
326 remove_wait_queue(&vnode
->update_waitq
, &myself
);
327 spin_unlock(&vnode
->lock
);
328 set_current_state(TASK_RUNNING
);
330 return test_bit(AFS_VNODE_DELETED
, &vnode
->flags
) ?
335 /* okay... we're going to have to initiate the op */
338 spin_unlock(&vnode
->lock
);
340 /* merge AFS status fetches and clear outstanding callback on this
343 /* pick a server to query */
344 server
= afs_volume_pick_fileserver(vnode
);
348 _debug("USING SERVER: %p{%08x}",
349 server
, ntohl(server
->addr
.s_addr
));
351 ret
= afs_fs_fetch_file_status(server
, key
, vnode
, NULL
,
354 } while (!afs_volume_release_fileserver(vnode
, server
, ret
));
356 /* adjust the flags */
360 afs_cache_permit(vnode
, key
, acl_order
);
361 afs_vnode_finalise_status_update(vnode
, server
);
362 afs_put_server(server
);
364 _debug("failed [%d]", ret
);
365 afs_vnode_status_update_failed(vnode
, ret
);
368 ASSERTCMP(vnode
->update_cnt
, >=, 0);
370 _leave(" = %d [cnt %d]", ret
, vnode
->update_cnt
);
374 spin_lock(&vnode
->lock
);
376 ASSERTCMP(vnode
->update_cnt
, >=, 0);
377 spin_unlock(&vnode
->lock
);
378 _leave(" = %ld [cnt %d]", PTR_ERR(server
), vnode
->update_cnt
);
379 return PTR_ERR(server
);
383 * fetch file data from the volume
384 * - TODO implement caching
386 int afs_vnode_fetch_data(struct afs_vnode
*vnode
, struct key
*key
,
387 off_t offset
, size_t length
, struct page
*page
)
389 struct afs_server
*server
;
392 _enter("%s{%u,%u,%u},%x,,,",
393 vnode
->volume
->vlocation
->vldb
.name
,
399 /* this op will fetch the status */
400 spin_lock(&vnode
->lock
);
402 spin_unlock(&vnode
->lock
);
404 /* merge in AFS status fetches and clear outstanding callback on this
407 /* pick a server to query */
408 server
= afs_volume_pick_fileserver(vnode
);
412 _debug("USING SERVER: %08x\n", ntohl(server
->addr
.s_addr
));
414 ret
= afs_fs_fetch_data(server
, key
, vnode
, offset
, length
,
415 page
, &afs_sync_call
);
417 } while (!afs_volume_release_fileserver(vnode
, server
, ret
));
419 /* adjust the flags */
421 afs_vnode_finalise_status_update(vnode
, server
);
422 afs_put_server(server
);
424 afs_vnode_status_update_failed(vnode
, ret
);
427 _leave(" = %d", ret
);
431 spin_lock(&vnode
->lock
);
433 ASSERTCMP(vnode
->update_cnt
, >=, 0);
434 spin_unlock(&vnode
->lock
);
435 return PTR_ERR(server
);
439 * make a file or a directory
441 int afs_vnode_create(struct afs_vnode
*vnode
, struct key
*key
,
442 const char *name
, umode_t mode
, struct afs_fid
*newfid
,
443 struct afs_file_status
*newstatus
,
444 struct afs_callback
*newcb
, struct afs_server
**_server
)
446 struct afs_server
*server
;
449 _enter("%s{%u,%u,%u},%x,%s,,",
450 vnode
->volume
->vlocation
->vldb
.name
,
457 /* this op will fetch the status on the directory we're creating in */
458 spin_lock(&vnode
->lock
);
460 spin_unlock(&vnode
->lock
);
463 /* pick a server to query */
464 server
= afs_volume_pick_fileserver(vnode
);
468 _debug("USING SERVER: %08x\n", ntohl(server
->addr
.s_addr
));
470 ret
= afs_fs_create(server
, key
, vnode
, name
, mode
, newfid
,
471 newstatus
, newcb
, &afs_sync_call
);
473 } while (!afs_volume_release_fileserver(vnode
, server
, ret
));
475 /* adjust the flags */
477 afs_vnode_finalise_status_update(vnode
, server
);
480 afs_vnode_status_update_failed(vnode
, ret
);
484 _leave(" = %d [cnt %d]", ret
, vnode
->update_cnt
);
488 spin_lock(&vnode
->lock
);
490 ASSERTCMP(vnode
->update_cnt
, >=, 0);
491 spin_unlock(&vnode
->lock
);
492 _leave(" = %ld [cnt %d]", PTR_ERR(server
), vnode
->update_cnt
);
493 return PTR_ERR(server
);
497 * remove a file or directory
499 int afs_vnode_remove(struct afs_vnode
*vnode
, struct key
*key
, const char *name
,
502 struct afs_server
*server
;
505 _enter("%s{%u,%u,%u},%x,%s",
506 vnode
->volume
->vlocation
->vldb
.name
,
513 /* this op will fetch the status on the directory we're removing from */
514 spin_lock(&vnode
->lock
);
516 spin_unlock(&vnode
->lock
);
519 /* pick a server to query */
520 server
= afs_volume_pick_fileserver(vnode
);
524 _debug("USING SERVER: %08x\n", ntohl(server
->addr
.s_addr
));
526 ret
= afs_fs_remove(server
, key
, vnode
, name
, isdir
,
529 } while (!afs_volume_release_fileserver(vnode
, server
, ret
));
531 /* adjust the flags */
533 afs_vnode_finalise_status_update(vnode
, server
);
534 afs_put_server(server
);
536 afs_vnode_status_update_failed(vnode
, ret
);
539 _leave(" = %d [cnt %d]", ret
, vnode
->update_cnt
);
543 spin_lock(&vnode
->lock
);
545 ASSERTCMP(vnode
->update_cnt
, >=, 0);
546 spin_unlock(&vnode
->lock
);
547 _leave(" = %ld [cnt %d]", PTR_ERR(server
), vnode
->update_cnt
);
548 return PTR_ERR(server
);
554 extern int afs_vnode_link(struct afs_vnode
*dvnode
, struct afs_vnode
*vnode
,
555 struct key
*key
, const char *name
)
557 struct afs_server
*server
;
560 _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s",
561 dvnode
->volume
->vlocation
->vldb
.name
,
565 vnode
->volume
->vlocation
->vldb
.name
,
572 /* this op will fetch the status on the directory we're removing from */
573 spin_lock(&vnode
->lock
);
575 spin_unlock(&vnode
->lock
);
576 spin_lock(&dvnode
->lock
);
577 dvnode
->update_cnt
++;
578 spin_unlock(&dvnode
->lock
);
581 /* pick a server to query */
582 server
= afs_volume_pick_fileserver(dvnode
);
586 _debug("USING SERVER: %08x\n", ntohl(server
->addr
.s_addr
));
588 ret
= afs_fs_link(server
, key
, dvnode
, vnode
, name
,
591 } while (!afs_volume_release_fileserver(dvnode
, server
, ret
));
593 /* adjust the flags */
595 afs_vnode_finalise_status_update(vnode
, server
);
596 afs_vnode_finalise_status_update(dvnode
, server
);
597 afs_put_server(server
);
599 afs_vnode_status_update_failed(vnode
, ret
);
600 afs_vnode_status_update_failed(dvnode
, ret
);
603 _leave(" = %d [cnt %d]", ret
, vnode
->update_cnt
);
607 spin_lock(&vnode
->lock
);
609 ASSERTCMP(vnode
->update_cnt
, >=, 0);
610 spin_unlock(&vnode
->lock
);
611 spin_lock(&dvnode
->lock
);
612 dvnode
->update_cnt
--;
613 ASSERTCMP(dvnode
->update_cnt
, >=, 0);
614 spin_unlock(&dvnode
->lock
);
615 _leave(" = %ld [cnt %d]", PTR_ERR(server
), vnode
->update_cnt
);
616 return PTR_ERR(server
);
620 * create a symbolic link
622 int afs_vnode_symlink(struct afs_vnode
*vnode
, struct key
*key
,
623 const char *name
, const char *content
,
624 struct afs_fid
*newfid
,
625 struct afs_file_status
*newstatus
,
626 struct afs_server
**_server
)
628 struct afs_server
*server
;
631 _enter("%s{%u,%u,%u},%x,%s,%s,,,",
632 vnode
->volume
->vlocation
->vldb
.name
,
639 /* this op will fetch the status on the directory we're creating in */
640 spin_lock(&vnode
->lock
);
642 spin_unlock(&vnode
->lock
);
645 /* pick a server to query */
646 server
= afs_volume_pick_fileserver(vnode
);
650 _debug("USING SERVER: %08x\n", ntohl(server
->addr
.s_addr
));
652 ret
= afs_fs_symlink(server
, key
, vnode
, name
, content
,
653 newfid
, newstatus
, &afs_sync_call
);
655 } while (!afs_volume_release_fileserver(vnode
, server
, ret
));
657 /* adjust the flags */
659 afs_vnode_finalise_status_update(vnode
, server
);
662 afs_vnode_status_update_failed(vnode
, ret
);
666 _leave(" = %d [cnt %d]", ret
, vnode
->update_cnt
);
670 spin_lock(&vnode
->lock
);
672 ASSERTCMP(vnode
->update_cnt
, >=, 0);
673 spin_unlock(&vnode
->lock
);
674 _leave(" = %ld [cnt %d]", PTR_ERR(server
), vnode
->update_cnt
);
675 return PTR_ERR(server
);
681 int afs_vnode_rename(struct afs_vnode
*orig_dvnode
,
682 struct afs_vnode
*new_dvnode
,
684 const char *orig_name
,
685 const char *new_name
)
687 struct afs_server
*server
;
690 _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s",
691 orig_dvnode
->volume
->vlocation
->vldb
.name
,
692 orig_dvnode
->fid
.vid
,
693 orig_dvnode
->fid
.vnode
,
694 orig_dvnode
->fid
.unique
,
695 new_dvnode
->volume
->vlocation
->vldb
.name
,
697 new_dvnode
->fid
.vnode
,
698 new_dvnode
->fid
.unique
,
703 /* this op will fetch the status on both the directories we're dealing
705 spin_lock(&orig_dvnode
->lock
);
706 orig_dvnode
->update_cnt
++;
707 spin_unlock(&orig_dvnode
->lock
);
708 if (new_dvnode
!= orig_dvnode
) {
709 spin_lock(&new_dvnode
->lock
);
710 new_dvnode
->update_cnt
++;
711 spin_unlock(&new_dvnode
->lock
);
715 /* pick a server to query */
716 server
= afs_volume_pick_fileserver(orig_dvnode
);
720 _debug("USING SERVER: %08x\n", ntohl(server
->addr
.s_addr
));
722 ret
= afs_fs_rename(server
, key
, orig_dvnode
, orig_name
,
723 new_dvnode
, new_name
, &afs_sync_call
);
725 } while (!afs_volume_release_fileserver(orig_dvnode
, server
, ret
));
727 /* adjust the flags */
729 afs_vnode_finalise_status_update(orig_dvnode
, server
);
730 if (new_dvnode
!= orig_dvnode
)
731 afs_vnode_finalise_status_update(new_dvnode
, server
);
732 afs_put_server(server
);
734 afs_vnode_status_update_failed(orig_dvnode
, ret
);
735 if (new_dvnode
!= orig_dvnode
)
736 afs_vnode_status_update_failed(new_dvnode
, ret
);
739 _leave(" = %d [cnt %d]", ret
, orig_dvnode
->update_cnt
);
743 spin_lock(&orig_dvnode
->lock
);
744 orig_dvnode
->update_cnt
--;
745 ASSERTCMP(orig_dvnode
->update_cnt
, >=, 0);
746 spin_unlock(&orig_dvnode
->lock
);
747 if (new_dvnode
!= orig_dvnode
) {
748 spin_lock(&new_dvnode
->lock
);
749 new_dvnode
->update_cnt
--;
750 ASSERTCMP(new_dvnode
->update_cnt
, >=, 0);
751 spin_unlock(&new_dvnode
->lock
);
753 _leave(" = %ld [cnt %d]", PTR_ERR(server
), orig_dvnode
->update_cnt
);
754 return PTR_ERR(server
);