diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 77 |
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 | ||
1033 | static 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 | |||
1053 | static int do_open(struct inode *inode, struct file *filp) | ||
1054 | { | ||
1055 | nfs_fscache_set_inode_cookie(inode, filp); | ||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | static 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); | ||
1077 | out: | ||
1078 | put_nfs_open_context(ctx); | ||
1079 | return ret; | ||
1080 | } | ||
1081 | |||
1032 | static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 1082 | static 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); | ||
1079 | out: | 1152 | out: |
1080 | return res; | 1153 | return res; |
1081 | no_open: | 1154 | no_open: |