Commit cd9a1c0e authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Clean up nfs4_atomic_open

Start moving the 'struct nameidata' dependent code out of the lower level
NFS code in preparation for the removal of open intents.

Instead of the struct nameidata, we pass down a partially initialised
struct nfs_open_context that will be fully initialised by the atomic open
upon success.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 859d5024
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "delegation.h" #include "delegation.h"
#include "iostat.h" #include "iostat.h"
#include "internal.h" #include "internal.h"
#include "fscache.h"
/* #define NFS_DEBUG_VERBOSE 1 */ /* #define NFS_DEBUG_VERBOSE 1 */
...@@ -1029,9 +1030,61 @@ static int is_atomic_open(struct nameidata *nd) ...@@ -1029,9 +1030,61 @@ static int is_atomic_open(struct nameidata *nd)
return 1; return 1;
} }
static struct nfs_open_context *nameidata_to_nfs_open_context(struct dentry *dentry, struct nameidata *nd)
{
struct path path = {
.mnt = nd->path.mnt,
.dentry = dentry,
};
struct nfs_open_context *ctx;
struct rpc_cred *cred;
fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return ERR_CAST(cred);
ctx = alloc_nfs_open_context(&path, cred, fmode);
put_rpccred(cred);
if (ctx == NULL)
return ERR_PTR(-ENOMEM);
return ctx;
}
static int do_open(struct inode *inode, struct file *filp)
{
nfs_fscache_set_inode_cookie(inode, filp);
return 0;
}
static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx)
{
struct file *filp;
int ret = 0;
/* If the open_intent is for execute, we have an extra check to make */
if (ctx->mode & FMODE_EXEC) {
ret = nfs_may_open(ctx->path.dentry->d_inode,
ctx->cred,
nd->intent.open.flags);
if (ret < 0)
goto out;
}
filp = lookup_instantiate_filp(nd, ctx->path.dentry, do_open);
if (IS_ERR(filp))
ret = PTR_ERR(filp);
else
nfs_file_set_open_context(filp, ctx);
out:
put_nfs_open_context(ctx);
return ret;
}
static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{ {
struct nfs_open_context *ctx;
struct iattr attr;
struct dentry *res = NULL; struct dentry *res = NULL;
int open_flags;
int error; int error;
dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n", 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,9 +1107,27 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
goto out; goto out;
} }
ctx = nameidata_to_nfs_open_context(dentry, nd);
res = ERR_CAST(ctx);
if (IS_ERR(ctx))
goto out;
open_flags = nd->intent.open.flags;
if (nd->flags & LOOKUP_CREATE) {
attr.ia_mode = nd->intent.open.create_mode;
attr.ia_valid = ATTR_MODE;
if (!IS_POSIXACL(dir))
attr.ia_mode &= ~current_umask();
} else {
open_flags &= ~O_EXCL;
attr.ia_valid = 0;
BUG_ON(open_flags & O_CREAT);
}
/* Open the file on the server */ /* Open the file on the server */
res = nfs4_atomic_open(dir, dentry, nd); res = nfs4_atomic_open(dir, ctx, open_flags, &attr);
if (IS_ERR(res)) { if (IS_ERR(res)) {
put_nfs_open_context(ctx);
error = PTR_ERR(res); error = PTR_ERR(res);
switch (error) { switch (error) {
/* Make a negative dentry */ /* Make a negative dentry */
...@@ -1074,8 +1145,10 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry ...@@ -1074,8 +1145,10 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
default: default:
goto out; goto out;
} }
} else if (res != NULL) }
if (res != NULL)
dentry = res; dentry = res;
nfs_intent_set_file(nd, ctx);
out: out:
return res; return res;
no_open: no_open:
......
...@@ -623,7 +623,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) ...@@ -623,7 +623,7 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
nfs_revalidate_inode(server, inode); nfs_revalidate_inode(server, inode);
} }
static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred) struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode)
{ {
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
...@@ -633,6 +633,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct ...@@ -633,6 +633,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct
path_get(&ctx->path); path_get(&ctx->path);
ctx->cred = get_rpccred(cred); ctx->cred = get_rpccred(cred);
ctx->state = NULL; ctx->state = NULL;
ctx->mode = f_mode;
ctx->flags = 0; ctx->flags = 0;
ctx->error = 0; ctx->error = 0;
ctx->dir_cookie = 0; ctx->dir_cookie = 0;
...@@ -673,7 +674,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx) ...@@ -673,7 +674,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
* Ensure that mmap has a recent RPC credential for use when writing out * Ensure that mmap has a recent RPC credential for use when writing out
* shared pages * shared pages
*/ */
static void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
{ {
struct inode *inode = filp->f_path.dentry->d_inode; struct inode *inode = filp->f_path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
...@@ -730,11 +731,10 @@ int nfs_open(struct inode *inode, struct file *filp) ...@@ -730,11 +731,10 @@ int nfs_open(struct inode *inode, struct file *filp)
cred = rpc_lookup_cred(); cred = rpc_lookup_cred();
if (IS_ERR(cred)) if (IS_ERR(cred))
return PTR_ERR(cred); return PTR_ERR(cred);
ctx = alloc_nfs_open_context(&filp->f_path, cred); ctx = alloc_nfs_open_context(&filp->f_path, cred, filp->f_mode);
put_rpccred(cred); put_rpccred(cred);
if (ctx == NULL) if (ctx == NULL)
return -ENOMEM; return -ENOMEM;
ctx->mode = filp->f_mode;
nfs_file_set_open_context(filp, ctx); nfs_file_set_open_context(filp, ctx);
put_nfs_open_context(ctx); put_nfs_open_context(ctx);
nfs_fscache_set_inode_cookie(inode, filp); nfs_fscache_set_inode_cookie(inode, filp);
......
...@@ -242,7 +242,7 @@ extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); ...@@ -242,7 +242,7 @@ extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *);
extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait); extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait);
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); extern struct dentry *nfs4_atomic_open(struct inode *, struct nfs_open_context *, int, struct iattr *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
......
...@@ -2025,39 +2025,17 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct ...@@ -2025,39 +2025,17 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
} }
struct dentry * struct dentry *
nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
{ {
struct path path = { struct dentry *dentry = ctx->path.dentry;
.mnt = nd->path.mnt,
.dentry = dentry,
};
struct dentry *parent; struct dentry *parent;
struct iattr attr;
struct rpc_cred *cred;
struct nfs4_state *state; struct nfs4_state *state;
struct dentry *res; struct dentry *res;
int open_flags = nd->intent.open.flags;
fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC);
if (nd->flags & LOOKUP_CREATE) {
attr.ia_mode = nd->intent.open.create_mode;
attr.ia_valid = ATTR_MODE;
if (!IS_POSIXACL(dir))
attr.ia_mode &= ~current_umask();
} else {
open_flags &= ~O_EXCL;
attr.ia_valid = 0;
BUG_ON(open_flags & O_CREAT);
}
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return (struct dentry *)cred;
parent = dentry->d_parent; parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */ /* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent); nfs_block_sillyrename(parent);
state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred); state = nfs4_do_open(dir, &ctx->path, ctx->mode, open_flags, attr, ctx->cred);
put_rpccred(cred);
if (IS_ERR(state)) { if (IS_ERR(state)) {
if (PTR_ERR(state) == -ENOENT) { if (PTR_ERR(state) == -ENOENT) {
d_add(dentry, NULL); d_add(dentry, NULL);
...@@ -2067,11 +2045,15 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) ...@@ -2067,11 +2045,15 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
return (struct dentry *)state; return (struct dentry *)state;
} }
res = d_add_unique(dentry, igrab(state->inode)); res = d_add_unique(dentry, igrab(state->inode));
if (res != NULL) if (res != NULL) {
path.dentry = res; struct dentry *dummy = ctx->path.dentry;
nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
ctx->path.dentry = dget(res);
dput(dummy);
}
ctx->state = state;
nfs_set_verifier(ctx->path.dentry, nfs_save_change_attribute(dir));
nfs_unblock_sillyrename(parent); nfs_unblock_sillyrename(parent);
nfs4_intent_set_file(nd, &path, state, fmode);
return res; return res;
} }
......
...@@ -360,6 +360,8 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); ...@@ -360,6 +360,8 @@ extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx); extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode);
extern struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred, fmode_t f_mode);
extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx);
extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx); extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx);
extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx); extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx);
extern u64 nfs_compat_user_ino64(u64 fileid); extern u64 nfs_compat_user_ino64(u64 fileid);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment