aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-04-26 18:59:35 -0400
committerDavid S. Miller <davem@davemloft.net>2007-04-26 18:59:35 -0400
commit260a980317dac80182dd76140cf67c6e81d6d3dd (patch)
tree84f3e919fd33be56aad4fc57f5cb844df1a6b952 /fs
parentc35eccb1f614954b10cba3f74b7c301993b2f42e (diff)
[AFS]: Add "directory write" support.
Add support for the create, link, symlink, unlink, mkdir, rmdir and rename VFS operations to the in-kernel AFS filesystem. Also: (1) Fix dentry and inode revalidation. d_revalidate should only look at state of the dentry. Revalidation of the contents of an inode pointed to by a dentry is now separate. (2) Fix afs_lookup() to hash negative dentries as well as positive ones. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/afs.h26
-rw-r--r--fs/afs/afs_fs.h11
-rw-r--r--fs/afs/callback.c36
-rw-r--r--fs/afs/dir.c676
-rw-r--r--fs/afs/file.c7
-rw-r--r--fs/afs/fsclient.c625
-rw-r--r--fs/afs/inode.c115
-rw-r--r--fs/afs/internal.h54
-rw-r--r--fs/afs/misc.c21
-rw-r--r--fs/afs/security.c31
-rw-r--r--fs/afs/server.c2
-rw-r--r--fs/afs/super.c6
-rw-r--r--fs/afs/vnode.c422
-rw-r--r--fs/afs/volume.c14
14 files changed, 1778 insertions, 268 deletions
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index d959092aaf4b..52d0752265b8 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -106,19 +106,37 @@ struct afs_file_status {
106 106
107 afs_file_type_t type; /* file type */ 107 afs_file_type_t type; /* file type */
108 unsigned nlink; /* link count */ 108 unsigned nlink; /* link count */
109 size_t size; /* file size */ 109 u64 size; /* file size */
110 afs_dataversion_t data_version; /* current data version */ 110 afs_dataversion_t data_version; /* current data version */
111 unsigned author; /* author ID */ 111 u32 author; /* author ID */
112 unsigned owner; /* owner ID */ 112 u32 owner; /* owner ID */
113 u32 group; /* group ID */
113 afs_access_t caller_access; /* access rights for authenticated caller */ 114 afs_access_t caller_access; /* access rights for authenticated caller */
114 afs_access_t anon_access; /* access rights for unauthenticated caller */ 115 afs_access_t anon_access; /* access rights for unauthenticated caller */
115 umode_t mode; /* UNIX mode */ 116 umode_t mode; /* UNIX mode */
116 struct afs_fid parent; /* parent file ID */ 117 struct afs_fid parent; /* parent dir ID for non-dirs only */
117 time_t mtime_client; /* last time client changed data */ 118 time_t mtime_client; /* last time client changed data */
118 time_t mtime_server; /* last time server changed data */ 119 time_t mtime_server; /* last time server changed data */
119}; 120};
120 121
121/* 122/*
123 * AFS file status change request
124 */
125struct afs_store_status {
126 u32 mask; /* which bits of the struct are set */
127 u32 mtime_client; /* last time client changed data */
128 u32 owner; /* owner ID */
129 u32 group; /* group ID */
130 umode_t mode; /* UNIX mode */
131};
132
133#define AFS_SET_MTIME 0x01 /* set the mtime */
134#define AFS_SET_OWNER 0x02 /* set the owner ID */
135#define AFS_SET_GROUP 0x04 /* set the group ID (unsupported?) */
136#define AFS_SET_MODE 0x08 /* set the UNIX mode */
137#define AFS_SET_SEG_SIZE 0x10 /* set the segment size (unsupported) */
138
139/*
122 * AFS volume synchronisation information 140 * AFS volume synchronisation information
123 */ 141 */
124struct afs_volsync { 142struct afs_volsync {
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index fd385954f21f..89e0d1650a72 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -16,12 +16,19 @@
16#define FS_SERVICE 1 /* AFS File Service ID */ 16#define FS_SERVICE 1 /* AFS File Service ID */
17 17
18enum AFS_FS_Operations { 18enum AFS_FS_Operations {
19 FSFETCHSTATUS = 132, /* AFS Fetch file status */
20 FSFETCHDATA = 130, /* AFS Fetch file data */ 19 FSFETCHDATA = 130, /* AFS Fetch file data */
20 FSFETCHSTATUS = 132, /* AFS Fetch file status */
21 FSREMOVEFILE = 136, /* AFS Remove a file */
22 FSCREATEFILE = 137, /* AFS Create a file */
23 FSRENAME = 138, /* AFS Rename or move a file or directory */
24 FSSYMLINK = 139, /* AFS Create a symbolic link */
25 FSLINK = 140, /* AFS Create a hard link */
26 FSMAKEDIR = 141, /* AFS Create a directory */
27 FSREMOVEDIR = 142, /* AFS Remove a directory */
21 FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */ 28 FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */
22 FSGETVOLUMEINFO = 148, /* AFS Get root volume information */ 29 FSGETVOLUMEINFO = 148, /* AFS Get root volume information */
23 FSGETROOTVOLUME = 151, /* AFS Get root volume name */ 30 FSGETROOTVOLUME = 151, /* AFS Get root volume name */
24 FSLOOKUP = 161 /* AFS lookup file in directory */ 31 FSLOOKUP = 161, /* AFS lookup file in directory */
25}; 32};
26 33
27enum AFS_FS_Errors { 34enum AFS_FS_Errors {
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index e674bebbb8b1..639399f0ab6f 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -44,7 +44,8 @@ void afs_init_callback_state(struct afs_server *server)
44 while (!RB_EMPTY_ROOT(&server->cb_promises)) { 44 while (!RB_EMPTY_ROOT(&server->cb_promises)) {
45 vnode = rb_entry(server->cb_promises.rb_node, 45 vnode = rb_entry(server->cb_promises.rb_node,
46 struct afs_vnode, cb_promise); 46 struct afs_vnode, cb_promise);
47 printk("\nUNPROMISE on %p\n", vnode); 47 _debug("UNPROMISE { vid=%x vn=%u uq=%u}",
48 vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
48 rb_erase(&vnode->cb_promise, &server->cb_promises); 49 rb_erase(&vnode->cb_promise, &server->cb_promises);
49 vnode->cb_promised = false; 50 vnode->cb_promised = false;
50 } 51 }
@@ -68,7 +69,7 @@ void afs_broken_callback_work(struct work_struct *work)
68 69
69 /* we're only interested in dealing with a broken callback on *this* 70 /* we're only interested in dealing with a broken callback on *this*
70 * vnode and only if no-one else has dealt with it yet */ 71 * vnode and only if no-one else has dealt with it yet */
71 if (!mutex_trylock(&vnode->cb_broken_lock)) 72 if (!mutex_trylock(&vnode->validate_lock))
72 return; /* someone else is dealing with it */ 73 return; /* someone else is dealing with it */
73 74
74 if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { 75 if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
@@ -84,13 +85,14 @@ void afs_broken_callback_work(struct work_struct *work)
84 /* if the vnode's data version number changed then its contents 85 /* if the vnode's data version number changed then its contents
85 * are different */ 86 * are different */
86 if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { 87 if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
87 _debug("zap data"); 88 _debug("zap data {%x:%u}",
89 vnode->fid.vid, vnode->fid.vnode);
88 invalidate_remote_inode(&vnode->vfs_inode); 90 invalidate_remote_inode(&vnode->vfs_inode);
89 } 91 }
90 } 92 }
91 93
92out: 94out:
93 mutex_unlock(&vnode->cb_broken_lock); 95 mutex_unlock(&vnode->validate_lock);
94 96
95 /* avoid the potential race whereby the mutex_trylock() in this 97 /* avoid the potential race whereby the mutex_trylock() in this
96 * function happens again between the clear_bit() and the 98 * function happens again between the clear_bit() and the
@@ -252,6 +254,32 @@ static void afs_do_give_up_callback(struct afs_server *server,
252} 254}
253 255
254/* 256/*
257 * discard the callback on a deleted item
258 */
259void afs_discard_callback_on_delete(struct afs_vnode *vnode)
260{
261 struct afs_server *server = vnode->server;
262
263 _enter("%d", vnode->cb_promised);
264
265 if (!vnode->cb_promised) {
266 _leave(" [not promised]");
267 return;
268 }
269
270 ASSERT(server != NULL);
271
272 spin_lock(&server->cb_lock);
273 if (vnode->cb_promised) {
274 ASSERT(server->cb_promises.rb_node != NULL);
275 rb_erase(&vnode->cb_promise, &server->cb_promises);
276 vnode->cb_promised = false;
277 }
278 spin_unlock(&server->cb_lock);
279 _leave("");
280}
281
282/*
255 * give up the callback registered for a vnode on the file server when the 283 * give up the callback registered for a vnode on the file server when the
256 * inode is being cleared 284 * inode is being cleared
257 */ 285 */
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 87368417e4d3..dbbe75d6023b 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -18,40 +18,50 @@
18#include <linux/ctype.h> 18#include <linux/ctype.h>
19#include "internal.h" 19#include "internal.h"
20 20
21static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, 21static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
22 struct nameidata *nd); 22 struct nameidata *nd);
23static int afs_dir_open(struct inode *inode, struct file *file); 23static int afs_dir_open(struct inode *inode, struct file *file);
24static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir); 24static int afs_readdir(struct file *file, void *dirent, filldir_t filldir);
25static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd); 25static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
26static int afs_d_delete(struct dentry *dentry); 26static int afs_d_delete(struct dentry *dentry);
27static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, 27static void afs_d_release(struct dentry *dentry);
28static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
28 loff_t fpos, u64 ino, unsigned dtype); 29 loff_t fpos, u64 ino, unsigned dtype);
30static int afs_create(struct inode *dir, struct dentry *dentry, int mode,
31 struct nameidata *nd);
32static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
33static int afs_rmdir(struct inode *dir, struct dentry *dentry);
34static int afs_unlink(struct inode *dir, struct dentry *dentry);
35static int afs_link(struct dentry *from, struct inode *dir,
36 struct dentry *dentry);
37static int afs_symlink(struct inode *dir, struct dentry *dentry,
38 const char *content);
39static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
40 struct inode *new_dir, struct dentry *new_dentry);
29 41
30const struct file_operations afs_dir_file_operations = { 42const struct file_operations afs_dir_file_operations = {
31 .open = afs_dir_open, 43 .open = afs_dir_open,
32 .release = afs_release, 44 .release = afs_release,
33 .readdir = afs_dir_readdir, 45 .readdir = afs_readdir,
34}; 46};
35 47
36const struct inode_operations afs_dir_inode_operations = { 48const struct inode_operations afs_dir_inode_operations = {
37 .lookup = afs_dir_lookup, 49 .create = afs_create,
50 .lookup = afs_lookup,
51 .link = afs_link,
52 .unlink = afs_unlink,
53 .symlink = afs_symlink,
54 .mkdir = afs_mkdir,
55 .rmdir = afs_rmdir,
56 .rename = afs_rename,
38 .permission = afs_permission, 57 .permission = afs_permission,
39 .getattr = afs_inode_getattr, 58 .getattr = afs_inode_getattr,
40#if 0 /* TODO */
41 .create = afs_dir_create,
42 .link = afs_dir_link,
43 .unlink = afs_dir_unlink,
44 .symlink = afs_dir_symlink,
45 .mkdir = afs_dir_mkdir,
46 .rmdir = afs_dir_rmdir,
47 .mknod = afs_dir_mknod,
48 .rename = afs_dir_rename,
49#endif
50}; 59};
51 60
52static struct dentry_operations afs_fs_dentry_operations = { 61static struct dentry_operations afs_fs_dentry_operations = {
53 .d_revalidate = afs_d_revalidate, 62 .d_revalidate = afs_d_revalidate,
54 .d_delete = afs_d_delete, 63 .d_delete = afs_d_delete,
64 .d_release = afs_d_release,
55}; 65};
56 66
57#define AFS_DIR_HASHTBL_SIZE 128 67#define AFS_DIR_HASHTBL_SIZE 128
@@ -103,7 +113,7 @@ struct afs_dir_page {
103 union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)]; 113 union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)];
104}; 114};
105 115
106struct afs_dir_lookup_cookie { 116struct afs_lookup_cookie {
107 struct afs_fid fid; 117 struct afs_fid fid;
108 const char *name; 118 const char *name;
109 size_t nlen; 119 size_t nlen;
@@ -299,7 +309,7 @@ static int afs_dir_iterate_block(unsigned *fpos,
299 nlen, 309 nlen,
300 blkoff + offset * sizeof(union afs_dirent), 310 blkoff + offset * sizeof(union afs_dirent),
301 ntohl(dire->u.vnode), 311 ntohl(dire->u.vnode),
302 filldir == afs_dir_lookup_filldir ? 312 filldir == afs_lookup_filldir ?
303 ntohl(dire->u.unique) : DT_UNKNOWN); 313 ntohl(dire->u.unique) : DT_UNKNOWN);
304 if (ret < 0) { 314 if (ret < 0) {
305 _leave(" = 0 [full]"); 315 _leave(" = 0 [full]");
@@ -379,7 +389,7 @@ out:
379/* 389/*
380 * read an AFS directory 390 * read an AFS directory
381 */ 391 */
382static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir) 392static int afs_readdir(struct file *file, void *cookie, filldir_t filldir)
383{ 393{
384 unsigned fpos; 394 unsigned fpos;
385 int ret; 395 int ret;
@@ -403,10 +413,10 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir)
403 * - if afs_dir_iterate_block() spots this function, it'll pass the FID 413 * - if afs_dir_iterate_block() spots this function, it'll pass the FID
404 * uniquifier through dtype 414 * uniquifier through dtype
405 */ 415 */
406static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, 416static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
407 loff_t fpos, u64 ino, unsigned dtype) 417 loff_t fpos, u64 ino, unsigned dtype)
408{ 418{
409 struct afs_dir_lookup_cookie *cookie = _cookie; 419 struct afs_lookup_cookie *cookie = _cookie;
410 420
411 _enter("{%s,%Zu},%s,%u,,%llu,%u", 421 _enter("{%s,%Zu},%s,%u,,%llu,%u",
412 cookie->name, cookie->nlen, name, nlen, ino, dtype); 422 cookie->name, cookie->nlen, name, nlen, ino, dtype);
@@ -430,11 +440,12 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
430 440
431/* 441/*
432 * do a lookup in a directory 442 * do a lookup in a directory
443 * - just returns the FID the dentry name maps to if found
433 */ 444 */
434static int afs_do_lookup(struct inode *dir, struct dentry *dentry, 445static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
435 struct afs_fid *fid, struct key *key) 446 struct afs_fid *fid, struct key *key)
436{ 447{
437 struct afs_dir_lookup_cookie cookie; 448 struct afs_lookup_cookie cookie;
438 struct afs_super_info *as; 449 struct afs_super_info *as;
439 unsigned fpos; 450 unsigned fpos;
440 int ret; 451 int ret;
@@ -450,7 +461,7 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
450 cookie.found = 0; 461 cookie.found = 0;
451 462
452 fpos = 0; 463 fpos = 0;
453 ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir, 464 ret = afs_dir_iterate(dir, &fpos, &cookie, afs_lookup_filldir,
454 key); 465 key);
455 if (ret < 0) { 466 if (ret < 0) {
456 _leave(" = %d [iter]", ret); 467 _leave(" = %d [iter]", ret);
@@ -471,8 +482,8 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
471/* 482/*
472 * look up an entry in a directory 483 * look up an entry in a directory
473 */ 484 */
474static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry, 485static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
475 struct nameidata *nd) 486 struct nameidata *nd)
476{ 487{
477 struct afs_vnode *vnode; 488 struct afs_vnode *vnode;
478 struct afs_fid fid; 489 struct afs_fid fid;
@@ -480,14 +491,18 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
480 struct key *key; 491 struct key *key;
481 int ret; 492 int ret;
482 493
483 _enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name); 494 vnode = AFS_FS_I(dir);
495
496 _enter("{%x:%d},%p{%s},",
497 vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name);
498
499 ASSERTCMP(dentry->d_inode, ==, NULL);
484 500
485 if (dentry->d_name.len > 255) { 501 if (dentry->d_name.len > 255) {
486 _leave(" = -ENAMETOOLONG"); 502 _leave(" = -ENAMETOOLONG");
487 return ERR_PTR(-ENAMETOOLONG); 503 return ERR_PTR(-ENAMETOOLONG);
488 } 504 }
489 505
490 vnode = AFS_FS_I(dir);
491 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 506 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
492 _leave(" = -ESTALE"); 507 _leave(" = -ESTALE");
493 return ERR_PTR(-ESTALE); 508 return ERR_PTR(-ESTALE);
@@ -499,15 +514,28 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
499 return ERR_PTR(PTR_ERR(key)); 514 return ERR_PTR(PTR_ERR(key));
500 } 515 }
501 516
517 ret = afs_validate(vnode, key);
518 if (ret < 0) {
519 key_put(key);
520 _leave(" = %d [val]", ret);
521 return ERR_PTR(ret);
522 }
523
502 ret = afs_do_lookup(dir, dentry, &fid, key); 524 ret = afs_do_lookup(dir, dentry, &fid, key);
503 if (ret < 0) { 525 if (ret < 0) {
504 key_put(key); 526 key_put(key);
527 if (ret == -ENOENT) {
528 d_add(dentry, NULL);
529 _leave(" = NULL [negative]");
530 return NULL;
531 }
505 _leave(" = %d [do]", ret); 532 _leave(" = %d [do]", ret);
506 return ERR_PTR(ret); 533 return ERR_PTR(ret);
507 } 534 }
535 dentry->d_fsdata = (void *)(unsigned long) vnode->status.data_version;
508 536
509 /* instantiate the dentry */ 537 /* instantiate the dentry */
510 inode = afs_iget(dir->i_sb, key, &fid); 538 inode = afs_iget(dir->i_sb, key, &fid, NULL, NULL);
511 key_put(key); 539 key_put(key);
512 if (IS_ERR(inode)) { 540 if (IS_ERR(inode)) {
513 _leave(" = %ld", PTR_ERR(inode)); 541 _leave(" = %ld", PTR_ERR(inode));
@@ -527,105 +555,64 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
527} 555}
528 556
529/* 557/*
530 * propagate changed and modified flags on a directory to all the children of
531 * that directory as they may indicate that the ACL on the dir has changed,
532 * potentially rendering the child inaccessible or that a file has been deleted
533 * or renamed
534 */
535static void afs_propagate_dir_changes(struct dentry *dir)
536{
537 struct dentry *child;
538 bool c, m;
539
540 c = test_bit(AFS_VNODE_CHANGED, &AFS_FS_I(dir->d_inode)->flags);
541 m = test_bit(AFS_VNODE_MODIFIED, &AFS_FS_I(dir->d_inode)->flags);
542
543 _enter("{%d,%d}", c, m);
544
545 spin_lock(&dir->d_lock);
546
547 list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
548 if (child->d_inode) {
549 struct afs_vnode *vnode;
550
551 _debug("tag %s", child->d_name.name);
552 vnode = AFS_FS_I(child->d_inode);
553 if (c)
554 set_bit(AFS_VNODE_DIR_CHANGED, &vnode->flags);
555 if (m)
556 set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags);
557 }
558 }
559
560 spin_unlock(&dir->d_lock);
561}
562
563/*
564 * check that a dentry lookup hit has found a valid entry 558 * check that a dentry lookup hit has found a valid entry
565 * - NOTE! the hit can be a negative hit too, so we can't assume we have an 559 * - NOTE! the hit can be a negative hit too, so we can't assume we have an
566 * inode 560 * inode
567 * - there are several things we need to check
568 * - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
569 * symlink)
570 * - parent dir metadata changed (security changes)
571 * - dentry data changed (write, truncate)
572 * - dentry metadata changed (security changes)
573 */ 561 */
574static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) 562static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
575{ 563{
576 struct afs_vnode *vnode; 564 struct afs_vnode *vnode, *dir;
577 struct afs_fid fid; 565 struct afs_fid fid;
578 struct dentry *parent; 566 struct dentry *parent;
579 struct inode *inode, *dir;
580 struct key *key; 567 struct key *key;
568 void *dir_version;
581 int ret; 569 int ret;
582 570
583 vnode = AFS_FS_I(dentry->d_inode); 571 vnode = AFS_FS_I(dentry->d_inode);
584 572
585 _enter("{sb=%p n=%s fl=%lx},", 573 if (dentry->d_inode)
586 dentry->d_sb, dentry->d_name.name, vnode->flags); 574 _enter("{v={%x:%u} n=%s fl=%lx},",
575 vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
576 vnode->flags);
577 else
578 _enter("{neg n=%s}", dentry->d_name.name);
587 579
588 key = afs_request_key(vnode->volume->cell); 580 key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
589 if (IS_ERR(key)) 581 if (IS_ERR(key))
590 key = NULL; 582 key = NULL;
591 583
592 /* lock down the parent dentry so we can peer at it */ 584 /* lock down the parent dentry so we can peer at it */
593 parent = dget_parent(dentry); 585 parent = dget_parent(dentry);
594 586 if (!parent->d_inode)
595 dir = parent->d_inode;
596 inode = dentry->d_inode;
597
598 /* handle a negative dentry */
599 if (!inode)
600 goto out_bad; 587 goto out_bad;
601 588
602 /* handle a bad inode */ 589 dir = AFS_FS_I(parent->d_inode);
603 if (is_bad_inode(inode)) {
604 printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
605 parent->d_name.name, dentry->d_name.name);
606 goto out_bad;
607 }
608 590
609 /* check that this dirent still exists if the directory's contents were 591 /* validate the parent directory */
610 * modified */ 592 if (test_bit(AFS_VNODE_MODIFIED, &dir->flags))
611 if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) { 593 afs_validate(dir, key);
594
595 if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
612 _debug("%s: parent dir deleted", dentry->d_name.name); 596 _debug("%s: parent dir deleted", dentry->d_name.name);
613 goto out_bad; 597 goto out_bad;
614 } 598 }
615 599
616 if (test_and_clear_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags)) { 600 dir_version = (void *) (unsigned long) dir->status.data_version;
617 /* rm/rmdir/rename may have occurred */ 601 if (dentry->d_fsdata == dir_version)
618 _debug("dir modified"); 602 goto out_valid; /* the dir contents are unchanged */
619 603
620 /* search the directory for this vnode */ 604 _debug("dir modified");
621 ret = afs_do_lookup(dir, dentry, &fid, key); 605
622 if (ret == -ENOENT) { 606 /* search the directory for this vnode */
623 _debug("%s: dirent not found", dentry->d_name.name); 607 ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key);
624 goto not_found; 608 switch (ret) {
625 } 609 case 0:
626 if (ret < 0) { 610 /* the filename maps to something */
627 _debug("failed to iterate dir %s: %d", 611 if (!dentry->d_inode)
628 parent->d_name.name, ret); 612 goto out_bad;
613 if (is_bad_inode(dentry->d_inode)) {
614 printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
615 parent->d_name.name, dentry->d_name.name);
629 goto out_bad; 616 goto out_bad;
630 } 617 }
631 618
@@ -639,56 +626,35 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
639 } 626 }
640 627
641 /* if the vnode ID uniqifier has changed, then the file has 628 /* if the vnode ID uniqifier has changed, then the file has
642 * been deleted */ 629 * been deleted and replaced, and the original vnode ID has
630 * been reused */
643 if (fid.unique != vnode->fid.unique) { 631 if (fid.unique != vnode->fid.unique) {
644 _debug("%s: file deleted (uq %u -> %u I:%lu)", 632 _debug("%s: file deleted (uq %u -> %u I:%lu)",
645 dentry->d_name.name, fid.unique, 633 dentry->d_name.name, fid.unique,
646 vnode->fid.unique, inode->i_version); 634 vnode->fid.unique, dentry->d_inode->i_version);
647 spin_lock(&vnode->lock); 635 spin_lock(&vnode->lock);
648 set_bit(AFS_VNODE_DELETED, &vnode->flags); 636 set_bit(AFS_VNODE_DELETED, &vnode->flags);
649 spin_unlock(&vnode->lock); 637 spin_unlock(&vnode->lock);
650 invalidate_remote_inode(inode); 638 goto not_found;
651 goto out_bad;
652 } 639 }
653 } 640 goto out_valid;
654 641
655 /* if the directory's metadata were changed then the security may be 642 case -ENOENT:
656 * different and we may no longer have access */ 643 /* the filename is unknown */
657 mutex_lock(&vnode->cb_broken_lock); 644 _debug("%s: dirent not found", dentry->d_name.name);
658 645 if (dentry->d_inode)
659 if (test_and_clear_bit(AFS_VNODE_DIR_CHANGED, &vnode->flags) || 646 goto not_found;
660 test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) { 647 goto out_valid;
661 _debug("%s: changed", dentry->d_name.name);
662 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
663 if (afs_vnode_fetch_status(vnode, NULL, key) < 0) {
664 mutex_unlock(&vnode->cb_broken_lock);
665 goto out_bad;
666 }
667 }
668 648
669 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 649 default:
670 _debug("%s: file already deleted", dentry->d_name.name); 650 _debug("failed to iterate dir %s: %d",
671 mutex_unlock(&vnode->cb_broken_lock); 651 parent->d_name.name, ret);
672 goto out_bad; 652 goto out_bad;
673 } 653 }
674 654
675 /* if the vnode's data version number changed then its contents are
676 * different */
677 if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
678 _debug("zap data");
679 invalidate_remote_inode(inode);
680 }
681
682 if (S_ISDIR(inode->i_mode) &&
683 (test_bit(AFS_VNODE_CHANGED, &vnode->flags) ||
684 test_bit(AFS_VNODE_MODIFIED, &vnode->flags)))
685 afs_propagate_dir_changes(dentry);
686
687 clear_bit(AFS_VNODE_CHANGED, &vnode->flags);
688 clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
689 mutex_unlock(&vnode->cb_broken_lock);
690
691out_valid: 655out_valid:
656 dentry->d_fsdata = dir_version;
657out_skip:
692 dput(parent); 658 dput(parent);
693 key_put(key); 659 key_put(key);
694 _leave(" = 1 [valid]"); 660 _leave(" = 1 [valid]");
@@ -701,10 +667,10 @@ not_found:
701 spin_unlock(&dentry->d_lock); 667 spin_unlock(&dentry->d_lock);
702 668
703out_bad: 669out_bad:
704 if (inode) { 670 if (dentry->d_inode) {
705 /* don't unhash if we have submounts */ 671 /* don't unhash if we have submounts */
706 if (have_submounts(dentry)) 672 if (have_submounts(dentry))
707 goto out_valid; 673 goto out_skip;
708 } 674 }
709 675
710 _debug("dropping dentry %s/%s", 676 _debug("dropping dentry %s/%s",
@@ -742,3 +708,433 @@ zap:
742 _leave(" = 1 [zap]"); 708 _leave(" = 1 [zap]");
743 return 1; 709 return 1;
744} 710}
711
712/*
713 * handle dentry release
714 */
715static void afs_d_release(struct dentry *dentry)
716{
717 _enter("%s", dentry->d_name.name);
718}
719
720/*
721 * create a directory on an AFS filesystem
722 */
723static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
724{
725 struct afs_file_status status;
726 struct afs_callback cb;
727 struct afs_server *server;
728 struct afs_vnode *dvnode, *vnode;
729 struct afs_fid fid;
730 struct inode *inode;
731 struct key *key;
732 int ret;
733
734 dvnode = AFS_FS_I(dir);
735
736 _enter("{%x:%d},{%s},%o",
737 dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
738
739 ret = -ENAMETOOLONG;
740 if (dentry->d_name.len > 255)
741 goto error;
742
743 key = afs_request_key(dvnode->volume->cell);
744 if (IS_ERR(key)) {
745 ret = PTR_ERR(key);
746 goto error;
747 }
748
749 mode |= S_IFDIR;
750 ret = afs_vnode_create(dvnode, key, dentry->d_name.name,
751 mode, &fid, &status, &cb, &server);
752 if (ret < 0)
753 goto mkdir_error;
754
755 inode = afs_iget(dir->i_sb, key, &fid, &status, &cb);
756 if (IS_ERR(inode)) {
757 /* ENOMEM at a really inconvenient time - just abandon the new
758 * directory on the server */
759 ret = PTR_ERR(inode);
760 goto iget_error;
761 }
762
763 /* apply the status report we've got for the new vnode */
764 vnode = AFS_FS_I(inode);
765 spin_lock(&vnode->lock);
766 vnode->update_cnt++;
767 spin_unlock(&vnode->lock);
768 afs_vnode_finalise_status_update(vnode, server);
769 afs_put_server(server);
770
771 d_instantiate(dentry, inode);
772 if (d_unhashed(dentry)) {
773 _debug("not hashed");
774 d_rehash(dentry);
775 }
776 key_put(key);
777 _leave(" = 0");
778 return 0;
779
780iget_error:
781 afs_put_server(server);
782mkdir_error:
783 key_put(key);
784error:
785 d_drop(dentry);
786 _leave(" = %d", ret);
787 return ret;
788}
789
790/*
791 * remove a directory from an AFS filesystem
792 */
793static int afs_rmdir(struct inode *dir, struct dentry *dentry)
794{
795 struct afs_vnode *dvnode, *vnode;
796 struct key *key;
797 int ret;
798
799 dvnode = AFS_FS_I(dir);
800
801 _enter("{%x:%d},{%s}",
802 dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
803
804 ret = -ENAMETOOLONG;
805 if (dentry->d_name.len > 255)
806 goto error;
807
808 key = afs_request_key(dvnode->volume->cell);
809 if (IS_ERR(key)) {
810 ret = PTR_ERR(key);
811 goto error;
812 }
813
814 ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, true);
815 if (ret < 0)
816 goto rmdir_error;
817
818 if (dentry->d_inode) {
819 vnode = AFS_FS_I(dentry->d_inode);
820 clear_nlink(&vnode->vfs_inode);
821 set_bit(AFS_VNODE_DELETED, &vnode->flags);
822 afs_discard_callback_on_delete(vnode);
823 }
824
825 key_put(key);
826 _leave(" = 0");
827 return 0;
828
829rmdir_error:
830 key_put(key);
831error:
832 _leave(" = %d", ret);
833 return ret;
834}
835
836/*
837 * remove a file from an AFS filesystem
838 */
839static int afs_unlink(struct inode *dir, struct dentry *dentry)
840{
841 struct afs_vnode *dvnode, *vnode;
842 struct key *key;
843 int ret;
844
845 dvnode = AFS_FS_I(dir);
846
847 _enter("{%x:%d},{%s}",
848 dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
849
850 ret = -ENAMETOOLONG;
851 if (dentry->d_name.len > 255)
852 goto error;
853
854 key = afs_request_key(dvnode->volume->cell);
855 if (IS_ERR(key)) {
856 ret = PTR_ERR(key);
857 goto error;
858 }
859
860 if (dentry->d_inode) {
861 vnode = AFS_FS_I(dentry->d_inode);
862
863 /* make sure we have a callback promise on the victim */
864 ret = afs_validate(vnode, key);
865 if (ret < 0)
866 goto error;
867 }
868
869 ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, false);
870 if (ret < 0)
871 goto remove_error;
872
873 if (dentry->d_inode) {
874 /* if the file wasn't deleted due to excess hard links, the
875 * fileserver will break the callback promise on the file - if
876 * it had one - before it returns to us, and if it was deleted,
877 * it won't
878 *
879 * however, if we didn't have a callback promise outstanding,
880 * or it was outstanding on a different server, then it won't
881 * break it either...
882 */
883 vnode = AFS_FS_I(dentry->d_inode);
884 if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
885 _debug("AFS_VNODE_DELETED");
886 if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags))
887 _debug("AFS_VNODE_CB_BROKEN");
888 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
889 ret = afs_validate(vnode, key);
890 _debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, ret);
891 }
892
893 key_put(key);
894 _leave(" = 0");
895 return 0;
896
897remove_error:
898 key_put(key);
899error:
900 _leave(" = %d", ret);
901 return ret;
902}
903
904/*
905 * create a regular file on an AFS filesystem
906 */
907static int afs_create(struct inode *dir, struct dentry *dentry, int mode,
908 struct nameidata *nd)
909{
910 struct afs_file_status status;
911 struct afs_callback cb;
912 struct afs_server *server;
913 struct afs_vnode *dvnode, *vnode;
914 struct afs_fid fid;
915 struct inode *inode;
916 struct key *key;
917 int ret;
918
919 dvnode = AFS_FS_I(dir);
920
921 _enter("{%x:%d},{%s},%o,",
922 dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
923
924 ret = -ENAMETOOLONG;
925 if (dentry->d_name.len > 255)
926 goto error;
927
928 key = afs_request_key(dvnode->volume->cell);
929 if (IS_ERR(key)) {
930 ret = PTR_ERR(key);
931 goto error;
932 }
933
934 mode |= S_IFREG;
935 ret = afs_vnode_create(dvnode, key, dentry->d_name.name,
936 mode, &fid, &status, &cb, &server);
937 if (ret < 0)
938 goto create_error;
939
940 inode = afs_iget(dir->i_sb, key, &fid, &status, &cb);
941 if (IS_ERR(inode)) {
942 /* ENOMEM at a really inconvenient time - just abandon the new
943 * directory on the server */
944 ret = PTR_ERR(inode);
945 goto iget_error;
946 }
947
948 /* apply the status report we've got for the new vnode */
949 vnode = AFS_FS_I(inode);
950 spin_lock(&vnode->lock);
951 vnode->update_cnt++;
952 spin_unlock(&vnode->lock);
953 afs_vnode_finalise_status_update(vnode, server);
954 afs_put_server(server);
955
956 d_instantiate(dentry, inode);
957 if (d_unhashed(dentry)) {
958 _debug("not hashed");
959 d_rehash(dentry);
960 }
961 key_put(key);
962 _leave(" = 0");
963 return 0;
964
965iget_error:
966 afs_put_server(server);
967create_error:
968 key_put(key);
969error:
970 d_drop(dentry);
971 _leave(" = %d", ret);
972 return ret;
973}
974
975/*
976 * create a hard link between files in an AFS filesystem
977 */
978static int afs_link(struct dentry *from, struct inode *dir,
979 struct dentry *dentry)
980{
981 struct afs_vnode *dvnode, *vnode;
982 struct key *key;
983 int ret;
984
985 vnode = AFS_FS_I(from->d_inode);
986 dvnode = AFS_FS_I(dir);
987
988 _enter("{%x:%d},{%x:%d},{%s}",
989 vnode->fid.vid, vnode->fid.vnode,
990 dvnode->fid.vid, dvnode->fid.vnode,
991 dentry->d_name.name);
992
993 ret = -ENAMETOOLONG;
994 if (dentry->d_name.len > 255)
995 goto error;
996
997 key = afs_request_key(dvnode->volume->cell);
998 if (IS_ERR(key)) {
999 ret = PTR_ERR(key);
1000 goto error;
1001 }
1002
1003 ret = afs_vnode_link(dvnode, vnode, key, dentry->d_name.name);
1004 if (ret < 0)
1005 goto link_error;
1006
1007 atomic_inc(&vnode->vfs_inode.i_count);
1008 d_instantiate(dentry, &vnode->vfs_inode);
1009 key_put(key);
1010 _leave(" = 0");
1011 return 0;
1012
1013link_error:
1014 key_put(key);
1015error:
1016 d_drop(dentry);
1017 _leave(" = %d", ret);
1018 return ret;
1019}
1020
1021/*
1022 * create a symlink in an AFS filesystem
1023 */
1024static int afs_symlink(struct inode *dir, struct dentry *dentry,
1025 const char *content)
1026{
1027 struct afs_file_status status;
1028 struct afs_server *server;
1029 struct afs_vnode *dvnode, *vnode;
1030 struct afs_fid fid;
1031 struct inode *inode;
1032 struct key *key;
1033 int ret;
1034
1035 dvnode = AFS_FS_I(dir);
1036
1037 _enter("{%x:%d},{%s},%s",
1038 dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name,
1039 content);
1040
1041 ret = -ENAMETOOLONG;
1042 if (dentry->d_name.len > 255)
1043 goto error;
1044
1045 ret = -EINVAL;
1046 if (strlen(content) > 1023)
1047 goto error;
1048
1049 key = afs_request_key(dvnode->volume->cell);
1050 if (IS_ERR(key)) {
1051 ret = PTR_ERR(key);
1052 goto error;
1053 }
1054
1055 ret = afs_vnode_symlink(dvnode, key, dentry->d_name.name, content,
1056 &fid, &status, &server);
1057 if (ret < 0)
1058 goto create_error;
1059
1060 inode = afs_iget(dir->i_sb, key, &fid, &status, NULL);
1061 if (IS_ERR(inode)) {
1062 /* ENOMEM at a really inconvenient time - just abandon the new
1063 * directory on the server */
1064 ret = PTR_ERR(inode);
1065 goto iget_error;
1066 }
1067
1068 /* apply the status report we've got for the new vnode */
1069 vnode = AFS_FS_I(inode);
1070 spin_lock(&vnode->lock);
1071 vnode->update_cnt++;
1072 spin_unlock(&vnode->lock);
1073 afs_vnode_finalise_status_update(vnode, server);
1074 afs_put_server(server);
1075
1076 d_instantiate(dentry, inode);
1077 if (d_unhashed(dentry)) {
1078 _debug("not hashed");
1079 d_rehash(dentry);
1080 }
1081 key_put(key);
1082 _leave(" = 0");
1083 return 0;
1084
1085iget_error:
1086 afs_put_server(server);
1087create_error:
1088 key_put(key);
1089error:
1090 d_drop(dentry);
1091 _leave(" = %d", ret);
1092 return ret;
1093}
1094
1095/*
1096 * rename a file in an AFS filesystem and/or move it between directories
1097 */
1098static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1099 struct inode *new_dir, struct dentry *new_dentry)
1100{
1101 struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
1102 struct key *key;
1103 int ret;
1104
1105 vnode = AFS_FS_I(old_dentry->d_inode);
1106 orig_dvnode = AFS_FS_I(old_dir);
1107 new_dvnode = AFS_FS_I(new_dir);
1108
1109 _enter("{%x:%d},{%x:%d},{%x:%d},{%s}",
1110 orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
1111 vnode->fid.vid, vnode->fid.vnode,
1112 new_dvnode->fid.vid, new_dvnode->fid.vnode,
1113 new_dentry->d_name.name);
1114
1115 ret = -ENAMETOOLONG;
1116 if (new_dentry->d_name.len > 255)
1117 goto error;
1118
1119 key = afs_request_key(orig_dvnode->volume->cell);
1120 if (IS_ERR(key)) {
1121 ret = PTR_ERR(key);
1122 goto error;
1123 }
1124
1125 ret = afs_vnode_rename(orig_dvnode, new_dvnode, key,
1126 old_dentry->d_name.name,
1127 new_dentry->d_name.name);
1128 if (ret < 0)
1129 goto rename_error;
1130 key_put(key);
1131 _leave(" = 0");
1132 return 0;
1133
1134rename_error:
1135 key_put(key);
1136error:
1137 d_drop(new_dentry);
1138 _leave(" = %d", ret);
1139 return ret;
1140}
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 101bbb8c0d8b..ae256498f4f7 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -50,6 +50,7 @@ int afs_open(struct inode *inode, struct file *file)
50{ 50{
51 struct afs_vnode *vnode = AFS_FS_I(inode); 51 struct afs_vnode *vnode = AFS_FS_I(inode);
52 struct key *key; 52 struct key *key;
53 int ret;
53 54
54 _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); 55 _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
55 56
@@ -59,6 +60,12 @@ int afs_open(struct inode *inode, struct file *file)
59 return PTR_ERR(key); 60 return PTR_ERR(key);
60 } 61 }
61 62
63 ret = afs_validate(vnode, key);
64 if (ret < 0) {
65 _leave(" = %d [val]", ret);
66 return ret;
67 }
68
62 file->private_data = key; 69 file->private_data = key;
63 _leave(" = 0"); 70 _leave(" = 0");
64 return 0; 71 return 0;
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 321b489aa90f..f036b4cc51a6 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -16,14 +16,28 @@
16#include "afs_fs.h" 16#include "afs_fs.h"
17 17
18/* 18/*
19 * decode an AFSFid block
20 */
21static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
22{
23 const __be32 *bp = *_bp;
24
25 fid->vid = ntohl(*bp++);
26 fid->vnode = ntohl(*bp++);
27 fid->unique = ntohl(*bp++);
28 *_bp = bp;
29}
30
31/*
19 * decode an AFSFetchStatus block 32 * decode an AFSFetchStatus block
20 */ 33 */
21static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 34static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
35 struct afs_file_status *status,
22 struct afs_vnode *vnode) 36 struct afs_vnode *vnode)
23{ 37{
24 const __be32 *bp = *_bp; 38 const __be32 *bp = *_bp;
25 umode_t mode; 39 umode_t mode;
26 u64 data_version; 40 u64 data_version, size;
27 u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ 41 u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
28 42
29#define EXTRACT(DST) \ 43#define EXTRACT(DST) \
@@ -33,55 +47,68 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
33 DST = x; \ 47 DST = x; \
34 } while (0) 48 } while (0)
35 49
36 vnode->status.if_version = ntohl(*bp++); 50 status->if_version = ntohl(*bp++);
37 EXTRACT(vnode->status.type); 51 EXTRACT(status->type);
38 vnode->status.nlink = ntohl(*bp++); 52 EXTRACT(status->nlink);
39 EXTRACT(vnode->status.size); 53 size = ntohl(*bp++);
40 data_version = ntohl(*bp++); 54 data_version = ntohl(*bp++);
41 EXTRACT(vnode->status.author); 55 EXTRACT(status->author);
42 EXTRACT(vnode->status.owner); 56 EXTRACT(status->owner);
43 EXTRACT(vnode->status.caller_access); /* call ticket dependent */ 57 EXTRACT(status->caller_access); /* call ticket dependent */
44 EXTRACT(vnode->status.anon_access); 58 EXTRACT(status->anon_access);
45 EXTRACT(vnode->status.mode); 59 EXTRACT(status->mode);
46 vnode->status.parent.vid = vnode->fid.vid; 60 EXTRACT(status->parent.vnode);
47 EXTRACT(vnode->status.parent.vnode); 61 EXTRACT(status->parent.unique);
48 EXTRACT(vnode->status.parent.unique);
49 bp++; /* seg size */ 62 bp++; /* seg size */
50 vnode->status.mtime_client = ntohl(*bp++); 63 status->mtime_client = ntohl(*bp++);
51 vnode->status.mtime_server = ntohl(*bp++); 64 status->mtime_server = ntohl(*bp++);
52 bp++; /* group */ 65 EXTRACT(status->group);
53 bp++; /* sync counter */ 66 bp++; /* sync counter */
54 data_version |= (u64) ntohl(*bp++) << 32; 67 data_version |= (u64) ntohl(*bp++) << 32;
55 bp++; /* spare2 */ 68 bp++; /* lock count */
56 bp++; /* spare3 */ 69 size |= (u64) ntohl(*bp++) << 32;
57 bp++; /* spare4 */ 70 bp++; /* spare 4 */
58 *_bp = bp; 71 *_bp = bp;
59 72
60 if (changed) { 73 if (size != status->size) {
61 _debug("vnode changed"); 74 status->size = size;
62 set_bit(AFS_VNODE_CHANGED, &vnode->flags); 75 changed |= true;
63 vnode->vfs_inode.i_uid = vnode->status.owner;
64 vnode->vfs_inode.i_size = vnode->status.size;
65 vnode->vfs_inode.i_version = vnode->fid.unique;
66
67 vnode->status.mode &= S_IALLUGO;
68 mode = vnode->vfs_inode.i_mode;
69 mode &= ~S_IALLUGO;
70 mode |= vnode->status.mode;
71 vnode->vfs_inode.i_mode = mode;
72 } 76 }
77 status->mode &= S_IALLUGO;
73 78
74 _debug("vnode time %lx, %lx", 79 _debug("vnode time %lx, %lx",
75 vnode->status.mtime_client, vnode->status.mtime_server); 80 status->mtime_client, status->mtime_server);
76 vnode->vfs_inode.i_ctime.tv_sec = vnode->status.mtime_server; 81
77 vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; 82 if (vnode) {
78 vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; 83 status->parent.vid = vnode->fid.vid;
79 84 if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
80 if (vnode->status.data_version != data_version) { 85 _debug("vnode changed");
81 _debug("vnode modified %llx", data_version); 86 i_size_write(&vnode->vfs_inode, size);
82 vnode->status.data_version = data_version; 87 vnode->vfs_inode.i_uid = status->owner;
83 set_bit(AFS_VNODE_MODIFIED, &vnode->flags); 88 vnode->vfs_inode.i_gid = status->group;
84 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 89 vnode->vfs_inode.i_version = vnode->fid.unique;
90 vnode->vfs_inode.i_nlink = status->nlink;
91
92 mode = vnode->vfs_inode.i_mode;
93 mode &= ~S_IALLUGO;
94 mode |= status->mode;
95 barrier();
96 vnode->vfs_inode.i_mode = mode;
97 }
98
99 vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server;
100 vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime;
101 vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime;
102 }
103
104 if (status->data_version != data_version) {
105 status->data_version = data_version;
106 if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
107 _debug("vnode modified %llx on {%x:%u}",
108 data_version, vnode->fid.vid, vnode->fid.vnode);
109 set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
110 set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
111 }
85 } 112 }
86} 113}
87 114
@@ -99,6 +126,17 @@ static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
99 *_bp = bp; 126 *_bp = bp;
100} 127}
101 128
129static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
130 struct afs_callback *cb)
131{
132 const __be32 *bp = *_bp;
133
134 cb->version = ntohl(*bp++);
135 cb->expiry = ntohl(*bp++);
136 cb->type = ntohl(*bp++);
137 *_bp = bp;
138}
139
102/* 140/*
103 * decode an AFSVolSync block 141 * decode an AFSVolSync block
104 */ 142 */
@@ -122,6 +160,7 @@ static void xdr_decode_AFSVolSync(const __be32 **_bp,
122static int afs_deliver_fs_fetch_status(struct afs_call *call, 160static int afs_deliver_fs_fetch_status(struct afs_call *call,
123 struct sk_buff *skb, bool last) 161 struct sk_buff *skb, bool last)
124{ 162{
163 struct afs_vnode *vnode = call->reply;
125 const __be32 *bp; 164 const __be32 *bp;
126 165
127 _enter(",,%u", last); 166 _enter(",,%u", last);
@@ -135,8 +174,8 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call,
135 174
136 /* unmarshall the reply once we've received all of it */ 175 /* unmarshall the reply once we've received all of it */
137 bp = call->buffer; 176 bp = call->buffer;
138 xdr_decode_AFSFetchStatus(&bp, call->reply); 177 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
139 xdr_decode_AFSCallBack(&bp, call->reply); 178 xdr_decode_AFSCallBack(&bp, vnode);
140 if (call->reply2) 179 if (call->reply2)
141 xdr_decode_AFSVolSync(&bp, call->reply2); 180 xdr_decode_AFSVolSync(&bp, call->reply2);
142 181
@@ -166,9 +205,10 @@ int afs_fs_fetch_file_status(struct afs_server *server,
166 struct afs_call *call; 205 struct afs_call *call;
167 __be32 *bp; 206 __be32 *bp;
168 207
169 _enter(",%x,,,", key_serial(key)); 208 _enter(",%x,{%x:%d},,",
209 key_serial(key), vnode->fid.vid, vnode->fid.vnode);
170 210
171 call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120); 211 call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
172 if (!call) 212 if (!call)
173 return -ENOMEM; 213 return -ENOMEM;
174 214
@@ -194,6 +234,7 @@ int afs_fs_fetch_file_status(struct afs_server *server,
194static int afs_deliver_fs_fetch_data(struct afs_call *call, 234static int afs_deliver_fs_fetch_data(struct afs_call *call,
195 struct sk_buff *skb, bool last) 235 struct sk_buff *skb, bool last)
196{ 236{
237 struct afs_vnode *vnode = call->reply;
197 const __be32 *bp; 238 const __be32 *bp;
198 struct page *page; 239 struct page *page;
199 void *buffer; 240 void *buffer;
@@ -248,7 +289,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
248 289
249 /* extract the metadata */ 290 /* extract the metadata */
250 case 3: 291 case 3:
251 ret = afs_extract_data(call, skb, last, call->buffer, 120); 292 ret = afs_extract_data(call, skb, last, call->buffer,
293 (21 + 3 + 6) * 4);
252 switch (ret) { 294 switch (ret) {
253 case 0: break; 295 case 0: break;
254 case -EAGAIN: return 0; 296 case -EAGAIN: return 0;
@@ -256,8 +298,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
256 } 298 }
257 299
258 bp = call->buffer; 300 bp = call->buffer;
259 xdr_decode_AFSFetchStatus(&bp, call->reply); 301 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
260 xdr_decode_AFSCallBack(&bp, call->reply); 302 xdr_decode_AFSCallBack(&bp, vnode);
261 if (call->reply2) 303 if (call->reply2)
262 xdr_decode_AFSVolSync(&bp, call->reply2); 304 xdr_decode_AFSVolSync(&bp, call->reply2);
263 305
@@ -296,7 +338,6 @@ int afs_fs_fetch_data(struct afs_server *server,
296 struct afs_vnode *vnode, 338 struct afs_vnode *vnode,
297 off_t offset, size_t length, 339 off_t offset, size_t length,
298 struct page *buffer, 340 struct page *buffer,
299 struct afs_volsync *volsync,
300 const struct afs_wait_mode *wait_mode) 341 const struct afs_wait_mode *wait_mode)
301{ 342{
302 struct afs_call *call; 343 struct afs_call *call;
@@ -304,13 +345,13 @@ int afs_fs_fetch_data(struct afs_server *server,
304 345
305 _enter(""); 346 _enter("");
306 347
307 call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, 120); 348 call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
308 if (!call) 349 if (!call)
309 return -ENOMEM; 350 return -ENOMEM;
310 351
311 call->key = key; 352 call->key = key;
312 call->reply = vnode; 353 call->reply = vnode;
313 call->reply2 = volsync; 354 call->reply2 = NULL; /* volsync */
314 call->reply3 = buffer; 355 call->reply3 = buffer;
315 call->service_id = FS_SERVICE; 356 call->service_id = FS_SERVICE;
316 call->port = htons(AFS_FS_PORT); 357 call->port = htons(AFS_FS_PORT);
@@ -411,3 +452,485 @@ int afs_fs_give_up_callbacks(struct afs_server *server,
411 452
412 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 453 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
413} 454}
455
456/*
457 * deliver reply data to an FS.CreateFile or an FS.MakeDir
458 */
459static int afs_deliver_fs_create_vnode(struct afs_call *call,
460 struct sk_buff *skb, bool last)
461{
462 struct afs_vnode *vnode = call->reply;
463 const __be32 *bp;
464
465 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
466
467 afs_transfer_reply(call, skb);
468 if (!last)
469 return 0;
470
471 if (call->reply_size != call->reply_max)
472 return -EBADMSG;
473
474 /* unmarshall the reply once we've received all of it */
475 bp = call->buffer;
476 xdr_decode_AFSFid(&bp, call->reply2);
477 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
478 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
479 xdr_decode_AFSCallBack_raw(&bp, call->reply4);
480 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
481
482 _leave(" = 0 [done]");
483 return 0;
484}
485
486/*
487 * FS.CreateFile and FS.MakeDir operation type
488 */
489static const struct afs_call_type afs_RXFSCreateXXXX = {
490 .name = "FS.CreateXXXX",
491 .deliver = afs_deliver_fs_create_vnode,
492 .abort_to_error = afs_abort_to_error,
493 .destructor = afs_flat_call_destructor,
494};
495
496/*
497 * create a file or make a directory
498 */
499int afs_fs_create(struct afs_server *server,
500 struct key *key,
501 struct afs_vnode *vnode,
502 const char *name,
503 umode_t mode,
504 struct afs_fid *newfid,
505 struct afs_file_status *newstatus,
506 struct afs_callback *newcb,
507 const struct afs_wait_mode *wait_mode)
508{
509 struct afs_call *call;
510 size_t namesz, reqsz, padsz;
511 __be32 *bp;
512
513 _enter("");
514
515 namesz = strlen(name);
516 padsz = (4 - (namesz & 3)) & 3;
517 reqsz = (5 * 4) + namesz + padsz + (6 * 4);
518
519 call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
520 (3 + 21 + 21 + 3 + 6) * 4);
521 if (!call)
522 return -ENOMEM;
523
524 call->key = key;
525 call->reply = vnode;
526 call->reply2 = newfid;
527 call->reply3 = newstatus;
528 call->reply4 = newcb;
529 call->service_id = FS_SERVICE;
530 call->port = htons(AFS_FS_PORT);
531
532 /* marshall the parameters */
533 bp = call->request;
534 *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
535 *bp++ = htonl(vnode->fid.vid);
536 *bp++ = htonl(vnode->fid.vnode);
537 *bp++ = htonl(vnode->fid.unique);
538 *bp++ = htonl(namesz);
539 memcpy(bp, name, namesz);
540 bp = (void *) bp + namesz;
541 if (padsz > 0) {
542 memset(bp, 0, padsz);
543 bp = (void *) bp + padsz;
544 }
545 *bp++ = htonl(AFS_SET_MODE);
546 *bp++ = 0; /* mtime */
547 *bp++ = 0; /* owner */
548 *bp++ = 0; /* group */
549 *bp++ = htonl(mode & S_IALLUGO); /* unix mode */
550 *bp++ = 0; /* segment size */
551
552 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
553}
554
555/*
556 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
557 */
558static int afs_deliver_fs_remove(struct afs_call *call,
559 struct sk_buff *skb, bool last)
560{
561 struct afs_vnode *vnode = call->reply;
562 const __be32 *bp;
563
564 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
565
566 afs_transfer_reply(call, skb);
567 if (!last)
568 return 0;
569
570 if (call->reply_size != call->reply_max)
571 return -EBADMSG;
572
573 /* unmarshall the reply once we've received all of it */
574 bp = call->buffer;
575 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
576 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
577
578 _leave(" = 0 [done]");
579 return 0;
580}
581
582/*
583 * FS.RemoveDir/FS.RemoveFile operation type
584 */
585static const struct afs_call_type afs_RXFSRemoveXXXX = {
586 .name = "FS.RemoveXXXX",
587 .deliver = afs_deliver_fs_remove,
588 .abort_to_error = afs_abort_to_error,
589 .destructor = afs_flat_call_destructor,
590};
591
592/*
593 * remove a file or directory
594 */
595int afs_fs_remove(struct afs_server *server,
596 struct key *key,
597 struct afs_vnode *vnode,
598 const char *name,
599 bool isdir,
600 const struct afs_wait_mode *wait_mode)
601{
602 struct afs_call *call;
603 size_t namesz, reqsz, padsz;
604 __be32 *bp;
605
606 _enter("");
607
608 namesz = strlen(name);
609 padsz = (4 - (namesz & 3)) & 3;
610 reqsz = (5 * 4) + namesz + padsz;
611
612 call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
613 if (!call)
614 return -ENOMEM;
615
616 call->key = key;
617 call->reply = vnode;
618 call->service_id = FS_SERVICE;
619 call->port = htons(AFS_FS_PORT);
620
621 /* marshall the parameters */
622 bp = call->request;
623 *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
624 *bp++ = htonl(vnode->fid.vid);
625 *bp++ = htonl(vnode->fid.vnode);
626 *bp++ = htonl(vnode->fid.unique);
627 *bp++ = htonl(namesz);
628 memcpy(bp, name, namesz);
629 bp = (void *) bp + namesz;
630 if (padsz > 0) {
631 memset(bp, 0, padsz);
632 bp = (void *) bp + padsz;
633 }
634
635 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
636}
637
638/*
639 * deliver reply data to an FS.Link
640 */
641static int afs_deliver_fs_link(struct afs_call *call,
642 struct sk_buff *skb, bool last)
643{
644 struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
645 const __be32 *bp;
646
647 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
648
649 afs_transfer_reply(call, skb);
650 if (!last)
651 return 0;
652
653 if (call->reply_size != call->reply_max)
654 return -EBADMSG;
655
656 /* unmarshall the reply once we've received all of it */
657 bp = call->buffer;
658 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
659 xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode);
660 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
661
662 _leave(" = 0 [done]");
663 return 0;
664}
665
666/*
667 * FS.Link operation type
668 */
669static const struct afs_call_type afs_RXFSLink = {
670 .name = "FS.Link",
671 .deliver = afs_deliver_fs_link,
672 .abort_to_error = afs_abort_to_error,
673 .destructor = afs_flat_call_destructor,
674};
675
676/*
677 * make a hard link
678 */
679int afs_fs_link(struct afs_server *server,
680 struct key *key,
681 struct afs_vnode *dvnode,
682 struct afs_vnode *vnode,
683 const char *name,
684 const struct afs_wait_mode *wait_mode)
685{
686 struct afs_call *call;
687 size_t namesz, reqsz, padsz;
688 __be32 *bp;
689
690 _enter("");
691
692 namesz = strlen(name);
693 padsz = (4 - (namesz & 3)) & 3;
694 reqsz = (5 * 4) + namesz + padsz + (3 * 4);
695
696 call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
697 if (!call)
698 return -ENOMEM;
699
700 call->key = key;
701 call->reply = dvnode;
702 call->reply2 = vnode;
703 call->service_id = FS_SERVICE;
704 call->port = htons(AFS_FS_PORT);
705
706 /* marshall the parameters */
707 bp = call->request;
708 *bp++ = htonl(FSLINK);
709 *bp++ = htonl(dvnode->fid.vid);
710 *bp++ = htonl(dvnode->fid.vnode);
711 *bp++ = htonl(dvnode->fid.unique);
712 *bp++ = htonl(namesz);
713 memcpy(bp, name, namesz);
714 bp = (void *) bp + namesz;
715 if (padsz > 0) {
716 memset(bp, 0, padsz);
717 bp = (void *) bp + padsz;
718 }
719 *bp++ = htonl(vnode->fid.vid);
720 *bp++ = htonl(vnode->fid.vnode);
721 *bp++ = htonl(vnode->fid.unique);
722
723 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
724}
725
726/*
727 * deliver reply data to an FS.Symlink
728 */
729static int afs_deliver_fs_symlink(struct afs_call *call,
730 struct sk_buff *skb, bool last)
731{
732 struct afs_vnode *vnode = call->reply;
733 const __be32 *bp;
734
735 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
736
737 afs_transfer_reply(call, skb);
738 if (!last)
739 return 0;
740
741 if (call->reply_size != call->reply_max)
742 return -EBADMSG;
743
744 /* unmarshall the reply once we've received all of it */
745 bp = call->buffer;
746 xdr_decode_AFSFid(&bp, call->reply2);
747 xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
748 xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
749 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
750
751 _leave(" = 0 [done]");
752 return 0;
753}
754
755/*
756 * FS.Symlink operation type
757 */
758static const struct afs_call_type afs_RXFSSymlink = {
759 .name = "FS.Symlink",
760 .deliver = afs_deliver_fs_symlink,
761 .abort_to_error = afs_abort_to_error,
762 .destructor = afs_flat_call_destructor,
763};
764
765/*
766 * create a symbolic link
767 */
768int afs_fs_symlink(struct afs_server *server,
769 struct key *key,
770 struct afs_vnode *vnode,
771 const char *name,
772 const char *contents,
773 struct afs_fid *newfid,
774 struct afs_file_status *newstatus,
775 const struct afs_wait_mode *wait_mode)
776{
777 struct afs_call *call;
778 size_t namesz, reqsz, padsz, c_namesz, c_padsz;
779 __be32 *bp;
780
781 _enter("");
782
783 namesz = strlen(name);
784 padsz = (4 - (namesz & 3)) & 3;
785
786 c_namesz = strlen(contents);
787 c_padsz = (4 - (c_namesz & 3)) & 3;
788
789 reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
790
791 call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
792 (3 + 21 + 21 + 6) * 4);
793 if (!call)
794 return -ENOMEM;
795
796 call->key = key;
797 call->reply = vnode;
798 call->reply2 = newfid;
799 call->reply3 = newstatus;
800 call->service_id = FS_SERVICE;
801 call->port = htons(AFS_FS_PORT);
802
803 /* marshall the parameters */
804 bp = call->request;
805 *bp++ = htonl(FSSYMLINK);
806 *bp++ = htonl(vnode->fid.vid);
807 *bp++ = htonl(vnode->fid.vnode);
808 *bp++ = htonl(vnode->fid.unique);
809 *bp++ = htonl(namesz);
810 memcpy(bp, name, namesz);
811 bp = (void *) bp + namesz;
812 if (padsz > 0) {
813 memset(bp, 0, padsz);
814 bp = (void *) bp + padsz;
815 }
816 *bp++ = htonl(c_namesz);
817 memcpy(bp, contents, c_namesz);
818 bp = (void *) bp + c_namesz;
819 if (c_padsz > 0) {
820 memset(bp, 0, c_padsz);
821 bp = (void *) bp + c_padsz;
822 }
823 *bp++ = htonl(AFS_SET_MODE);
824 *bp++ = 0; /* mtime */
825 *bp++ = 0; /* owner */
826 *bp++ = 0; /* group */
827 *bp++ = htonl(S_IRWXUGO); /* unix mode */
828 *bp++ = 0; /* segment size */
829
830 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
831}
832
833/*
834 * deliver reply data to an FS.Rename
835 */
836static int afs_deliver_fs_rename(struct afs_call *call,
837 struct sk_buff *skb, bool last)
838{
839 struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
840 const __be32 *bp;
841
842 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
843
844 afs_transfer_reply(call, skb);
845 if (!last)
846 return 0;
847
848 if (call->reply_size != call->reply_max)
849 return -EBADMSG;
850
851 /* unmarshall the reply once we've received all of it */
852 bp = call->buffer;
853 xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode);
854 if (new_dvnode != orig_dvnode)
855 xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode);
856 /* xdr_decode_AFSVolSync(&bp, call->replyX); */
857
858 _leave(" = 0 [done]");
859 return 0;
860}
861
862/*
863 * FS.Rename operation type
864 */
865static const struct afs_call_type afs_RXFSRename = {
866 .name = "FS.Rename",
867 .deliver = afs_deliver_fs_rename,
868 .abort_to_error = afs_abort_to_error,
869 .destructor = afs_flat_call_destructor,
870};
871
872/*
873 * create a symbolic link
874 */
875int afs_fs_rename(struct afs_server *server,
876 struct key *key,
877 struct afs_vnode *orig_dvnode,
878 const char *orig_name,
879 struct afs_vnode *new_dvnode,
880 const char *new_name,
881 const struct afs_wait_mode *wait_mode)
882{
883 struct afs_call *call;
884 size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
885 __be32 *bp;
886
887 _enter("");
888
889 o_namesz = strlen(orig_name);
890 o_padsz = (4 - (o_namesz & 3)) & 3;
891
892 n_namesz = strlen(new_name);
893 n_padsz = (4 - (n_namesz & 3)) & 3;
894
895 reqsz = (4 * 4) +
896 4 + o_namesz + o_padsz +
897 (3 * 4) +
898 4 + n_namesz + n_padsz;
899
900 call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
901 if (!call)
902 return -ENOMEM;
903
904 call->key = key;
905 call->reply = orig_dvnode;
906 call->reply2 = new_dvnode;
907 call->service_id = FS_SERVICE;
908 call->port = htons(AFS_FS_PORT);
909
910 /* marshall the parameters */
911 bp = call->request;
912 *bp++ = htonl(FSRENAME);
913 *bp++ = htonl(orig_dvnode->fid.vid);
914 *bp++ = htonl(orig_dvnode->fid.vnode);
915 *bp++ = htonl(orig_dvnode->fid.unique);
916 *bp++ = htonl(o_namesz);
917 memcpy(bp, orig_name, o_namesz);
918 bp = (void *) bp + o_namesz;
919 if (o_padsz > 0) {
920 memset(bp, 0, o_padsz);
921 bp = (void *) bp + o_padsz;
922 }
923
924 *bp++ = htonl(new_dvnode->fid.vid);
925 *bp++ = htonl(new_dvnode->fid.vnode);
926 *bp++ = htonl(new_dvnode->fid.unique);
927 *bp++ = htonl(n_namesz);
928 memcpy(bp, new_name, n_namesz);
929 bp = (void *) bp + n_namesz;
930 if (n_padsz > 0) {
931 memset(bp, 0, n_padsz);
932 bp = (void *) bp + n_padsz;
933 }
934
935 return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
936}
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 227336228299..56ca8581b37f 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -33,7 +33,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
33{ 33{
34 struct inode *inode = AFS_VNODE_TO_I(vnode); 34 struct inode *inode = AFS_VNODE_TO_I(vnode);
35 35
36 _debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu", 36 _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
37 vnode->status.type, 37 vnode->status.type,
38 vnode->status.nlink, 38 vnode->status.nlink,
39 vnode->status.size, 39 vnode->status.size,
@@ -115,8 +115,9 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
115/* 115/*
116 * inode retrieval 116 * inode retrieval
117 */ 117 */
118inline struct inode *afs_iget(struct super_block *sb, struct key *key, 118struct inode *afs_iget(struct super_block *sb, struct key *key,
119 struct afs_fid *fid) 119 struct afs_fid *fid, struct afs_file_status *status,
120 struct afs_callback *cb)
120{ 121{
121 struct afs_iget_data data = { .fid = *fid }; 122 struct afs_iget_data data = { .fid = *fid };
122 struct afs_super_info *as; 123 struct afs_super_info *as;
@@ -156,16 +157,37 @@ inline struct inode *afs_iget(struct super_block *sb, struct key *key,
156 &vnode->cache); 157 &vnode->cache);
157#endif 158#endif
158 159
159 /* okay... it's a new inode */ 160 if (!status) {
160 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); 161 /* it's a remotely extant inode */
161 ret = afs_vnode_fetch_status(vnode, NULL, key); 162 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
162 if (ret < 0) 163 ret = afs_vnode_fetch_status(vnode, NULL, key);
163 goto bad_inode; 164 if (ret < 0)
165 goto bad_inode;
166 } else {
167 /* it's an inode we just created */
168 memcpy(&vnode->status, status, sizeof(vnode->status));
169
170 if (!cb) {
171 /* it's a symlink we just created (the fileserver
172 * didn't give us a callback) */
173 vnode->cb_version = 0;
174 vnode->cb_expiry = 0;
175 vnode->cb_type = 0;
176 vnode->cb_expires = get_seconds();
177 } else {
178 vnode->cb_version = cb->version;
179 vnode->cb_expiry = cb->expiry;
180 vnode->cb_type = cb->type;
181 vnode->cb_expires = vnode->cb_expiry + get_seconds();
182 }
183 }
184
164 ret = afs_inode_map_status(vnode, key); 185 ret = afs_inode_map_status(vnode, key);
165 if (ret < 0) 186 if (ret < 0)
166 goto bad_inode; 187 goto bad_inode;
167 188
168 /* success */ 189 /* success */
190 clear_bit(AFS_VNODE_UNSET, &vnode->flags);
169 inode->i_flags |= S_NOATIME; 191 inode->i_flags |= S_NOATIME;
170 unlock_new_inode(inode); 192 unlock_new_inode(inode);
171 _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type); 193 _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type);
@@ -182,6 +204,78 @@ bad_inode:
182} 204}
183 205
184/* 206/*
207 * validate a vnode/inode
208 * - there are several things we need to check
209 * - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
210 * symlink)
211 * - parent dir metadata changed (security changes)
212 * - dentry data changed (write, truncate)
213 * - dentry metadata changed (security changes)
214 */
215int afs_validate(struct afs_vnode *vnode, struct key *key)
216{
217 int ret;
218
219 _enter("{v={%x:%u} fl=%lx},%x",
220 vnode->fid.vid, vnode->fid.vnode, vnode->flags,
221 key_serial(key));
222
223 if (vnode->cb_promised &&
224 !test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
225 !test_bit(AFS_VNODE_MODIFIED, &vnode->flags) &&
226 !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
227 if (vnode->cb_expires < get_seconds() + 10) {
228 _debug("callback expired");
229 set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
230 } else {
231 goto valid;
232 }
233 }
234
235 if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
236 goto valid;
237
238 mutex_lock(&vnode->validate_lock);
239
240 /* if the promise has expired, we need to check the server again to get
241 * a new promise - note that if the (parent) directory's metadata was
242 * changed then the security may be different and we may no longer have
243 * access */
244 if (!vnode->cb_promised ||
245 test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
246 _debug("not promised");
247 ret = afs_vnode_fetch_status(vnode, NULL, key);
248 if (ret < 0)
249 goto error_unlock;
250 _debug("new promise [fl=%lx]", vnode->flags);
251 }
252
253 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
254 _debug("file already deleted");
255 ret = -ESTALE;
256 goto error_unlock;
257 }
258
259 /* if the vnode's data version number changed then its contents are
260 * different */
261 if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
262 _debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode);
263 invalidate_remote_inode(&vnode->vfs_inode);
264 }
265
266 clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
267 mutex_unlock(&vnode->validate_lock);
268valid:
269 _leave(" = 0");
270 return 0;
271
272error_unlock:
273 mutex_unlock(&vnode->validate_lock);
274 _leave(" = %d", ret);
275 return ret;
276}
277
278/*
185 * read the attributes of an inode 279 * read the attributes of an inode
186 */ 280 */
187int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, 281int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
@@ -207,9 +301,10 @@ void afs_clear_inode(struct inode *inode)
207 301
208 vnode = AFS_FS_I(inode); 302 vnode = AFS_FS_I(inode);
209 303
210 _enter("ino=%lu { vn=%08x v=%u x=%u t=%u }", 304 _enter("{%x:%d.%d} v=%u x=%u t=%u }",
211 inode->i_ino, 305 vnode->fid.vid,
212 vnode->fid.vnode, 306 vnode->fid.vnode,
307 vnode->fid.unique,
213 vnode->cb_version, 308 vnode->cb_version,
214 vnode->cb_expiry, 309 vnode->cb_expiry,
215 vnode->cb_type); 310 vnode->cb_type);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 6120d4bd19e0..73bfa0b2d99e 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -80,6 +80,7 @@ struct afs_call {
80 void *reply; /* reply buffer (first part) */ 80 void *reply; /* reply buffer (first part) */
81 void *reply2; /* reply buffer (second part) */ 81 void *reply2; /* reply buffer (second part) */
82 void *reply3; /* reply buffer (third part) */ 82 void *reply3; /* reply buffer (third part) */
83 void *reply4; /* reply buffer (fourth part) */
83 enum { /* call state */ 84 enum { /* call state */
84 AFS_CALL_REQUESTING, /* request is being sent for outgoing call */ 85 AFS_CALL_REQUESTING, /* request is being sent for outgoing call */
85 AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */ 86 AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */
@@ -300,19 +301,18 @@ struct afs_vnode {
300#endif 301#endif
301 struct afs_permits *permits; /* cache of permits so far obtained */ 302 struct afs_permits *permits; /* cache of permits so far obtained */
302 struct mutex permits_lock; /* lock for altering permits list */ 303 struct mutex permits_lock; /* lock for altering permits list */
304 struct mutex validate_lock; /* lock for validating this vnode */
303 wait_queue_head_t update_waitq; /* status fetch waitqueue */ 305 wait_queue_head_t update_waitq; /* status fetch waitqueue */
304 unsigned update_cnt; /* number of outstanding ops that will update the 306 int update_cnt; /* number of outstanding ops that will update the
305 * status */ 307 * status */
306 spinlock_t lock; /* waitqueue/flags lock */ 308 spinlock_t lock; /* waitqueue/flags lock */
307 unsigned long flags; 309 unsigned long flags;
308#define AFS_VNODE_CB_BROKEN 0 /* set if vnode's callback was broken */ 310#define AFS_VNODE_CB_BROKEN 0 /* set if vnode's callback was broken */
309#define AFS_VNODE_CHANGED 1 /* set if vnode's metadata changed */ 311#define AFS_VNODE_UNSET 1 /* set if vnode attributes not yet set */
310#define AFS_VNODE_MODIFIED 2 /* set if vnode's data modified */ 312#define AFS_VNODE_MODIFIED 2 /* set if vnode's data modified */
311#define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */ 313#define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */
312#define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */ 314#define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */
313#define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */ 315#define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */
314#define AFS_VNODE_DIR_CHANGED 6 /* set if vnode's parent dir metadata changed */
315#define AFS_VNODE_DIR_MODIFIED 7 /* set if vnode's parent dir data modified */
316 316
317 long acl_order; /* ACL check count (callback break count) */ 317 long acl_order; /* ACL check count (callback break count) */
318 318
@@ -320,7 +320,6 @@ struct afs_vnode {
320 struct rb_node server_rb; /* link in server->fs_vnodes */ 320 struct rb_node server_rb; /* link in server->fs_vnodes */
321 struct rb_node cb_promise; /* link in server->cb_promises */ 321 struct rb_node cb_promise; /* link in server->cb_promises */
322 struct work_struct cb_broken_work; /* work to be done on callback break */ 322 struct work_struct cb_broken_work; /* work to be done on callback break */
323 struct mutex cb_broken_lock; /* lock against multiple attempts to fix break */
324 time_t cb_expires; /* time at which callback expires */ 323 time_t cb_expires; /* time at which callback expires */
325 time_t cb_expires_at; /* time used to order cb_promise */ 324 time_t cb_expires_at; /* time used to order cb_promise */
326 unsigned cb_version; /* callback version */ 325 unsigned cb_version; /* callback version */
@@ -388,6 +387,7 @@ extern void afs_init_callback_state(struct afs_server *);
388extern void afs_broken_callback_work(struct work_struct *); 387extern void afs_broken_callback_work(struct work_struct *);
389extern void afs_break_callbacks(struct afs_server *, size_t, 388extern void afs_break_callbacks(struct afs_server *, size_t,
390 struct afs_callback[]); 389 struct afs_callback[]);
390extern void afs_discard_callback_on_delete(struct afs_vnode *);
391extern void afs_give_up_callback(struct afs_vnode *); 391extern void afs_give_up_callback(struct afs_vnode *);
392extern void afs_dispatch_give_up_callbacks(struct work_struct *); 392extern void afs_dispatch_give_up_callbacks(struct work_struct *);
393extern void afs_flush_callback_breaks(struct afs_server *); 393extern void afs_flush_callback_breaks(struct afs_server *);
@@ -448,14 +448,34 @@ extern int afs_fs_give_up_callbacks(struct afs_server *,
448 const struct afs_wait_mode *); 448 const struct afs_wait_mode *);
449extern int afs_fs_fetch_data(struct afs_server *, struct key *, 449extern int afs_fs_fetch_data(struct afs_server *, struct key *,
450 struct afs_vnode *, off_t, size_t, struct page *, 450 struct afs_vnode *, off_t, size_t, struct page *,
451 struct afs_volsync *,
452 const struct afs_wait_mode *); 451 const struct afs_wait_mode *);
452extern int afs_fs_create(struct afs_server *, struct key *,
453 struct afs_vnode *, const char *, umode_t,
454 struct afs_fid *, struct afs_file_status *,
455 struct afs_callback *,
456 const struct afs_wait_mode *);
457extern int afs_fs_remove(struct afs_server *, struct key *,
458 struct afs_vnode *, const char *, bool,
459 const struct afs_wait_mode *);
460extern int afs_fs_link(struct afs_server *, struct key *, struct afs_vnode *,
461 struct afs_vnode *, const char *,
462 const struct afs_wait_mode *);
463extern int afs_fs_symlink(struct afs_server *, struct key *,
464 struct afs_vnode *, const char *, const char *,
465 struct afs_fid *, struct afs_file_status *,
466 const struct afs_wait_mode *);
467extern int afs_fs_rename(struct afs_server *, struct key *,
468 struct afs_vnode *, const char *,
469 struct afs_vnode *, const char *,
470 const struct afs_wait_mode *);
453 471
454/* 472/*
455 * inode.c 473 * inode.c
456 */ 474 */
457extern struct inode *afs_iget(struct super_block *, struct key *, 475extern struct inode *afs_iget(struct super_block *, struct key *,
458 struct afs_fid *); 476 struct afs_fid *, struct afs_file_status *,
477 struct afs_callback *);
478extern int afs_validate(struct afs_vnode *, struct key *);
459extern int afs_inode_getattr(struct vfsmount *, struct dentry *, 479extern int afs_inode_getattr(struct vfsmount *, struct dentry *,
460 struct kstat *); 480 struct kstat *);
461extern void afs_zap_permits(struct rcu_head *); 481extern void afs_zap_permits(struct rcu_head *);
@@ -522,7 +542,11 @@ extern int afs_permission(struct inode *, int, struct nameidata *);
522 */ 542 */
523extern spinlock_t afs_server_peer_lock; 543extern spinlock_t afs_server_peer_lock;
524 544
525#define afs_get_server(S) do { atomic_inc(&(S)->usage); } while(0) 545#define afs_get_server(S) \
546do { \
547 _debug("GET SERVER %d", atomic_read(&(S)->usage)); \
548 atomic_inc(&(S)->usage); \
549} while(0)
526 550
527extern struct afs_server *afs_lookup_server(struct afs_cell *, 551extern struct afs_server *afs_lookup_server(struct afs_cell *,
528 const struct in_addr *); 552 const struct in_addr *);
@@ -588,10 +612,24 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode)
588 return &vnode->vfs_inode; 612 return &vnode->vfs_inode;
589} 613}
590 614
615extern void afs_vnode_finalise_status_update(struct afs_vnode *,
616 struct afs_server *);
591extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *, 617extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *,
592 struct key *); 618 struct key *);
593extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *, 619extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *,
594 off_t, size_t, struct page *); 620 off_t, size_t, struct page *);
621extern int afs_vnode_create(struct afs_vnode *, struct key *, const char *,
622 umode_t, struct afs_fid *, struct afs_file_status *,
623 struct afs_callback *, struct afs_server **);
624extern int afs_vnode_remove(struct afs_vnode *, struct key *, const char *,
625 bool);
626extern int afs_vnode_link(struct afs_vnode *, struct afs_vnode *, struct key *,
627 const char *);
628extern int afs_vnode_symlink(struct afs_vnode *, struct key *, const char *,
629 const char *, struct afs_fid *,
630 struct afs_file_status *, struct afs_server **);
631extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *,
632 struct key *, const char *, const char *);
595 633
596/* 634/*
597 * volume.c 635 * volume.c
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
index 98e9276c46a2..cdb9792d8161 100644
--- a/fs/afs/misc.c
+++ b/fs/afs/misc.c
@@ -22,6 +22,7 @@ int afs_abort_to_error(u32 abort_code)
22{ 22{
23 switch (abort_code) { 23 switch (abort_code) {
24 case 13: return -EACCES; 24 case 13: return -EACCES;
25 case 30: return -EROFS;
25 case VSALVAGE: return -EIO; 26 case VSALVAGE: return -EIO;
26 case VNOVNODE: return -ENOENT; 27 case VNOVNODE: return -ENOENT;
27 case VNOVOL: return -ENOMEDIUM; 28 case VNOVOL: return -ENOMEDIUM;
@@ -33,6 +34,24 @@ int afs_abort_to_error(u32 abort_code)
33 case VOVERQUOTA: return -EDQUOT; 34 case VOVERQUOTA: return -EDQUOT;
34 case VBUSY: return -EBUSY; 35 case VBUSY: return -EBUSY;
35 case VMOVED: return -ENXIO; 36 case VMOVED: return -ENXIO;
36 default: return -EIO; 37 case 0x2f6df0c: return -EACCES;
38 case 0x2f6df0f: return -EBUSY;
39 case 0x2f6df10: return -EEXIST;
40 case 0x2f6df11: return -EXDEV;
41 case 0x2f6df13: return -ENOTDIR;
42 case 0x2f6df14: return -EISDIR;
43 case 0x2f6df15: return -EINVAL;
44 case 0x2f6df1a: return -EFBIG;
45 case 0x2f6df1b: return -ENOSPC;
46 case 0x2f6df1d: return -EROFS;
47 case 0x2f6df1e: return -EMLINK;
48 case 0x2f6df20: return -EDOM;
49 case 0x2f6df21: return -ERANGE;
50 case 0x2f6df22: return -EDEADLK;
51 case 0x2f6df23: return -ENAMETOOLONG;
52 case 0x2f6df24: return -ENOLCK;
53 case 0x2f6df26: return -ENOTEMPTY;
54 case 0x2f6df78: return -EDQUOT;
55 default: return -EREMOTEIO;
37 } 56 }
38} 57}
diff --git a/fs/afs/security.c b/fs/afs/security.c
index cbdd7f7162fa..f9f424d80458 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -92,7 +92,7 @@ static struct afs_vnode *afs_get_auth_inode(struct afs_vnode *vnode,
92 ASSERT(auth_inode != NULL); 92 ASSERT(auth_inode != NULL);
93 } else { 93 } else {
94 auth_inode = afs_iget(vnode->vfs_inode.i_sb, key, 94 auth_inode = afs_iget(vnode->vfs_inode.i_sb, key,
95 &vnode->status.parent); 95 &vnode->status.parent, NULL, NULL);
96 if (IS_ERR(auth_inode)) 96 if (IS_ERR(auth_inode))
97 return ERR_PTR(PTR_ERR(auth_inode)); 97 return ERR_PTR(PTR_ERR(auth_inode));
98 } 98 }
@@ -288,7 +288,8 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
288 struct key *key; 288 struct key *key;
289 int ret; 289 int ret;
290 290
291 _enter("{%x:%x},%x,", vnode->fid.vid, vnode->fid.vnode, mask); 291 _enter("{{%x:%x},%lx},%x,",
292 vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
292 293
293 key = afs_request_key(vnode->volume->cell); 294 key = afs_request_key(vnode->volume->cell);
294 if (IS_ERR(key)) { 295 if (IS_ERR(key)) {
@@ -296,13 +297,19 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
296 return PTR_ERR(key); 297 return PTR_ERR(key);
297 } 298 }
298 299
300 /* if the promise has expired, we need to check the server again */
301 if (!vnode->cb_promised) {
302 _debug("not promised");
303 ret = afs_vnode_fetch_status(vnode, NULL, key);
304 if (ret < 0)
305 goto error;
306 _debug("new promise [fl=%lx]", vnode->flags);
307 }
308
299 /* check the permits to see if we've got one yet */ 309 /* check the permits to see if we've got one yet */
300 ret = afs_check_permit(vnode, key, &access); 310 ret = afs_check_permit(vnode, key, &access);
301 if (ret < 0) { 311 if (ret < 0)
302 key_put(key); 312 goto error;
303 _leave(" = %d [check]", ret);
304 return ret;
305 }
306 313
307 /* interpret the access mask */ 314 /* interpret the access mask */
308 _debug("REQ %x ACC %x on %s", 315 _debug("REQ %x ACC %x on %s",
@@ -336,10 +343,14 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
336 } 343 }
337 344
338 key_put(key); 345 key_put(key);
339 return generic_permission(inode, mask, NULL); 346 ret = generic_permission(inode, mask, NULL);
347 _leave(" = %d", ret);
348 return ret;
340 349
341permission_denied: 350permission_denied:
351 ret = -EACCES;
352error:
342 key_put(key); 353 key_put(key);
343 _leave(" = -EACCES"); 354 _leave(" = %d", ret);
344 return -EACCES; 355 return ret;
345} 356}
diff --git a/fs/afs/server.c b/fs/afs/server.c
index bde6125c2f22..96bb23b476a2 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -223,6 +223,8 @@ void afs_put_server(struct afs_server *server)
223 223
224 _enter("%p{%d}", server, atomic_read(&server->usage)); 224 _enter("%p{%d}", server, atomic_read(&server->usage));
225 225
226 _debug("PUT SERVER %d", atomic_read(&server->usage));
227
226 ASSERTCMP(atomic_read(&server->usage), >, 0); 228 ASSERTCMP(atomic_read(&server->usage), >, 0);
227 229
228 if (likely(!atomic_dec_and_test(&server->usage))) { 230 if (likely(!atomic_dec_and_test(&server->usage))) {
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 497350a5463b..cebd03c91f57 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -331,7 +331,7 @@ static int afs_fill_super(struct super_block *sb, void *data)
331 fid.vid = as->volume->vid; 331 fid.vid = as->volume->vid;
332 fid.vnode = 1; 332 fid.vnode = 1;
333 fid.unique = 1; 333 fid.unique = 1;
334 inode = afs_iget(sb, params->key, &fid); 334 inode = afs_iget(sb, params->key, &fid, NULL, NULL);
335 if (IS_ERR(inode)) 335 if (IS_ERR(inode))
336 goto error_inode; 336 goto error_inode;
337 337
@@ -473,9 +473,9 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
473 inode_init_once(&vnode->vfs_inode); 473 inode_init_once(&vnode->vfs_inode);
474 init_waitqueue_head(&vnode->update_waitq); 474 init_waitqueue_head(&vnode->update_waitq);
475 mutex_init(&vnode->permits_lock); 475 mutex_init(&vnode->permits_lock);
476 mutex_init(&vnode->validate_lock);
476 spin_lock_init(&vnode->lock); 477 spin_lock_init(&vnode->lock);
477 INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); 478 INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
478 mutex_init(&vnode->cb_broken_lock);
479 } 479 }
480} 480}
481 481
@@ -497,7 +497,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
497 497
498 vnode->volume = NULL; 498 vnode->volume = NULL;
499 vnode->update_cnt = 0; 499 vnode->update_cnt = 0;
500 vnode->flags = 0; 500 vnode->flags = 1 << AFS_VNODE_UNSET;
501 vnode->cb_promised = false; 501 vnode->cb_promised = false;
502 502
503 return &vnode->vfs_inode; 503 return &vnode->vfs_inode;
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index 160097619ec7..a1904ab8426a 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -30,7 +30,7 @@ static noinline bool dump_tree_aux(struct rb_node *node, struct rb_node *parent,
30 bad = dump_tree_aux(node->rb_left, node, depth + 2, '/'); 30 bad = dump_tree_aux(node->rb_left, node, depth + 2, '/');
31 31
32 vnode = rb_entry(node, struct afs_vnode, cb_promise); 32 vnode = rb_entry(node, struct afs_vnode, cb_promise);
33 kdebug("%c %*.*s%c%p {%d}", 33 _debug("%c %*.*s%c%p {%d}",
34 rb_is_red(node) ? 'R' : 'B', 34 rb_is_red(node) ? 'R' : 'B',
35 depth, depth, "", lr, 35 depth, depth, "", lr,
36 vnode, vnode->cb_expires_at); 36 vnode, vnode->cb_expires_at);
@@ -47,7 +47,7 @@ static noinline bool dump_tree_aux(struct rb_node *node, struct rb_node *parent,
47 47
48static noinline void dump_tree(const char *name, struct afs_server *server) 48static noinline void dump_tree(const char *name, struct afs_server *server)
49{ 49{
50 kenter("%s", name); 50 _enter("%s", name);
51 if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-')) 51 if (dump_tree_aux(server->cb_promises.rb_node, NULL, 0, '-'))
52 BUG(); 52 BUG();
53} 53}
@@ -187,47 +187,61 @@ static void afs_vnode_deleted_remotely(struct afs_vnode *vnode)
187 spin_unlock(&server->cb_lock); 187 spin_unlock(&server->cb_lock);
188 } 188 }
189 189
190 spin_lock(&vnode->server->fs_lock);
191 rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
192 spin_unlock(&vnode->server->fs_lock);
193
194 vnode->server = NULL;
190 afs_put_server(server); 195 afs_put_server(server);
191} 196}
192 197
193/* 198/*
194 * finish off updating the recorded status of a file 199 * finish off updating the recorded status of a file after a successful
200 * operation completion
195 * - starts callback expiry timer 201 * - starts callback expiry timer
196 * - adds to server's callback list 202 * - adds to server's callback list
197 */ 203 */
198static void afs_vnode_finalise_status_update(struct afs_vnode *vnode, 204void afs_vnode_finalise_status_update(struct afs_vnode *vnode,
199 struct afs_server *server, 205 struct afs_server *server)
200 int ret)
201{ 206{
202 struct afs_server *oldserver = NULL; 207 struct afs_server *oldserver = NULL;
203 208
204 _enter("%p,%p,%d", vnode, server, ret); 209 _enter("%p,%p", vnode, server);
210
211 spin_lock(&vnode->lock);
212 clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
213 afs_vnode_note_promise(vnode, server);
214 vnode->update_cnt--;
215 ASSERTCMP(vnode->update_cnt, >=, 0);
216 spin_unlock(&vnode->lock);
217
218 wake_up_all(&vnode->update_waitq);
219 afs_put_server(oldserver);
220 _leave("");
221}
222
223/*
224 * finish off updating the recorded status of a file after an operation failed
225 */
226static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret)
227{
228 _enter("%p,%d", vnode, ret);
205 229
206 spin_lock(&vnode->lock); 230 spin_lock(&vnode->lock);
207 231
208 clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags); 232 clear_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
209 233
210 switch (ret) { 234 if (ret == -ENOENT) {
211 case 0:
212 afs_vnode_note_promise(vnode, server);
213 break;
214 case -ENOENT:
215 /* the file was deleted on the server */ 235 /* the file was deleted on the server */
216 _debug("got NOENT from server - marking file deleted"); 236 _debug("got NOENT from server - marking file deleted");
217 afs_vnode_deleted_remotely(vnode); 237 afs_vnode_deleted_remotely(vnode);
218 break;
219 default:
220 break;
221 } 238 }
222 239
223 vnode->update_cnt--; 240 vnode->update_cnt--;
224 241 ASSERTCMP(vnode->update_cnt, >=, 0);
225 spin_unlock(&vnode->lock); 242 spin_unlock(&vnode->lock);
226 243
227 wake_up_all(&vnode->update_waitq); 244 wake_up_all(&vnode->update_waitq);
228
229 afs_put_server(oldserver);
230
231 _leave(""); 245 _leave("");
232} 246}
233 247
@@ -275,8 +289,12 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode,
275 return 0; 289 return 0;
276 } 290 }
277 291
292 ASSERTCMP(vnode->update_cnt, >=, 0);
293
278 if (vnode->update_cnt > 0) { 294 if (vnode->update_cnt > 0) {
279 /* someone else started a fetch */ 295 /* someone else started a fetch */
296 _debug("wait on fetch %d", vnode->update_cnt);
297
280 set_current_state(TASK_UNINTERRUPTIBLE); 298 set_current_state(TASK_UNINTERRUPTIBLE);
281 ASSERT(myself.func != NULL); 299 ASSERT(myself.func != NULL);
282 add_wait_queue(&vnode->update_waitq, &myself); 300 add_wait_queue(&vnode->update_waitq, &myself);
@@ -325,7 +343,7 @@ get_anyway:
325 /* pick a server to query */ 343 /* pick a server to query */
326 server = afs_volume_pick_fileserver(vnode); 344 server = afs_volume_pick_fileserver(vnode);
327 if (IS_ERR(server)) 345 if (IS_ERR(server))
328 return PTR_ERR(server); 346 goto no_server;
329 347
330 _debug("USING SERVER: %p{%08x}", 348 _debug("USING SERVER: %p{%08x}",
331 server, ntohl(server->addr.s_addr)); 349 server, ntohl(server->addr.s_addr));
@@ -336,17 +354,34 @@ get_anyway:
336 } while (!afs_volume_release_fileserver(vnode, server, ret)); 354 } while (!afs_volume_release_fileserver(vnode, server, ret));
337 355
338 /* adjust the flags */ 356 /* adjust the flags */
339 if (ret == 0 && auth_vnode) 357 if (ret == 0) {
340 afs_cache_permit(vnode, key, acl_order); 358 _debug("adjust");
341 afs_vnode_finalise_status_update(vnode, server, ret); 359 if (auth_vnode)
360 afs_cache_permit(vnode, key, acl_order);
361 afs_vnode_finalise_status_update(vnode, server);
362 afs_put_server(server);
363 } else {
364 _debug("failed [%d]", ret);
365 afs_vnode_status_update_failed(vnode, ret);
366 }
342 367
343 _leave(" = %d", ret); 368 ASSERTCMP(vnode->update_cnt, >=, 0);
369
370 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
344 return ret; 371 return ret;
372
373no_server:
374 spin_lock(&vnode->lock);
375 vnode->update_cnt--;
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);
345} 380}
346 381
347/* 382/*
348 * fetch file data from the volume 383 * fetch file data from the volume
349 * - TODO implement caching and server failover 384 * - TODO implement caching
350 */ 385 */
351int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, 386int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
352 off_t offset, size_t length, struct page *page) 387 off_t offset, size_t length, struct page *page)
@@ -372,18 +407,349 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
372 /* pick a server to query */ 407 /* pick a server to query */
373 server = afs_volume_pick_fileserver(vnode); 408 server = afs_volume_pick_fileserver(vnode);
374 if (IS_ERR(server)) 409 if (IS_ERR(server))
375 return PTR_ERR(server); 410 goto no_server;
376 411
377 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); 412 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
378 413
379 ret = afs_fs_fetch_data(server, key, vnode, offset, length, 414 ret = afs_fs_fetch_data(server, key, vnode, offset, length,
380 page, NULL, &afs_sync_call); 415 page, &afs_sync_call);
381 416
382 } while (!afs_volume_release_fileserver(vnode, server, ret)); 417 } while (!afs_volume_release_fileserver(vnode, server, ret));
383 418
384 /* adjust the flags */ 419 /* adjust the flags */
385 afs_vnode_finalise_status_update(vnode, server, ret); 420 if (ret == 0) {
421 afs_vnode_finalise_status_update(vnode, server);
422 afs_put_server(server);
423 } else {
424 afs_vnode_status_update_failed(vnode, ret);
425 }
386 426
387 _leave(" = %d", ret); 427 _leave(" = %d", ret);
388 return ret; 428 return ret;
429
430no_server:
431 spin_lock(&vnode->lock);
432 vnode->update_cnt--;
433 ASSERTCMP(vnode->update_cnt, >=, 0);
434 spin_unlock(&vnode->lock);
435 return PTR_ERR(server);
436}
437
438/*
439 * make a file or a directory
440 */
441int 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)
445{
446 struct afs_server *server;
447 int ret;
448
449 _enter("%s{%u,%u,%u},%x,%s,,",
450 vnode->volume->vlocation->vldb.name,
451 vnode->fid.vid,
452 vnode->fid.vnode,
453 vnode->fid.unique,
454 key_serial(key),
455 name);
456
457 /* this op will fetch the status on the directory we're creating in */
458 spin_lock(&vnode->lock);
459 vnode->update_cnt++;
460 spin_unlock(&vnode->lock);
461
462 do {
463 /* pick a server to query */
464 server = afs_volume_pick_fileserver(vnode);
465 if (IS_ERR(server))
466 goto no_server;
467
468 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
469
470 ret = afs_fs_create(server, key, vnode, name, mode, newfid,
471 newstatus, newcb, &afs_sync_call);
472
473 } while (!afs_volume_release_fileserver(vnode, server, ret));
474
475 /* adjust the flags */
476 if (ret == 0) {
477 afs_vnode_finalise_status_update(vnode, server);
478 *_server = server;
479 } else {
480 afs_vnode_status_update_failed(vnode, ret);
481 *_server = NULL;
482 }
483
484 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
485 return ret;
486
487no_server:
488 spin_lock(&vnode->lock);
489 vnode->update_cnt--;
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);
494}
495
496/*
497 * remove a file or directory
498 */
499int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name,
500 bool isdir)
501{
502 struct afs_server *server;
503 int ret;
504
505 _enter("%s{%u,%u,%u},%x,%s",
506 vnode->volume->vlocation->vldb.name,
507 vnode->fid.vid,
508 vnode->fid.vnode,
509 vnode->fid.unique,
510 key_serial(key),
511 name);
512
513 /* this op will fetch the status on the directory we're removing from */
514 spin_lock(&vnode->lock);
515 vnode->update_cnt++;
516 spin_unlock(&vnode->lock);
517
518 do {
519 /* pick a server to query */
520 server = afs_volume_pick_fileserver(vnode);
521 if (IS_ERR(server))
522 goto no_server;
523
524 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
525
526 ret = afs_fs_remove(server, key, vnode, name, isdir,
527 &afs_sync_call);
528
529 } while (!afs_volume_release_fileserver(vnode, server, ret));
530
531 /* adjust the flags */
532 if (ret == 0) {
533 afs_vnode_finalise_status_update(vnode, server);
534 afs_put_server(server);
535 } else {
536 afs_vnode_status_update_failed(vnode, ret);
537 }
538
539 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
540 return ret;
541
542no_server:
543 spin_lock(&vnode->lock);
544 vnode->update_cnt--;
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);
549}
550
551/*
552 * create a hard link
553 */
554extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
555 struct key *key, const char *name)
556{
557 struct afs_server *server;
558 int ret;
559
560 _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s",
561 dvnode->volume->vlocation->vldb.name,
562 dvnode->fid.vid,
563 dvnode->fid.vnode,
564 dvnode->fid.unique,
565 vnode->volume->vlocation->vldb.name,
566 vnode->fid.vid,
567 vnode->fid.vnode,
568 vnode->fid.unique,
569 key_serial(key),
570 name);
571
572 /* this op will fetch the status on the directory we're removing from */
573 spin_lock(&vnode->lock);
574 vnode->update_cnt++;
575 spin_unlock(&vnode->lock);
576 spin_lock(&dvnode->lock);
577 dvnode->update_cnt++;
578 spin_unlock(&dvnode->lock);
579
580 do {
581 /* pick a server to query */
582 server = afs_volume_pick_fileserver(dvnode);
583 if (IS_ERR(server))
584 goto no_server;
585
586 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
587
588 ret = afs_fs_link(server, key, dvnode, vnode, name,
589 &afs_sync_call);
590
591 } while (!afs_volume_release_fileserver(dvnode, server, ret));
592
593 /* adjust the flags */
594 if (ret == 0) {
595 afs_vnode_finalise_status_update(vnode, server);
596 afs_vnode_finalise_status_update(dvnode, server);
597 afs_put_server(server);
598 } else {
599 afs_vnode_status_update_failed(vnode, ret);
600 afs_vnode_status_update_failed(dvnode, ret);
601 }
602
603 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
604 return ret;
605
606no_server:
607 spin_lock(&vnode->lock);
608 vnode->update_cnt--;
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);
617}
618
619/*
620 * create a symbolic link
621 */
622int 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)
627{
628 struct afs_server *server;
629 int ret;
630
631 _enter("%s{%u,%u,%u},%x,%s,%s,,,",
632 vnode->volume->vlocation->vldb.name,
633 vnode->fid.vid,
634 vnode->fid.vnode,
635 vnode->fid.unique,
636 key_serial(key),
637 name, content);
638
639 /* this op will fetch the status on the directory we're creating in */
640 spin_lock(&vnode->lock);
641 vnode->update_cnt++;
642 spin_unlock(&vnode->lock);
643
644 do {
645 /* pick a server to query */
646 server = afs_volume_pick_fileserver(vnode);
647 if (IS_ERR(server))
648 goto no_server;
649
650 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
651
652 ret = afs_fs_symlink(server, key, vnode, name, content,
653 newfid, newstatus, &afs_sync_call);
654
655 } while (!afs_volume_release_fileserver(vnode, server, ret));
656
657 /* adjust the flags */
658 if (ret == 0) {
659 afs_vnode_finalise_status_update(vnode, server);
660 *_server = server;
661 } else {
662 afs_vnode_status_update_failed(vnode, ret);
663 *_server = NULL;
664 }
665
666 _leave(" = %d [cnt %d]", ret, vnode->update_cnt);
667 return ret;
668
669no_server:
670 spin_lock(&vnode->lock);
671 vnode->update_cnt--;
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);
676}
677
678/*
679 * rename a file
680 */
681int afs_vnode_rename(struct afs_vnode *orig_dvnode,
682 struct afs_vnode *new_dvnode,
683 struct key *key,
684 const char *orig_name,
685 const char *new_name)
686{
687 struct afs_server *server;
688 int ret;
689
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,
696 new_dvnode->fid.vid,
697 new_dvnode->fid.vnode,
698 new_dvnode->fid.unique,
699 key_serial(key),
700 orig_name,
701 new_name);
702
703 /* this op will fetch the status on both the directories we're dealing
704 * with */
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);
712 }
713
714 do {
715 /* pick a server to query */
716 server = afs_volume_pick_fileserver(orig_dvnode);
717 if (IS_ERR(server))
718 goto no_server;
719
720 _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
721
722 ret = afs_fs_rename(server, key, orig_dvnode, orig_name,
723 new_dvnode, new_name, &afs_sync_call);
724
725 } while (!afs_volume_release_fileserver(orig_dvnode, server, ret));
726
727 /* adjust the flags */
728 if (ret == 0) {
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);
733 } else {
734 afs_vnode_status_update_failed(orig_dvnode, ret);
735 if (new_dvnode != orig_dvnode)
736 afs_vnode_status_update_failed(new_dvnode, ret);
737 }
738
739 _leave(" = %d [cnt %d]", ret, orig_dvnode->update_cnt);
740 return ret;
741
742no_server:
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);
752 }
753 _leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt);
754 return PTR_ERR(server);
389} 755}
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 15e13678c216..dd160cada45d 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -295,6 +295,7 @@ struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode)
295 * - releases the ref on the server struct that was acquired by picking 295 * - releases the ref on the server struct that was acquired by picking
296 * - records result of using a particular server to access a volume 296 * - records result of using a particular server to access a volume
297 * - return 0 to try again, 1 if okay or to issue error 297 * - return 0 to try again, 1 if okay or to issue error
298 * - the caller must release the server struct if result was 0
298 */ 299 */
299int afs_volume_release_fileserver(struct afs_vnode *vnode, 300int afs_volume_release_fileserver(struct afs_vnode *vnode,
300 struct afs_server *server, 301 struct afs_server *server,
@@ -312,7 +313,8 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode,
312 case 0: 313 case 0:
313 server->fs_act_jif = jiffies; 314 server->fs_act_jif = jiffies;
314 server->fs_state = 0; 315 server->fs_state = 0;
315 break; 316 _leave("");
317 return 1;
316 318
317 /* the fileserver denied all knowledge of the volume */ 319 /* the fileserver denied all knowledge of the volume */
318 case -ENOMEDIUM: 320 case -ENOMEDIUM:
@@ -377,14 +379,12 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode,
377 server->fs_act_jif = jiffies; 379 server->fs_act_jif = jiffies;
378 case -ENOMEM: 380 case -ENOMEM:
379 case -ENONET: 381 case -ENONET:
380 break; 382 /* tell the caller to accept the result */
383 afs_put_server(server);
384 _leave(" [local failure]");
385 return 1;
381 } 386 }
382 387
383 /* tell the caller to accept the result */
384 afs_put_server(server);
385 _leave("");
386 return 1;
387
388 /* tell the caller to loop around and try the next server */ 388 /* tell the caller to loop around and try the next server */
389try_next_server_upw: 389try_next_server_upw:
390 up_write(&volume->server_sem); 390 up_write(&volume->server_sem);