NFSv4: Ensure that we wait for the CLOSE request to complete
Otherwise, we do end up breaking close-to-open semantics. We also end up breaking some of the silly-rename tests in Connectathon on some setups. Please refer to the bug-report at http://bugzilla.linux-nfs.org/show_bug.cgi?id=150 Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
565277f63c
commit
a49c3c7736
|
@ -131,7 +131,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
/* Ensure that dirty pages are flushed out with the right creds */
|
/* Ensure that dirty pages are flushed out with the right creds */
|
||||||
if (filp->f_mode & FMODE_WRITE)
|
if (filp->f_mode & FMODE_WRITE)
|
||||||
filemap_fdatawrite(filp->f_mapping);
|
nfs_wb_all(filp->f_path.dentry->d_inode);
|
||||||
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
|
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
|
||||||
return NFS_PROTO(inode)->file_release(inode, filp);
|
return NFS_PROTO(inode)->file_release(inode, filp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,7 +514,7 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_nfs_open_context(struct nfs_open_context *ctx)
|
static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
|
||||||
{
|
{
|
||||||
struct inode *inode = ctx->path.dentry->d_inode;
|
struct inode *inode = ctx->path.dentry->d_inode;
|
||||||
|
|
||||||
|
@ -522,8 +522,12 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
|
||||||
return;
|
return;
|
||||||
list_del(&ctx->list);
|
list_del(&ctx->list);
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
if (ctx->state != NULL)
|
if (ctx->state != NULL) {
|
||||||
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
|
if (wait)
|
||||||
|
nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
|
||||||
|
else
|
||||||
|
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
|
||||||
|
}
|
||||||
if (ctx->cred != NULL)
|
if (ctx->cred != NULL)
|
||||||
put_rpccred(ctx->cred);
|
put_rpccred(ctx->cred);
|
||||||
dput(ctx->path.dentry);
|
dput(ctx->path.dentry);
|
||||||
|
@ -531,6 +535,16 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
|
||||||
kfree(ctx);
|
kfree(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void put_nfs_open_context(struct nfs_open_context *ctx)
|
||||||
|
{
|
||||||
|
__put_nfs_open_context(ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_nfs_open_context_sync(struct nfs_open_context *ctx)
|
||||||
|
{
|
||||||
|
__put_nfs_open_context(ctx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
|
@ -577,7 +591,7 @@ static void nfs_file_clear_open_context(struct file *filp)
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
|
list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
put_nfs_open_context(ctx);
|
put_nfs_open_context_sync(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc
|
||||||
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
|
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
|
||||||
extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
|
extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
|
||||||
extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
|
extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
|
||||||
extern int nfs4_do_close(struct path *path, struct nfs4_state *state);
|
extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait);
|
||||||
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
|
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
|
||||||
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);
|
||||||
|
@ -209,6 +209,7 @@ extern void nfs4_drop_state_owner(struct nfs4_state_owner *);
|
||||||
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
|
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
|
||||||
extern void nfs4_put_open_state(struct nfs4_state *);
|
extern void nfs4_put_open_state(struct nfs4_state *);
|
||||||
extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
|
extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
|
||||||
|
extern void nfs4_close_sync(struct path *, struct nfs4_state *, mode_t);
|
||||||
extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
|
extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
|
||||||
extern void nfs4_schedule_state_recovery(struct nfs_client *);
|
extern void nfs4_schedule_state_recovery(struct nfs_client *);
|
||||||
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
|
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
|
||||||
|
|
|
@ -1305,7 +1305,7 @@ static const struct rpc_call_ops nfs4_close_ops = {
|
||||||
*
|
*
|
||||||
* NOTE: Caller must be holding the sp->so_owner semaphore!
|
* NOTE: Caller must be holding the sp->so_owner semaphore!
|
||||||
*/
|
*/
|
||||||
int nfs4_do_close(struct path *path, struct nfs4_state *state)
|
int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
|
||||||
{
|
{
|
||||||
struct nfs_server *server = NFS_SERVER(state->inode);
|
struct nfs_server *server = NFS_SERVER(state->inode);
|
||||||
struct nfs4_closedata *calldata;
|
struct nfs4_closedata *calldata;
|
||||||
|
@ -1333,8 +1333,11 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state)
|
||||||
task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata);
|
task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata);
|
||||||
if (IS_ERR(task))
|
if (IS_ERR(task))
|
||||||
return PTR_ERR(task);
|
return PTR_ERR(task);
|
||||||
|
status = 0;
|
||||||
|
if (wait)
|
||||||
|
status = rpc_wait_for_completion_task(task);
|
||||||
rpc_put_task(task);
|
rpc_put_task(task);
|
||||||
return 0;
|
return status;
|
||||||
out_free_calldata:
|
out_free_calldata:
|
||||||
kfree(calldata);
|
kfree(calldata);
|
||||||
out:
|
out:
|
||||||
|
@ -1365,7 +1368,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
|
||||||
}
|
}
|
||||||
ret = PTR_ERR(filp);
|
ret = PTR_ERR(filp);
|
||||||
out_close:
|
out_close:
|
||||||
nfs4_close_state(path, state, nd->intent.open.flags);
|
nfs4_close_sync(path, state, nd->intent.open.flags);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1450,7 +1453,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
|
||||||
nfs4_intent_set_file(nd, &path, state);
|
nfs4_intent_set_file(nd, &path, state);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
nfs4_close_state(&path, state, openflags);
|
nfs4_close_sync(&path, state, openflags);
|
||||||
out_drop:
|
out_drop:
|
||||||
d_drop(dentry);
|
d_drop(dentry);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1904,7 +1907,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
||||||
if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
|
if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
|
||||||
status = nfs4_intent_set_file(nd, &path, state);
|
status = nfs4_intent_set_file(nd, &path, state);
|
||||||
else
|
else
|
||||||
nfs4_close_state(&path, state, flags);
|
nfs4_close_sync(&path, state, flags);
|
||||||
out:
|
out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,7 +425,7 @@ void nfs4_put_open_state(struct nfs4_state *state)
|
||||||
/*
|
/*
|
||||||
* Close the current file.
|
* Close the current file.
|
||||||
*/
|
*/
|
||||||
void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
|
static void __nfs4_close(struct path *path, struct nfs4_state *state, mode_t mode, int wait)
|
||||||
{
|
{
|
||||||
struct nfs4_state_owner *owner = state->owner;
|
struct nfs4_state_owner *owner = state->owner;
|
||||||
int call_close = 0;
|
int call_close = 0;
|
||||||
|
@ -466,7 +466,17 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
|
||||||
nfs4_put_open_state(state);
|
nfs4_put_open_state(state);
|
||||||
nfs4_put_state_owner(owner);
|
nfs4_put_state_owner(owner);
|
||||||
} else
|
} else
|
||||||
nfs4_do_close(path, state);
|
nfs4_do_close(path, state, wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
|
||||||
|
{
|
||||||
|
__nfs4_close(path, state, mode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nfs4_close_sync(struct path *path, struct nfs4_state *state, mode_t mode)
|
||||||
|
{
|
||||||
|
__nfs4_close(path, state, mode, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue