aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c77
-rw-r--r--fs/nfs/inode.c8
-rw-r--r--fs/nfs/nfs4_fs.h2
-rw-r--r--fs/nfs/nfs4proc.c40
4 files changed, 91 insertions, 36 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e257172d438c..17529b5bc551 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -38,6 +38,7 @@
38#include "delegation.h" 38#include "delegation.h"
39#include "iostat.h" 39#include "iostat.h"
40#include "internal.h" 40#include "internal.h"
41#include "fscache.h"
41 42
42/* #define NFS_DEBUG_VERBOSE 1 */ 43/* #define NFS_DEBUG_VERBOSE 1 */
43 44
@@ -1029,9 +1030,61 @@ static int is_atomic_open(struct nameidata *nd)
1029 return 1; 1030 return 1;
1030} 1031}
1031 1032
1033static struct nfs_open_context *nameidata_to_nfs_open_context(struct dentry *dentry, struct nameidata *nd)
1034{
1035 struct path path = {
1036 .mnt = nd->path.mnt,
1037 .dentry = dentry,
1038 };
1039 struct nfs_open_context *ctx;
1040 struct rpc_cred *cred;
1041 fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
1042
1043 cred = rpc_lookup_cred();
1044 if (IS_ERR(cred))
1045 return ERR_CAST(cred);
1046 ctx = alloc_nfs_open_context(&path, cred, fmode);
1047 put_rpccred(cred);
1048 if (ctx == NULL)
1049 return ERR_PTR(-ENOMEM);
1050 return ctx;
1051}
1052
1053static int do_open(struct inode *inode, struct file *filp)
1054{
1055 nfs_fscache_set_inode_cookie(inode, filp);
1056 return 0;
1057}
1058
1059static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx)
1060{
1061 struct file *filp;
1062 int ret = 0;
1063
1064 /* If the open_intent is for execute, we have an extra check to make */
1065 if (ctx->mode & FMODE_EXEC) {
1066 ret = nfs_may_open(ctx->path.dentry->d_inode,
1067 ctx->cred,
1068 nd->intent.open.flags);
1069 if (ret < 0)
1070 goto out;
1071 }
1072 filp = lookup_instantiate_filp(nd, ctx->path.dentry, do_open);
1073 if (IS_ERR(filp))
1074 ret = PTR_ERR(filp);
1075 else
1076 nfs_file_set_open_context(filp, ctx);
1077out:
1078 put_nfs_open_context(ctx);
1079 return ret;
1080}
1081
1032static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 1082static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1033{ 1083{
1084 struct nfs_open_context *ctx;
1085 struct iattr attr;
1034 struct dentry *res = NULL; 1086 struct dentry *res = NULL;
1087 int open_flags;
1035 int error; 1088 int error;
1036 1089
1037 dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n", 1090 dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",
@@ -1054,9 +1107,27 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
1054 goto out; 1107 goto out;
1055 } 1108 }
1056 1109
1110 ctx = nameidata_to_nfs_open_context(dentry, nd);
1111 res = ERR_CAST(ctx);
1112 if (IS_ERR(ctx))
1113 goto out;
1114
1115 open_flags = nd->intent.open.flags;
1116 if (nd->flags & LOOKUP_CREATE) {
1117 attr.ia_mode = nd->intent.open.create_mode;
1118 attr.ia_valid = ATTR_MODE;
1119 if (!IS_POSIXACL(dir))
1120 attr.ia_mode &= ~current_umask();
1121 } else {
1122 open_flags &= ~O_EXCL;
1123 attr.ia_valid = 0;
1124 BUG_ON(open_flags & O_CREAT);
1125 }
1126
1057 /* Open the file on the server */ 1127 /* Open the file on the server */
1058 res = nfs4_atomic_open(dir, dentry, nd); 1128 res = nfs4_atomic_open(dir, ctx, open_flags, &attr);
1059 if (IS_ERR(res)) { 1129 if (IS_ERR(res)) {
1130 put_nfs_open_context(ctx);
1060 error = PTR_ERR(res); 1131 error = PTR_ERR(res);
1061 switch (error) { 1132 switch (error) {
1062 /* Make a negative dentry */ 1133 /* Make a negative dentry */
@@ -1074,8 +1145,10 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
1074 default: 1145 default:
1075 goto out; 1146 goto out;
1076 } 1147 }
1077 } else if (res != NULL) 1148 }
1149 if (res != NULL)
1078 dentry = res; 1150 dentry = res;
1151 nfs_intent_set_file(nd, ctx);
1079out: 1152out:
1080 return res; 1153 return res;
1081no_open: 1154no_open:
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 7d2d6c72aa78..2f9266406afc 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -623,7 +623,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
623 nfs_revalidate_inode(server, inode); 623 nfs_revalidate_inode(server, inode);
624} 624}
625 625
626static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred) 626struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode)
627{ 627{
628 struct nfs_open_context *ctx; 628 struct nfs_open_context *ctx;
629 629
@@ -633,6 +633,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct
633 path_get(&ctx->path); 633 path_get(&ctx->path);
634 ctx->cred = get_rpccred(cred); 634 ctx->cred = get_rpccred(cred);
635 ctx->state = NULL; 635 ctx->state = NULL;
636 ctx->mode = f_mode;
636 ctx->flags = 0; 637 ctx->flags = 0;
637 ctx->error = 0; 638 ctx->error = 0;
638 ctx->dir_cookie = 0; 639 ctx->dir_cookie = 0;
@@ -673,7 +674,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
673 * Ensure that mmap has a recent RPC credential for use when writing out 674 * Ensure that mmap has a recent RPC credential for use when writing out
674 * shared pages 675 * shared pages
675 */ 676 */
676static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) 677void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
677{ 678{
678 struct inode *inode = filp->f_path.dentry->d_inode; 679 struct inode *inode = filp->f_path.dentry->d_inode;
679 struct nfs_inode *nfsi = NFS_I(inode); 680 struct nfs_inode *nfsi = NFS_I(inode);
@@ -730,11 +731,10 @@ int nfs_open(struct inode *inode, struct file *filp)
730 cred = rpc_lookup_cred(); 731 cred = rpc_lookup_cred();
731 if (IS_ERR(cred)) 732 if (IS_ERR(cred))
732 return PTR_ERR(cred); 733 return PTR_ERR(cred);
733 ctx = alloc_nfs_open_context(&filp->f_path, cred); 734 ctx = alloc_nfs_open_context(&filp->f_path, cred, filp->f_mode);
734 put_rpccred(cred); 735 put_rpccred(cred);
735 if (ctx == NULL) 736 if (ctx == NULL)
736 return -ENOMEM; 737 return -ENOMEM;
737 ctx->mode = filp->f_mode;
738 nfs_file_set_open_context(filp, ctx); 738 nfs_file_set_open_context(filp, ctx);
739 put_nfs_open_context(ctx); 739 put_nfs_open_context(ctx);
740 nfs_fscache_set_inode_cookie(inode, filp); 740 nfs_fscache_set_inode_cookie(inode, filp);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 311e15cc8af0..c5cc2a6aceb0 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -242,7 +242,7 @@ extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
242extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); 242extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
243extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); 243extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
244extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait); 244extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait);
245extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); 245extern struct dentry *nfs4_atomic_open(struct inode *, struct nfs_open_context *, int, struct iattr *);
246extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); 246extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
247extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); 247extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
248extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, 248extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 089da5b5d20a..38c3bed2240d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2025,39 +2025,17 @@ out_close:
2025} 2025}
2026 2026
2027struct dentry * 2027struct dentry *
2028nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 2028nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
2029{ 2029{
2030 struct path path = { 2030 struct dentry *dentry = ctx->path.dentry;
2031 .mnt = nd->path.mnt,
2032 .dentry = dentry,
2033 };
2034 struct dentry *parent; 2031 struct dentry *parent;
2035 struct iattr attr;
2036 struct rpc_cred *cred;
2037 struct nfs4_state *state; 2032 struct nfs4_state *state;
2038 struct dentry *res; 2033 struct dentry *res;
2039 int open_flags = nd->intent.open.flags;
2040 fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
2041
2042 if (nd->flags & LOOKUP_CREATE) {
2043 attr.ia_mode = nd->intent.open.create_mode;
2044 attr.ia_valid = ATTR_MODE;
2045 if (!IS_POSIXACL(dir))
2046 attr.ia_mode &= ~current_umask();
2047 } else {
2048 open_flags &= ~O_EXCL;
2049 attr.ia_valid = 0;
2050 BUG_ON(open_flags & O_CREAT);
2051 }
2052 2034
2053 cred = rpc_lookup_cred();
2054 if (IS_ERR(cred))
2055 return (struct dentry *)cred;
2056 parent = dentry->d_parent; 2035 parent = dentry->d_parent;
2057 /* Protect against concurrent sillydeletes */ 2036 /* Protect against concurrent sillydeletes */
2058 nfs_block_sillyrename(parent); 2037 nfs_block_sillyrename(parent);
2059 state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred); 2038 state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred);
2060 put_rpccred(cred);
2061 if (IS_ERR(state)) { 2039 if (IS_ERR(state)) {
2062 if (PTR_ERR(state) == -ENOENT) { 2040 if (PTR_ERR(state) == -ENOENT) {
2063 d_add(dentry, NULL); 2041 d_add(dentry, NULL);
@@ -2067,11 +2045,15 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
2067 return (struct dentry *)state; 2045 return (struct dentry *)state;
2068 } 2046 }
2069 res = d_add_unique(dentry, igrab(state->inode)); 2047 res = d_add_unique(dentry, igrab(state->inode));
2070 if (res != NULL) 2048 if (res != NULL) {
2071 path.dentry = res; 2049 struct dentry *dummy = ctx->path.dentry;
2072 nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir)); 2050
2051 ctx->path.dentry = dget(res);
2052 dput(dummy);
2053 }
2054 ctx->state = state;
2055 nfs_set_verifier(ctx->path.dentry, nfs_save_change_attribute(dir));
2073 nfs_unblock_sillyrename(parent); 2056 nfs_unblock_sillyrename(parent);
2074 nfs4_intent_set_file(nd, &path, state, fmode);
2075 return res; 2057 return res;
2076} 2058}
2077 2059