Skip to content

Commit

Permalink
Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
Browse files Browse the repository at this point in the history
* git://git.linux-nfs.org/pub/linux/nfs-2.6:
  NFSv4: Fix an rpc_cred reference leakage in fs/nfs/delegation.c
  NFSv4: Ensure that we wait for the CLOSE request to complete
  NFS: Fix a race in sillyrename
  NFS: Fix a writeback race...
  • Loading branch information
Linus Torvalds committed Oct 19, 2007
2 parents 4800be2 + 603c83d commit b04cde3
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 36 deletions.
3 changes: 2 additions & 1 deletion fs/nfs/delegation.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
spin_unlock(&inode->i_lock);

spin_unlock(&clp->cl_lock);
kfree(delegation);
if (delegation != NULL)
nfs_free_delegation(delegation);
return status;
}

Expand Down
14 changes: 11 additions & 3 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
nfs_fattr_init(&fattr);
desc->entry = &my_entry;

nfs_block_sillyrename(dentry);
while(!desc->entry->eof) {
res = readdir_search_pagecache(desc);

Expand Down Expand Up @@ -592,6 +593,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
break;
}
}
nfs_unblock_sillyrename(dentry);
unlock_kernel();
if (res > 0)
res = 0;
Expand Down Expand Up @@ -866,6 +868,7 @@ struct dentry_operations nfs_dentry_operations = {
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct dentry *res;
struct dentry *parent;
struct inode *inode = NULL;
int error;
struct nfs_fh fhandle;
Expand Down Expand Up @@ -894,26 +897,31 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
goto out_unlock;
}

parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent);
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error == -ENOENT)
goto no_entry;
if (error < 0) {
res = ERR_PTR(error);
goto out_unlock;
goto out_unblock_sillyrename;
}
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
res = (struct dentry *)inode;
if (IS_ERR(res))
goto out_unlock;
goto out_unblock_sillyrename;

no_entry:
res = d_materialise_unique(dentry, inode);
if (res != NULL) {
if (IS_ERR(res))
goto out_unlock;
goto out_unblock_sillyrename;
dentry = res;
}
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_unblock_sillyrename:
nfs_unblock_sillyrename(parent);
out_unlock:
unlock_kernel();
out:
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ nfs_file_release(struct inode *inode, struct file *filp)
{
/* Ensure that dirty pages are flushed out with the right creds */
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);
return NFS_PROTO(inode)->file_release(inode, filp);
}
Expand Down
25 changes: 21 additions & 4 deletions fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,23 +514,37 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *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;

if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
return;
list_del(&ctx->list);
spin_unlock(&inode->i_lock);
if (ctx->state != NULL)
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
if (ctx->state != NULL) {
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)
put_rpccred(ctx->cred);
dput(ctx->path.dentry);
mntput(ctx->path.mnt);
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
* shared pages
Expand Down Expand Up @@ -577,7 +591,7 @@ static void nfs_file_clear_open_context(struct file *filp)
spin_lock(&inode->i_lock);
list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
spin_unlock(&inode->i_lock);
put_nfs_open_context(ctx);
put_nfs_open_context_sync(ctx);
}
}

Expand Down Expand Up @@ -1169,6 +1183,9 @@ static void init_once(struct kmem_cache * cachep, void *foo)
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
nfsi->ncommit = 0;
nfsi->npages = 0;
atomic_set(&nfsi->silly_count, 1);
INIT_HLIST_HEAD(&nfsi->silly_list);
init_waitqueue_head(&nfsi->waitqueue);
nfs4_init_once(nfsi);
}

Expand Down
3 changes: 2 additions & 1 deletion fs/nfs/nfs4_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_async_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 int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
Expand Down Expand Up @@ -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 void nfs4_put_open_state(struct nfs4_state *);
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_schedule_state_recovery(struct nfs_client *);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
Expand Down
19 changes: 14 additions & 5 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,7 @@ static const struct rpc_call_ops nfs4_close_ops = {
*
* 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 nfs4_closedata *calldata;
Expand Down Expand Up @@ -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);
if (IS_ERR(task))
return PTR_ERR(task);
status = 0;
if (wait)
status = rpc_wait_for_completion_task(task);
rpc_put_task(task);
return 0;
return status;
out_free_calldata:
kfree(calldata);
out:
Expand Down Expand Up @@ -1365,13 +1368,14 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
}
ret = PTR_ERR(filp);
out_close:
nfs4_close_state(path, state, nd->intent.open.flags);
nfs4_close_sync(path, state, nd->intent.open.flags);
return ret;
}

struct dentry *
nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
struct dentry *parent;
struct path path = {
.mnt = nd->mnt,
.dentry = dentry,
Expand All @@ -1394,19 +1398,24 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
if (IS_ERR(cred))
return (struct dentry *)cred;
parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent);
state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
put_rpccred(cred);
if (IS_ERR(state)) {
if (PTR_ERR(state) == -ENOENT) {
d_add(dentry, NULL);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
}
nfs_unblock_sillyrename(parent);
return (struct dentry *)state;
}
res = d_add_unique(dentry, igrab(state->inode));
if (res != NULL)
path.dentry = res;
nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));
nfs_unblock_sillyrename(parent);
nfs4_intent_set_file(nd, &path, state);
return res;
}
Expand Down Expand Up @@ -1444,7 +1453,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
nfs4_intent_set_file(nd, &path, state);
return 1;
}
nfs4_close_state(&path, state, openflags);
nfs4_close_sync(&path, state, openflags);
out_drop:
d_drop(dentry);
return 0;
Expand Down Expand Up @@ -1898,7 +1907,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
status = nfs4_intent_set_file(nd, &path, state);
else
nfs4_close_state(&path, state, flags);
nfs4_close_sync(&path, state, flags);
out:
return status;
}
Expand Down
14 changes: 12 additions & 2 deletions fs/nfs/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ void nfs4_put_open_state(struct nfs4_state *state)
/*
* 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;
int call_close = 0;
Expand Down Expand Up @@ -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_state_owner(owner);
} 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);
}

/*
Expand Down
Loading

0 comments on commit b04cde3

Please sign in to comment.