aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r--fs/nfs/dir.c77
1 files changed, 75 insertions, 2 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: