Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 71668
b: refs/heads/master
c: 565277f
h: refs/heads/master
v: v3
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Oct 19, 2007
1 parent 574c479 commit 4e215bd
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 61e930a904966cc37e0a3404276f0b73037e57ca
refs/heads/master: 565277f63c616e11c37309a1e98c052d18ebbb55
14 changes: 11 additions & 3 deletions trunk/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
3 changes: 3 additions & 0 deletions trunk/fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,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
6 changes: 6 additions & 0 deletions trunk/fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,7 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct
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 +1395,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
114 changes: 99 additions & 15 deletions trunk/fs/nfs/unlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@


struct nfs_unlinkdata {
struct hlist_node list;
struct nfs_removeargs args;
struct nfs_removeres res;
struct inode *dir;
Expand Down Expand Up @@ -52,6 +53,20 @@ static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
return 0;
}

static void nfs_free_dname(struct nfs_unlinkdata *data)
{
kfree(data->args.name.name);
data->args.name.name = NULL;
data->args.name.len = 0;
}

static void nfs_dec_sillycount(struct inode *dir)
{
struct nfs_inode *nfsi = NFS_I(dir);
if (atomic_dec_return(&nfsi->silly_count) == 1)
wake_up(&nfsi->waitqueue);
}

/**
* nfs_async_unlink_init - Initialize the RPC info
* task: rpc_task of the sillydelete
Expand Down Expand Up @@ -95,6 +110,8 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
static void nfs_async_unlink_release(void *calldata)
{
struct nfs_unlinkdata *data = calldata;

nfs_dec_sillycount(data->dir);
nfs_free_unlinkdata(data);
}

Expand All @@ -104,33 +121,100 @@ static const struct rpc_call_ops nfs_unlink_ops = {
.rpc_release = nfs_async_unlink_release,
};

static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data)
{
struct rpc_task *task;
struct dentry *alias;

alias = d_lookup(parent, &data->args.name);
if (alias != NULL) {
int ret = 0;
/*
* Hey, we raced with lookup... See if we need to transfer
* the sillyrename information to the aliased dentry.
*/
nfs_free_dname(data);
spin_lock(&alias->d_lock);
if (!(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
alias->d_fsdata = data;
alias->d_flags ^= DCACHE_NFSFS_RENAMED;
ret = 1;
}
spin_unlock(&alias->d_lock);
nfs_dec_sillycount(dir);
dput(alias);
return ret;
}
data->dir = igrab(dir);
if (!data->dir) {
nfs_dec_sillycount(dir);
return 0;
}
data->args.fh = NFS_FH(dir);
nfs_fattr_init(&data->res.dir_attr);

task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
if (!IS_ERR(task))
rpc_put_task(task);
return 1;
}

static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
{
struct dentry *parent;
struct inode *dir;
int ret = 0;

if (nfs_copy_dname(dentry, data) < 0)
goto out_free;

parent = dget_parent(dentry);
if (parent == NULL)
goto out_free;
dir = igrab(parent->d_inode);
dir = parent->d_inode;
if (nfs_copy_dname(dentry, data) == 0)
goto out_dput;
/* Non-exclusive lock protects against concurrent lookup() calls */
spin_lock(&dir->i_lock);
if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) {
/* Deferred delete */
hlist_add_head(&data->list, &NFS_I(dir)->silly_list);
spin_unlock(&dir->i_lock);
ret = 1;
goto out_dput;
}
spin_unlock(&dir->i_lock);
ret = nfs_do_call_unlink(parent, dir, data);
out_dput:
dput(parent);
if (dir == NULL)
goto out_free;
out_free:
return ret;
}

data->dir = dir;
data->args.fh = NFS_FH(dir);
nfs_fattr_init(&data->res.dir_attr);
void nfs_block_sillyrename(struct dentry *dentry)
{
struct nfs_inode *nfsi = NFS_I(dentry->d_inode);

task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
if (!IS_ERR(task))
rpc_put_task(task);
return 1;
out_free:
return 0;
wait_event(nfsi->waitqueue, atomic_cmpxchg(&nfsi->silly_count, 1, 0) == 1);
}

void nfs_unblock_sillyrename(struct dentry *dentry)
{
struct inode *dir = dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(dir);
struct nfs_unlinkdata *data;

atomic_inc(&nfsi->silly_count);
spin_lock(&dir->i_lock);
while (!hlist_empty(&nfsi->silly_list)) {
if (!atomic_inc_not_zero(&nfsi->silly_count))
break;
data = hlist_entry(nfsi->silly_list.first, struct nfs_unlinkdata, list);
hlist_del(&data->list);
spin_unlock(&dir->i_lock);
if (nfs_do_call_unlink(dentry, dir, data) == 0)
nfs_free_unlinkdata(data);
spin_lock(&dir->i_lock);
}
spin_unlock(&dir->i_lock);
}

/**
Expand Down
8 changes: 8 additions & 0 deletions trunk/include/linux/nfs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ struct nfs_inode {
/* Open contexts for shared mmap writes */
struct list_head open_files;

/* Number of in-flight sillydelete RPC calls */
atomic_t silly_count;
/* List of deferred sillydelete requests */
struct hlist_head silly_list;
wait_queue_head_t waitqueue;

#ifdef CONFIG_NFS_V4
struct nfs4_cached_acl *nfs4_acl;
/* NFSv4 state */
Expand Down Expand Up @@ -394,6 +400,8 @@ extern void nfs_release_automount_timer(void);
*/
extern int nfs_async_unlink(struct inode *dir, struct dentry *dentry);
extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
extern void nfs_block_sillyrename(struct dentry *dentry);
extern void nfs_unblock_sillyrename(struct dentry *dentry);

/*
* linux/fs/nfs/write.c
Expand Down

0 comments on commit 4e215bd

Please sign in to comment.