diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-03-17 15:15:21 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-03-17 15:15:21 -0400 |
commit | bd0f725c4c0bd77b6d931f63eda2d51423a22d43 (patch) | |
tree | 95caf3ce41ef7d73eae1972ad04b230cdeed6340 /fs/nfs | |
parent | 2ca310fc4160ed0420da65534a21ae77b24326a8 (diff) | |
parent | fdb63dcdb53a3c6dc11d4e438ef2425ec962d1e9 (diff) |
Merge branch 'devel' into linux-next
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/callback_proc.c | 19 | ||||
-rw-r--r-- | fs/nfs/dir.c | 55 | ||||
-rw-r--r-- | fs/nfs/inode.c | 34 | ||||
-rw-r--r-- | fs/nfs/internal.h | 8 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 36 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 11 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 154 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 2 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 17 | ||||
-rw-r--r-- | fs/nfs/proc.c | 25 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 35 |
11 files changed, 229 insertions, 167 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index ae2e87b95453..41db5258e7a7 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -112,7 +112,8 @@ out: | |||
112 | * TODO: keep track of all layouts (and delegations) in a hash table | 112 | * TODO: keep track of all layouts (and delegations) in a hash table |
113 | * hashed by filehandle. | 113 | * hashed by filehandle. |
114 | */ | 114 | */ |
115 | static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh) | 115 | static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, |
116 | struct nfs_fh *fh, nfs4_stateid *stateid) | ||
116 | { | 117 | { |
117 | struct nfs_server *server; | 118 | struct nfs_server *server; |
118 | struct inode *ino; | 119 | struct inode *ino; |
@@ -120,17 +121,19 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, | |||
120 | 121 | ||
121 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 122 | list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { |
122 | list_for_each_entry(lo, &server->layouts, plh_layouts) { | 123 | list_for_each_entry(lo, &server->layouts, plh_layouts) { |
124 | if (!nfs4_stateid_match_other(&lo->plh_stateid, stateid)) | ||
125 | continue; | ||
123 | if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh)) | 126 | if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh)) |
124 | continue; | 127 | continue; |
125 | ino = igrab(lo->plh_inode); | 128 | ino = igrab(lo->plh_inode); |
126 | if (!ino) | 129 | if (!ino) |
127 | continue; | 130 | break; |
128 | spin_lock(&ino->i_lock); | 131 | spin_lock(&ino->i_lock); |
129 | /* Is this layout in the process of being freed? */ | 132 | /* Is this layout in the process of being freed? */ |
130 | if (NFS_I(ino)->layout != lo) { | 133 | if (NFS_I(ino)->layout != lo) { |
131 | spin_unlock(&ino->i_lock); | 134 | spin_unlock(&ino->i_lock); |
132 | iput(ino); | 135 | iput(ino); |
133 | continue; | 136 | break; |
134 | } | 137 | } |
135 | pnfs_get_layout_hdr(lo); | 138 | pnfs_get_layout_hdr(lo); |
136 | spin_unlock(&ino->i_lock); | 139 | spin_unlock(&ino->i_lock); |
@@ -141,13 +144,14 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, | |||
141 | return NULL; | 144 | return NULL; |
142 | } | 145 | } |
143 | 146 | ||
144 | static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh) | 147 | static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, |
148 | struct nfs_fh *fh, nfs4_stateid *stateid) | ||
145 | { | 149 | { |
146 | struct pnfs_layout_hdr *lo; | 150 | struct pnfs_layout_hdr *lo; |
147 | 151 | ||
148 | spin_lock(&clp->cl_lock); | 152 | spin_lock(&clp->cl_lock); |
149 | rcu_read_lock(); | 153 | rcu_read_lock(); |
150 | lo = get_layout_by_fh_locked(clp, fh); | 154 | lo = get_layout_by_fh_locked(clp, fh, stateid); |
151 | rcu_read_unlock(); | 155 | rcu_read_unlock(); |
152 | spin_unlock(&clp->cl_lock); | 156 | spin_unlock(&clp->cl_lock); |
153 | 157 | ||
@@ -162,9 +166,9 @@ static u32 initiate_file_draining(struct nfs_client *clp, | |||
162 | u32 rv = NFS4ERR_NOMATCHING_LAYOUT; | 166 | u32 rv = NFS4ERR_NOMATCHING_LAYOUT; |
163 | LIST_HEAD(free_me_list); | 167 | LIST_HEAD(free_me_list); |
164 | 168 | ||
165 | lo = get_layout_by_fh(clp, &args->cbl_fh); | 169 | lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid); |
166 | if (!lo) | 170 | if (!lo) |
167 | return NFS4ERR_NOMATCHING_LAYOUT; | 171 | goto out; |
168 | 172 | ||
169 | ino = lo->plh_inode; | 173 | ino = lo->plh_inode; |
170 | spin_lock(&ino->i_lock); | 174 | spin_lock(&ino->i_lock); |
@@ -179,6 +183,7 @@ static u32 initiate_file_draining(struct nfs_client *clp, | |||
179 | pnfs_free_lseg_list(&free_me_list); | 183 | pnfs_free_lseg_list(&free_me_list); |
180 | pnfs_put_layout_hdr(lo); | 184 | pnfs_put_layout_hdr(lo); |
181 | iput(ino); | 185 | iput(ino); |
186 | out: | ||
182 | return rv; | 187 | return rv; |
183 | } | 188 | } |
184 | 189 | ||
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index be38b573495a..b31f5d2400bd 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -69,21 +69,28 @@ const struct address_space_operations nfs_dir_aops = { | |||
69 | 69 | ||
70 | static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) | 70 | static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred) |
71 | { | 71 | { |
72 | struct nfs_inode *nfsi = NFS_I(dir); | ||
72 | struct nfs_open_dir_context *ctx; | 73 | struct nfs_open_dir_context *ctx; |
73 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | 74 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); |
74 | if (ctx != NULL) { | 75 | if (ctx != NULL) { |
75 | ctx->duped = 0; | 76 | ctx->duped = 0; |
76 | ctx->attr_gencount = NFS_I(dir)->attr_gencount; | 77 | ctx->attr_gencount = nfsi->attr_gencount; |
77 | ctx->dir_cookie = 0; | 78 | ctx->dir_cookie = 0; |
78 | ctx->dup_cookie = 0; | 79 | ctx->dup_cookie = 0; |
79 | ctx->cred = get_rpccred(cred); | 80 | ctx->cred = get_rpccred(cred); |
81 | spin_lock(&dir->i_lock); | ||
82 | list_add(&ctx->list, &nfsi->open_files); | ||
83 | spin_unlock(&dir->i_lock); | ||
80 | return ctx; | 84 | return ctx; |
81 | } | 85 | } |
82 | return ERR_PTR(-ENOMEM); | 86 | return ERR_PTR(-ENOMEM); |
83 | } | 87 | } |
84 | 88 | ||
85 | static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) | 89 | static void put_nfs_open_dir_context(struct inode *dir, struct nfs_open_dir_context *ctx) |
86 | { | 90 | { |
91 | spin_lock(&dir->i_lock); | ||
92 | list_del(&ctx->list); | ||
93 | spin_unlock(&dir->i_lock); | ||
87 | put_rpccred(ctx->cred); | 94 | put_rpccred(ctx->cred); |
88 | kfree(ctx); | 95 | kfree(ctx); |
89 | } | 96 | } |
@@ -126,7 +133,7 @@ out: | |||
126 | static int | 133 | static int |
127 | nfs_closedir(struct inode *inode, struct file *filp) | 134 | nfs_closedir(struct inode *inode, struct file *filp) |
128 | { | 135 | { |
129 | put_nfs_open_dir_context(filp->private_data); | 136 | put_nfs_open_dir_context(filp->f_path.dentry->d_inode, filp->private_data); |
130 | return 0; | 137 | return 0; |
131 | } | 138 | } |
132 | 139 | ||
@@ -437,6 +444,22 @@ void nfs_advise_use_readdirplus(struct inode *dir) | |||
437 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags); | 444 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags); |
438 | } | 445 | } |
439 | 446 | ||
447 | /* | ||
448 | * This function is mainly for use by nfs_getattr(). | ||
449 | * | ||
450 | * If this is an 'ls -l', we want to force use of readdirplus. | ||
451 | * Do this by checking if there is an active file descriptor | ||
452 | * and calling nfs_advise_use_readdirplus, then forcing a | ||
453 | * cache flush. | ||
454 | */ | ||
455 | void nfs_force_use_readdirplus(struct inode *dir) | ||
456 | { | ||
457 | if (!list_empty(&NFS_I(dir)->open_files)) { | ||
458 | nfs_advise_use_readdirplus(dir); | ||
459 | nfs_zap_mapping(dir, dir->i_mapping); | ||
460 | } | ||
461 | } | ||
462 | |||
440 | static | 463 | static |
441 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | 464 | void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) |
442 | { | 465 | { |
@@ -815,6 +838,17 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc) | |||
815 | goto out; | 838 | goto out; |
816 | } | 839 | } |
817 | 840 | ||
841 | static bool nfs_dir_mapping_need_revalidate(struct inode *dir) | ||
842 | { | ||
843 | struct nfs_inode *nfsi = NFS_I(dir); | ||
844 | |||
845 | if (nfs_attribute_cache_expired(dir)) | ||
846 | return true; | ||
847 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
848 | return true; | ||
849 | return false; | ||
850 | } | ||
851 | |||
818 | /* The file offset position represents the dirent entry number. A | 852 | /* The file offset position represents the dirent entry number. A |
819 | last cookie cache takes care of the common case of reading the | 853 | last cookie cache takes care of the common case of reading the |
820 | whole directory. | 854 | whole directory. |
@@ -847,7 +881,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) | |||
847 | desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; | 881 | desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; |
848 | 882 | ||
849 | nfs_block_sillyrename(dentry); | 883 | nfs_block_sillyrename(dentry); |
850 | if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) | 884 | if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode)) |
851 | res = nfs_revalidate_mapping(inode, file->f_mapping); | 885 | res = nfs_revalidate_mapping(inode, file->f_mapping); |
852 | if (res < 0) | 886 | if (res < 0) |
853 | goto out; | 887 | goto out; |
@@ -1906,6 +1940,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1906 | struct inode *old_inode = old_dentry->d_inode; | 1940 | struct inode *old_inode = old_dentry->d_inode; |
1907 | struct inode *new_inode = new_dentry->d_inode; | 1941 | struct inode *new_inode = new_dentry->d_inode; |
1908 | struct dentry *dentry = NULL, *rehash = NULL; | 1942 | struct dentry *dentry = NULL, *rehash = NULL; |
1943 | struct rpc_task *task; | ||
1909 | int error = -EBUSY; | 1944 | int error = -EBUSY; |
1910 | 1945 | ||
1911 | dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n", | 1946 | dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n", |
@@ -1953,8 +1988,16 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1953 | if (new_inode != NULL) | 1988 | if (new_inode != NULL) |
1954 | NFS_PROTO(new_inode)->return_delegation(new_inode); | 1989 | NFS_PROTO(new_inode)->return_delegation(new_inode); |
1955 | 1990 | ||
1956 | error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, | 1991 | task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL); |
1957 | new_dir, &new_dentry->d_name); | 1992 | if (IS_ERR(task)) { |
1993 | error = PTR_ERR(task); | ||
1994 | goto out; | ||
1995 | } | ||
1996 | |||
1997 | error = rpc_wait_for_completion_task(task); | ||
1998 | if (error == 0) | ||
1999 | error = task->tk_status; | ||
2000 | rpc_put_task(task); | ||
1958 | nfs_mark_for_revalidate(old_inode); | 2001 | nfs_mark_for_revalidate(old_inode); |
1959 | out: | 2002 | out: |
1960 | if (rehash) | 2003 | if (rehash) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 360114ae8b82..9dbef878a2b2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -588,6 +588,25 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) | |||
588 | } | 588 | } |
589 | EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); | 589 | EXPORT_SYMBOL_GPL(nfs_setattr_update_inode); |
590 | 590 | ||
591 | static void nfs_request_parent_use_readdirplus(struct dentry *dentry) | ||
592 | { | ||
593 | struct dentry *parent; | ||
594 | |||
595 | parent = dget_parent(dentry); | ||
596 | nfs_force_use_readdirplus(parent->d_inode); | ||
597 | dput(parent); | ||
598 | } | ||
599 | |||
600 | static bool nfs_need_revalidate_inode(struct inode *inode) | ||
601 | { | ||
602 | if (NFS_I(inode)->cache_validity & | ||
603 | (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) | ||
604 | return true; | ||
605 | if (nfs_attribute_cache_expired(inode)) | ||
606 | return true; | ||
607 | return false; | ||
608 | } | ||
609 | |||
591 | int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | 610 | int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) |
592 | { | 611 | { |
593 | struct inode *inode = dentry->d_inode; | 612 | struct inode *inode = dentry->d_inode; |
@@ -616,10 +635,13 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
616 | ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) | 635 | ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) |
617 | need_atime = 0; | 636 | need_atime = 0; |
618 | 637 | ||
619 | if (need_atime) | 638 | if (need_atime || nfs_need_revalidate_inode(inode)) { |
620 | err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | 639 | struct nfs_server *server = NFS_SERVER(inode); |
621 | else | 640 | |
622 | err = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 641 | if (server->caps & NFS_CAP_READDIRPLUS) |
642 | nfs_request_parent_use_readdirplus(dentry); | ||
643 | err = __nfs_revalidate_inode(server, inode); | ||
644 | } | ||
623 | if (!err) { | 645 | if (!err) { |
624 | generic_fillattr(inode, stat); | 646 | generic_fillattr(inode, stat); |
625 | stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); | 647 | stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); |
@@ -961,9 +983,7 @@ int nfs_attribute_cache_expired(struct inode *inode) | |||
961 | */ | 983 | */ |
962 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 984 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
963 | { | 985 | { |
964 | if (!(NFS_I(inode)->cache_validity & | 986 | if (!nfs_need_revalidate_inode(inode)) |
965 | (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) | ||
966 | && !nfs_attribute_cache_expired(inode)) | ||
967 | return NFS_STALE(inode) ? -ESTALE : 0; | 987 | return NFS_STALE(inode) ? -ESTALE : 0; |
968 | return __nfs_revalidate_inode(server, inode); | 988 | return __nfs_revalidate_inode(server, inode); |
969 | } | 989 | } |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index b46cf5a67329..dd8bfc2e2464 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -301,6 +301,7 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp, | |||
301 | const char *ip_addr); | 301 | const char *ip_addr); |
302 | 302 | ||
303 | /* dir.c */ | 303 | /* dir.c */ |
304 | extern void nfs_force_use_readdirplus(struct inode *dir); | ||
304 | extern unsigned long nfs_access_cache_count(struct shrinker *shrink, | 305 | extern unsigned long nfs_access_cache_count(struct shrinker *shrink, |
305 | struct shrink_control *sc); | 306 | struct shrink_control *sc); |
306 | extern unsigned long nfs_access_cache_scan(struct shrinker *shrink, | 307 | extern unsigned long nfs_access_cache_scan(struct shrinker *shrink, |
@@ -474,6 +475,13 @@ extern int nfs_migrate_page(struct address_space *, | |||
474 | #define nfs_migrate_page NULL | 475 | #define nfs_migrate_page NULL |
475 | #endif | 476 | #endif |
476 | 477 | ||
478 | /* unlink.c */ | ||
479 | extern struct rpc_task * | ||
480 | nfs_async_rename(struct inode *old_dir, struct inode *new_dir, | ||
481 | struct dentry *old_dentry, struct dentry *new_dentry, | ||
482 | void (*complete)(struct rpc_task *, struct nfs_renamedata *)); | ||
483 | extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry); | ||
484 | |||
477 | /* direct.c */ | 485 | /* direct.c */ |
478 | void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, | 486 | void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo, |
479 | struct nfs_direct_req *dreq); | 487 | struct nfs_direct_req *dreq); |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index aa9bc973f36a..251e6253fc36 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -478,41 +478,6 @@ nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | |||
478 | } | 478 | } |
479 | 479 | ||
480 | static int | 480 | static int |
481 | nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, | ||
482 | struct inode *new_dir, struct qstr *new_name) | ||
483 | { | ||
484 | struct nfs_renameargs arg = { | ||
485 | .old_dir = NFS_FH(old_dir), | ||
486 | .old_name = old_name, | ||
487 | .new_dir = NFS_FH(new_dir), | ||
488 | .new_name = new_name, | ||
489 | }; | ||
490 | struct nfs_renameres res; | ||
491 | struct rpc_message msg = { | ||
492 | .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], | ||
493 | .rpc_argp = &arg, | ||
494 | .rpc_resp = &res, | ||
495 | }; | ||
496 | int status = -ENOMEM; | ||
497 | |||
498 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); | ||
499 | |||
500 | res.old_fattr = nfs_alloc_fattr(); | ||
501 | res.new_fattr = nfs_alloc_fattr(); | ||
502 | if (res.old_fattr == NULL || res.new_fattr == NULL) | ||
503 | goto out; | ||
504 | |||
505 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); | ||
506 | nfs_post_op_update_inode(old_dir, res.old_fattr); | ||
507 | nfs_post_op_update_inode(new_dir, res.new_fattr); | ||
508 | out: | ||
509 | nfs_free_fattr(res.old_fattr); | ||
510 | nfs_free_fattr(res.new_fattr); | ||
511 | dprintk("NFS reply rename: %d\n", status); | ||
512 | return status; | ||
513 | } | ||
514 | |||
515 | static int | ||
516 | nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | 481 | nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) |
517 | { | 482 | { |
518 | struct nfs3_linkargs arg = { | 483 | struct nfs3_linkargs arg = { |
@@ -967,7 +932,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
967 | .unlink_setup = nfs3_proc_unlink_setup, | 932 | .unlink_setup = nfs3_proc_unlink_setup, |
968 | .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare, | 933 | .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare, |
969 | .unlink_done = nfs3_proc_unlink_done, | 934 | .unlink_done = nfs3_proc_unlink_done, |
970 | .rename = nfs3_proc_rename, | ||
971 | .rename_setup = nfs3_proc_rename_setup, | 935 | .rename_setup = nfs3_proc_rename_setup, |
972 | .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare, | 936 | .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare, |
973 | .rename_done = nfs3_proc_rename_done, | 937 | .rename_done = nfs3_proc_rename_done, |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index a5b27c2d9689..e1d1badbe53c 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -427,6 +427,7 @@ extern void nfs4_close_sync(struct nfs4_state *, fmode_t); | |||
427 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); | 427 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); |
428 | extern void nfs_inode_find_state_and_recover(struct inode *inode, | 428 | extern void nfs_inode_find_state_and_recover(struct inode *inode, |
429 | const nfs4_stateid *stateid); | 429 | const nfs4_stateid *stateid); |
430 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *, struct nfs4_state *); | ||
430 | extern void nfs4_schedule_lease_recovery(struct nfs_client *); | 431 | extern void nfs4_schedule_lease_recovery(struct nfs_client *); |
431 | extern int nfs4_wait_clnt_recover(struct nfs_client *clp); | 432 | extern int nfs4_wait_clnt_recover(struct nfs_client *clp); |
432 | extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); | 433 | extern int nfs4_client_recover_expired_lease(struct nfs_client *clp); |
@@ -500,6 +501,16 @@ static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_statei | |||
500 | return memcmp(dst, src, sizeof(*dst)) == 0; | 501 | return memcmp(dst, src, sizeof(*dst)) == 0; |
501 | } | 502 | } |
502 | 503 | ||
504 | static inline bool nfs4_stateid_match_other(const nfs4_stateid *dst, const nfs4_stateid *src) | ||
505 | { | ||
506 | return memcmp(dst->other, src->other, NFS4_STATEID_OTHER_SIZE) == 0; | ||
507 | } | ||
508 | |||
509 | static inline bool nfs4_stateid_is_newer(const nfs4_stateid *s1, const nfs4_stateid *s2) | ||
510 | { | ||
511 | return (s32)(be32_to_cpu(s1->seqid) - be32_to_cpu(s2->seqid)) > 0; | ||
512 | } | ||
513 | |||
503 | static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state) | 514 | static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state) |
504 | { | 515 | { |
505 | return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0; | 516 | return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 450bfedbe2f4..025116c66fef 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -1137,12 +1137,71 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode) | |||
1137 | nfs4_state_set_mode_locked(state, state->state | fmode); | 1137 | nfs4_state_set_mode_locked(state, state->state | fmode); |
1138 | } | 1138 | } |
1139 | 1139 | ||
1140 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) | 1140 | static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state) |
1141 | { | ||
1142 | struct nfs_client *clp = state->owner->so_server->nfs_client; | ||
1143 | bool need_recover = false; | ||
1144 | |||
1145 | if (test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags) && state->n_rdonly) | ||
1146 | need_recover = true; | ||
1147 | if (test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags) && state->n_wronly) | ||
1148 | need_recover = true; | ||
1149 | if (test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags) && state->n_rdwr) | ||
1150 | need_recover = true; | ||
1151 | if (need_recover) | ||
1152 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
1153 | } | ||
1154 | |||
1155 | static bool nfs_need_update_open_stateid(struct nfs4_state *state, | ||
1156 | nfs4_stateid *stateid) | ||
1157 | { | ||
1158 | if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0) | ||
1159 | return true; | ||
1160 | if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) { | ||
1161 | nfs_test_and_clear_all_open_stateid(state); | ||
1162 | return true; | ||
1163 | } | ||
1164 | if (nfs4_stateid_is_newer(stateid, &state->open_stateid)) | ||
1165 | return true; | ||
1166 | return false; | ||
1167 | } | ||
1168 | |||
1169 | static void nfs_clear_open_stateid_locked(struct nfs4_state *state, | ||
1170 | nfs4_stateid *stateid, fmode_t fmode) | ||
1141 | { | 1171 | { |
1172 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1173 | switch (fmode & (FMODE_READ|FMODE_WRITE)) { | ||
1174 | case FMODE_WRITE: | ||
1175 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1176 | break; | ||
1177 | case FMODE_READ: | ||
1178 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1179 | break; | ||
1180 | case 0: | ||
1181 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1182 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1183 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
1184 | } | ||
1185 | if (stateid == NULL) | ||
1186 | return; | ||
1187 | if (!nfs_need_update_open_stateid(state, stateid)) | ||
1188 | return; | ||
1142 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 1189 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
1143 | nfs4_stateid_copy(&state->stateid, stateid); | 1190 | nfs4_stateid_copy(&state->stateid, stateid); |
1144 | nfs4_stateid_copy(&state->open_stateid, stateid); | 1191 | nfs4_stateid_copy(&state->open_stateid, stateid); |
1145 | set_bit(NFS_OPEN_STATE, &state->flags); | 1192 | } |
1193 | |||
1194 | static void nfs_clear_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) | ||
1195 | { | ||
1196 | write_seqlock(&state->seqlock); | ||
1197 | nfs_clear_open_stateid_locked(state, stateid, fmode); | ||
1198 | write_sequnlock(&state->seqlock); | ||
1199 | if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) | ||
1200 | nfs4_schedule_state_manager(state->owner->so_server->nfs_client); | ||
1201 | } | ||
1202 | |||
1203 | static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) | ||
1204 | { | ||
1146 | switch (fmode) { | 1205 | switch (fmode) { |
1147 | case FMODE_READ: | 1206 | case FMODE_READ: |
1148 | set_bit(NFS_O_RDONLY_STATE, &state->flags); | 1207 | set_bit(NFS_O_RDONLY_STATE, &state->flags); |
@@ -1153,13 +1212,11 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid * | |||
1153 | case FMODE_READ|FMODE_WRITE: | 1212 | case FMODE_READ|FMODE_WRITE: |
1154 | set_bit(NFS_O_RDWR_STATE, &state->flags); | 1213 | set_bit(NFS_O_RDWR_STATE, &state->flags); |
1155 | } | 1214 | } |
1156 | } | 1215 | if (!nfs_need_update_open_stateid(state, stateid)) |
1157 | 1216 | return; | |
1158 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) | 1217 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
1159 | { | 1218 | nfs4_stateid_copy(&state->stateid, stateid); |
1160 | write_seqlock(&state->seqlock); | 1219 | nfs4_stateid_copy(&state->open_stateid, stateid); |
1161 | nfs_set_open_stateid_locked(state, stateid, fmode); | ||
1162 | write_sequnlock(&state->seqlock); | ||
1163 | } | 1220 | } |
1164 | 1221 | ||
1165 | static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode) | 1222 | static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode) |
@@ -1217,6 +1274,8 @@ no_delegation: | |||
1217 | __update_open_stateid(state, open_stateid, NULL, fmode); | 1274 | __update_open_stateid(state, open_stateid, NULL, fmode); |
1218 | ret = 1; | 1275 | ret = 1; |
1219 | } | 1276 | } |
1277 | if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) | ||
1278 | nfs4_schedule_state_manager(state->owner->so_server->nfs_client); | ||
1220 | 1279 | ||
1221 | return ret; | 1280 | return ret; |
1222 | } | 1281 | } |
@@ -1450,12 +1509,15 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1450 | struct nfs4_state *newstate; | 1509 | struct nfs4_state *newstate; |
1451 | int ret; | 1510 | int ret; |
1452 | 1511 | ||
1512 | /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */ | ||
1513 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1514 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1515 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1453 | /* memory barrier prior to reading state->n_* */ | 1516 | /* memory barrier prior to reading state->n_* */ |
1454 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 1517 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
1455 | clear_bit(NFS_OPEN_STATE, &state->flags); | 1518 | clear_bit(NFS_OPEN_STATE, &state->flags); |
1456 | smp_rmb(); | 1519 | smp_rmb(); |
1457 | if (state->n_rdwr != 0) { | 1520 | if (state->n_rdwr != 0) { |
1458 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1459 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); | 1521 | ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); |
1460 | if (ret != 0) | 1522 | if (ret != 0) |
1461 | return ret; | 1523 | return ret; |
@@ -1463,7 +1525,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1463 | return -ESTALE; | 1525 | return -ESTALE; |
1464 | } | 1526 | } |
1465 | if (state->n_wronly != 0) { | 1527 | if (state->n_wronly != 0) { |
1466 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1467 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); | 1528 | ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); |
1468 | if (ret != 0) | 1529 | if (ret != 0) |
1469 | return ret; | 1530 | return ret; |
@@ -1471,7 +1532,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
1471 | return -ESTALE; | 1532 | return -ESTALE; |
1472 | } | 1533 | } |
1473 | if (state->n_rdonly != 0) { | 1534 | if (state->n_rdonly != 0) { |
1474 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1475 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); | 1535 | ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); |
1476 | if (ret != 0) | 1536 | if (ret != 0) |
1477 | return ret; | 1537 | return ret; |
@@ -2479,26 +2539,6 @@ static void nfs4_free_closedata(void *data) | |||
2479 | kfree(calldata); | 2539 | kfree(calldata); |
2480 | } | 2540 | } |
2481 | 2541 | ||
2482 | static void nfs4_close_clear_stateid_flags(struct nfs4_state *state, | ||
2483 | fmode_t fmode) | ||
2484 | { | ||
2485 | spin_lock(&state->owner->so_lock); | ||
2486 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
2487 | switch (fmode & (FMODE_READ|FMODE_WRITE)) { | ||
2488 | case FMODE_WRITE: | ||
2489 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
2490 | break; | ||
2491 | case FMODE_READ: | ||
2492 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
2493 | break; | ||
2494 | case 0: | ||
2495 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
2496 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
2497 | clear_bit(NFS_OPEN_STATE, &state->flags); | ||
2498 | } | ||
2499 | spin_unlock(&state->owner->so_lock); | ||
2500 | } | ||
2501 | |||
2502 | static void nfs4_close_done(struct rpc_task *task, void *data) | 2542 | static void nfs4_close_done(struct rpc_task *task, void *data) |
2503 | { | 2543 | { |
2504 | struct nfs4_closedata *calldata = data; | 2544 | struct nfs4_closedata *calldata = data; |
@@ -2517,9 +2557,9 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2517 | if (calldata->roc) | 2557 | if (calldata->roc) |
2518 | pnfs_roc_set_barrier(state->inode, | 2558 | pnfs_roc_set_barrier(state->inode, |
2519 | calldata->roc_barrier); | 2559 | calldata->roc_barrier); |
2520 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 2560 | nfs_clear_open_stateid(state, &calldata->res.stateid, 0); |
2521 | renew_lease(server, calldata->timestamp); | 2561 | renew_lease(server, calldata->timestamp); |
2522 | break; | 2562 | goto out_release; |
2523 | case -NFS4ERR_ADMIN_REVOKED: | 2563 | case -NFS4ERR_ADMIN_REVOKED: |
2524 | case -NFS4ERR_STALE_STATEID: | 2564 | case -NFS4ERR_STALE_STATEID: |
2525 | case -NFS4ERR_OLD_STATEID: | 2565 | case -NFS4ERR_OLD_STATEID: |
@@ -2533,7 +2573,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2533 | goto out_release; | 2573 | goto out_release; |
2534 | } | 2574 | } |
2535 | } | 2575 | } |
2536 | nfs4_close_clear_stateid_flags(state, calldata->arg.fmode); | 2576 | nfs_clear_open_stateid(state, NULL, calldata->arg.fmode); |
2537 | out_release: | 2577 | out_release: |
2538 | nfs_release_seqid(calldata->arg.seqid); | 2578 | nfs_release_seqid(calldata->arg.seqid); |
2539 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 2579 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
@@ -3507,49 +3547,6 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | |||
3507 | return 1; | 3547 | return 1; |
3508 | } | 3548 | } |
3509 | 3549 | ||
3510 | static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | ||
3511 | struct inode *new_dir, struct qstr *new_name) | ||
3512 | { | ||
3513 | struct nfs_server *server = NFS_SERVER(old_dir); | ||
3514 | struct nfs_renameargs arg = { | ||
3515 | .old_dir = NFS_FH(old_dir), | ||
3516 | .new_dir = NFS_FH(new_dir), | ||
3517 | .old_name = old_name, | ||
3518 | .new_name = new_name, | ||
3519 | }; | ||
3520 | struct nfs_renameres res = { | ||
3521 | .server = server, | ||
3522 | }; | ||
3523 | struct rpc_message msg = { | ||
3524 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], | ||
3525 | .rpc_argp = &arg, | ||
3526 | .rpc_resp = &res, | ||
3527 | }; | ||
3528 | int status = -ENOMEM; | ||
3529 | |||
3530 | status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); | ||
3531 | if (!status) { | ||
3532 | update_changeattr(old_dir, &res.old_cinfo); | ||
3533 | update_changeattr(new_dir, &res.new_cinfo); | ||
3534 | } | ||
3535 | return status; | ||
3536 | } | ||
3537 | |||
3538 | static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | ||
3539 | struct inode *new_dir, struct qstr *new_name) | ||
3540 | { | ||
3541 | struct nfs4_exception exception = { }; | ||
3542 | int err; | ||
3543 | do { | ||
3544 | err = _nfs4_proc_rename(old_dir, old_name, | ||
3545 | new_dir, new_name); | ||
3546 | trace_nfs4_rename(old_dir, old_name, new_dir, new_name, err); | ||
3547 | err = nfs4_handle_exception(NFS_SERVER(old_dir), err, | ||
3548 | &exception); | ||
3549 | } while (exception.retry); | ||
3550 | return err; | ||
3551 | } | ||
3552 | |||
3553 | static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | 3550 | static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) |
3554 | { | 3551 | { |
3555 | struct nfs_server *server = NFS_SERVER(inode); | 3552 | struct nfs_server *server = NFS_SERVER(inode); |
@@ -8408,7 +8405,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
8408 | .unlink_setup = nfs4_proc_unlink_setup, | 8405 | .unlink_setup = nfs4_proc_unlink_setup, |
8409 | .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare, | 8406 | .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare, |
8410 | .unlink_done = nfs4_proc_unlink_done, | 8407 | .unlink_done = nfs4_proc_unlink_done, |
8411 | .rename = nfs4_proc_rename, | ||
8412 | .rename_setup = nfs4_proc_rename_setup, | 8408 | .rename_setup = nfs4_proc_rename_setup, |
8413 | .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare, | 8409 | .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare, |
8414 | .rename_done = nfs4_proc_rename_done, | 8410 | .rename_done = nfs4_proc_rename_done, |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0deb32105ccf..f544a1560c83 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1316,7 +1316,7 @@ static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_st | |||
1316 | return 1; | 1316 | return 1; |
1317 | } | 1317 | } |
1318 | 1318 | ||
1319 | static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) | 1319 | int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state) |
1320 | { | 1320 | { |
1321 | set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); | 1321 | set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags); |
1322 | clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | 1322 | clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 4755858e37a0..cb53d450ae32 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -662,7 +662,18 @@ pnfs_destroy_all_layouts(struct nfs_client *clp) | |||
662 | */ | 662 | */ |
663 | static bool pnfs_seqid_is_newer(u32 s1, u32 s2) | 663 | static bool pnfs_seqid_is_newer(u32 s1, u32 s2) |
664 | { | 664 | { |
665 | return (s32)s1 - (s32)s2 > 0; | 665 | return (s32)(s1 - s2) > 0; |
666 | } | ||
667 | |||
668 | static void | ||
669 | pnfs_verify_layout_stateid(struct pnfs_layout_hdr *lo, | ||
670 | const nfs4_stateid *new, | ||
671 | struct list_head *free_me_list) | ||
672 | { | ||
673 | if (nfs4_stateid_match_other(&lo->plh_stateid, new)) | ||
674 | return; | ||
675 | /* Layout is new! Kill existing layout segments */ | ||
676 | pnfs_mark_matching_lsegs_invalid(lo, free_me_list, NULL); | ||
666 | } | 677 | } |
667 | 678 | ||
668 | /* update lo->plh_stateid with new if is more recent */ | 679 | /* update lo->plh_stateid with new if is more recent */ |
@@ -1315,6 +1326,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
1315 | struct nfs4_layoutget_res *res = &lgp->res; | 1326 | struct nfs4_layoutget_res *res = &lgp->res; |
1316 | struct pnfs_layout_segment *lseg; | 1327 | struct pnfs_layout_segment *lseg; |
1317 | struct inode *ino = lo->plh_inode; | 1328 | struct inode *ino = lo->plh_inode; |
1329 | LIST_HEAD(free_me); | ||
1318 | int status = 0; | 1330 | int status = 0; |
1319 | 1331 | ||
1320 | /* Inject layout blob into I/O device driver */ | 1332 | /* Inject layout blob into I/O device driver */ |
@@ -1341,6 +1353,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
1341 | goto out_forget_reply; | 1353 | goto out_forget_reply; |
1342 | } | 1354 | } |
1343 | 1355 | ||
1356 | /* Check that the new stateid matches the old stateid */ | ||
1357 | pnfs_verify_layout_stateid(lo, &res->stateid, &free_me); | ||
1344 | /* Done processing layoutget. Set the layout stateid */ | 1358 | /* Done processing layoutget. Set the layout stateid */ |
1345 | pnfs_set_layout_stateid(lo, &res->stateid, false); | 1359 | pnfs_set_layout_stateid(lo, &res->stateid, false); |
1346 | 1360 | ||
@@ -1355,6 +1369,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
1355 | } | 1369 | } |
1356 | 1370 | ||
1357 | spin_unlock(&ino->i_lock); | 1371 | spin_unlock(&ino->i_lock); |
1372 | pnfs_free_lseg_list(&free_me); | ||
1358 | return lseg; | 1373 | return lseg; |
1359 | out: | 1374 | out: |
1360 | return ERR_PTR(status); | 1375 | return ERR_PTR(status); |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index fddbba2d9eff..e55ce9e8b034 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -357,30 +357,6 @@ nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir, | |||
357 | } | 357 | } |
358 | 358 | ||
359 | static int | 359 | static int |
360 | nfs_proc_rename(struct inode *old_dir, struct qstr *old_name, | ||
361 | struct inode *new_dir, struct qstr *new_name) | ||
362 | { | ||
363 | struct nfs_renameargs arg = { | ||
364 | .old_dir = NFS_FH(old_dir), | ||
365 | .old_name = old_name, | ||
366 | .new_dir = NFS_FH(new_dir), | ||
367 | .new_name = new_name, | ||
368 | }; | ||
369 | struct rpc_message msg = { | ||
370 | .rpc_proc = &nfs_procedures[NFSPROC_RENAME], | ||
371 | .rpc_argp = &arg, | ||
372 | }; | ||
373 | int status; | ||
374 | |||
375 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); | ||
376 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); | ||
377 | nfs_mark_for_revalidate(old_dir); | ||
378 | nfs_mark_for_revalidate(new_dir); | ||
379 | dprintk("NFS reply rename: %d\n", status); | ||
380 | return status; | ||
381 | } | ||
382 | |||
383 | static int | ||
384 | nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | 360 | nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) |
385 | { | 361 | { |
386 | struct nfs_linkargs arg = { | 362 | struct nfs_linkargs arg = { |
@@ -745,7 +721,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = { | |||
745 | .unlink_setup = nfs_proc_unlink_setup, | 721 | .unlink_setup = nfs_proc_unlink_setup, |
746 | .unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare, | 722 | .unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare, |
747 | .unlink_done = nfs_proc_unlink_done, | 723 | .unlink_done = nfs_proc_unlink_done, |
748 | .rename = nfs_proc_rename, | ||
749 | .rename_setup = nfs_proc_rename_setup, | 724 | .rename_setup = nfs_proc_rename_setup, |
750 | .rename_rpc_prepare = nfs_proc_rename_rpc_prepare, | 725 | .rename_rpc_prepare = nfs_proc_rename_rpc_prepare, |
751 | .rename_done = nfs_proc_rename_done, | 726 | .rename_done = nfs_proc_rename_done, |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 11d78944de79..de54129336c6 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
16 | #include <linux/namei.h> | 16 | #include <linux/namei.h> |
17 | #include <linux/fsnotify.h> | ||
17 | 18 | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | #include "nfs4_fs.h" | 20 | #include "nfs4_fs.h" |
@@ -353,8 +354,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) | |||
353 | return; | 354 | return; |
354 | } | 355 | } |
355 | 356 | ||
356 | if (task->tk_status != 0) | 357 | if (data->complete) |
357 | nfs_cancel_async_unlink(old_dentry); | 358 | data->complete(task, data); |
358 | } | 359 | } |
359 | 360 | ||
360 | /** | 361 | /** |
@@ -399,9 +400,10 @@ static const struct rpc_call_ops nfs_rename_ops = { | |||
399 | * | 400 | * |
400 | * It's expected that valid references to the dentries and inodes are held | 401 | * It's expected that valid references to the dentries and inodes are held |
401 | */ | 402 | */ |
402 | static struct rpc_task * | 403 | struct rpc_task * |
403 | nfs_async_rename(struct inode *old_dir, struct inode *new_dir, | 404 | nfs_async_rename(struct inode *old_dir, struct inode *new_dir, |
404 | struct dentry *old_dentry, struct dentry *new_dentry) | 405 | struct dentry *old_dentry, struct dentry *new_dentry, |
406 | void (*complete)(struct rpc_task *, struct nfs_renamedata *)) | ||
405 | { | 407 | { |
406 | struct nfs_renamedata *data; | 408 | struct nfs_renamedata *data; |
407 | struct rpc_message msg = { }; | 409 | struct rpc_message msg = { }; |
@@ -438,6 +440,7 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, | |||
438 | data->new_dentry = dget(new_dentry); | 440 | data->new_dentry = dget(new_dentry); |
439 | nfs_fattr_init(&data->old_fattr); | 441 | nfs_fattr_init(&data->old_fattr); |
440 | nfs_fattr_init(&data->new_fattr); | 442 | nfs_fattr_init(&data->new_fattr); |
443 | data->complete = complete; | ||
441 | 444 | ||
442 | /* set up nfs_renameargs */ | 445 | /* set up nfs_renameargs */ |
443 | data->args.old_dir = NFS_FH(old_dir); | 446 | data->args.old_dir = NFS_FH(old_dir); |
@@ -456,6 +459,27 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, | |||
456 | return rpc_run_task(&task_setup_data); | 459 | return rpc_run_task(&task_setup_data); |
457 | } | 460 | } |
458 | 461 | ||
462 | /* | ||
463 | * Perform tasks needed when a sillyrename is done such as cancelling the | ||
464 | * queued async unlink if it failed. | ||
465 | */ | ||
466 | static void | ||
467 | nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data) | ||
468 | { | ||
469 | struct dentry *dentry = data->old_dentry; | ||
470 | |||
471 | if (task->tk_status != 0) { | ||
472 | nfs_cancel_async_unlink(dentry); | ||
473 | return; | ||
474 | } | ||
475 | |||
476 | /* | ||
477 | * vfs_unlink and the like do not issue this when a file is | ||
478 | * sillyrenamed, so do it here. | ||
479 | */ | ||
480 | fsnotify_nameremove(dentry, 0); | ||
481 | } | ||
482 | |||
459 | #define SILLYNAME_PREFIX ".nfs" | 483 | #define SILLYNAME_PREFIX ".nfs" |
460 | #define SILLYNAME_PREFIX_LEN ((unsigned)sizeof(SILLYNAME_PREFIX) - 1) | 484 | #define SILLYNAME_PREFIX_LEN ((unsigned)sizeof(SILLYNAME_PREFIX) - 1) |
461 | #define SILLYNAME_FILEID_LEN ((unsigned)sizeof(u64) << 1) | 485 | #define SILLYNAME_FILEID_LEN ((unsigned)sizeof(u64) << 1) |
@@ -548,7 +572,8 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
548 | } | 572 | } |
549 | 573 | ||
550 | /* run the rename task, undo unlink if it fails */ | 574 | /* run the rename task, undo unlink if it fails */ |
551 | task = nfs_async_rename(dir, dir, dentry, sdentry); | 575 | task = nfs_async_rename(dir, dir, dentry, sdentry, |
576 | nfs_complete_sillyrename); | ||
552 | if (IS_ERR(task)) { | 577 | if (IS_ERR(task)) { |
553 | error = -EBUSY; | 578 | error = -EBUSY; |
554 | nfs_cancel_async_unlink(dentry); | 579 | nfs_cancel_async_unlink(dentry); |