Merge commit 'gcl/merge' into merge
[linux-2.6] / fs / afs / vnode.c
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 }