Skip to content

Commit

Permalink
nfs: move nfs_sillyrename to unlink.c
Browse files Browse the repository at this point in the history
...since that's where most of the sillyrenaming code lives. A comment
block is added to the beginning as well to clarify how sillyrenaming
works. Also, make nfs_async_unlink static as nfs_sillyrename is the only
caller.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Jeff Layton authored and Trond Myklebust committed Sep 17, 2010
1 parent e8582a8 commit 779c517
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 72 deletions.
70 changes: 0 additions & 70 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1498,76 +1498,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
return error;
}

static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
static unsigned int sillycounter;
const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2;
const int countersize = sizeof(sillycounter)*2;
const int slen = sizeof(".nfs")+fileidsize+countersize-1;
char silly[slen+1];
struct qstr qsilly;
struct dentry *sdentry;
int error = -EIO;

dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
atomic_read(&dentry->d_count));
nfs_inc_stats(dir, NFSIOS_SILLYRENAME);

/*
* We don't allow a dentry to be silly-renamed twice.
*/
error = -EBUSY;
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
goto out;

sprintf(silly, ".nfs%*.*Lx",
fileidsize, fileidsize,
(unsigned long long)NFS_FILEID(dentry->d_inode));

/* Return delegation in anticipation of the rename */
nfs_inode_return_delegation(dentry->d_inode);

sdentry = NULL;
do {
char *suffix = silly + slen - countersize;

dput(sdentry);
sillycounter++;
sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);

dfprintk(VFS, "NFS: trying to rename %s to %s\n",
dentry->d_name.name, silly);

sdentry = lookup_one_len(silly, dentry->d_parent, slen);
/*
* N.B. Better to return EBUSY here ... it could be
* dangerous to delete the file while it's in use.
*/
if (IS_ERR(sdentry))
goto out;
} while(sdentry->d_inode != NULL); /* need negative lookup */

qsilly.name = silly;
qsilly.len = strlen(silly);
if (dentry->d_inode) {
error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
dir, &qsilly);
nfs_mark_for_revalidate(dentry->d_inode);
} else
error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
dir, &qsilly);
if (!error) {
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
d_move(dentry, sdentry);
error = nfs_async_unlink(dir, dentry);
/* If we return 0 we don't unlink */
}
dput(sdentry);
out:
return error;
}

/*
* Remove a file after making sure there are no pending writes,
* and after checking that the file has only one user.
Expand Down
85 changes: 84 additions & 1 deletion fs/nfs/unlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
#include <linux/nfs_fs.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/namei.h>

#include "internal.h"
#include "nfs4_fs.h"
#include "iostat.h"
#include "delegation.h"

struct nfs_unlinkdata {
struct hlist_node list;
Expand Down Expand Up @@ -244,7 +247,7 @@ void nfs_unblock_sillyrename(struct dentry *dentry)
* @dir: parent directory of dentry
* @dentry: dentry to unlink
*/
int
static int
nfs_async_unlink(struct inode *dir, struct dentry *dentry)
{
struct nfs_unlinkdata *data;
Expand Down Expand Up @@ -303,3 +306,83 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
nfs_free_unlinkdata(data);
}

/**
* nfs_sillyrename - Perform a silly-rename of a dentry
* @dir: inode of directory that contains dentry
* @dentry: dentry to be sillyrenamed
*
* NFSv2/3 is stateless and the server doesn't know when the client is
* holding a file open. To prevent application problems when a file is
* unlinked while it's still open, the client performs a "silly-rename".
* That is, it renames the file to a hidden file in the same directory,
* and only performs the unlink once the last reference to it is put.
*
* The final cleanup is done during dentry_iput.
*/
int
nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
static unsigned int sillycounter;
const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2;
const int countersize = sizeof(sillycounter)*2;
const int slen = sizeof(".nfs")+fileidsize+countersize-1;
char silly[slen+1];
struct qstr qsilly;
struct dentry *sdentry;
int error = -EIO;

dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
atomic_read(&dentry->d_count));
nfs_inc_stats(dir, NFSIOS_SILLYRENAME);

/*
* We don't allow a dentry to be silly-renamed twice.
*/
error = -EBUSY;
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
goto out;

sprintf(silly, ".nfs%*.*Lx",
fileidsize, fileidsize,
(unsigned long long)NFS_FILEID(dentry->d_inode));

/* Return delegation in anticipation of the rename */
nfs_inode_return_delegation(dentry->d_inode);

sdentry = NULL;
do {
char *suffix = silly + slen - countersize;

dput(sdentry);
sillycounter++;
sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);

dfprintk(VFS, "NFS: trying to rename %s to %s\n",
dentry->d_name.name, silly);

sdentry = lookup_one_len(silly, dentry->d_parent, slen);
/*
* N.B. Better to return EBUSY here ... it could be
* dangerous to delete the file while it's in use.
*/
if (IS_ERR(sdentry))
goto out;
} while (sdentry->d_inode != NULL); /* need negative lookup */

qsilly.name = silly;
qsilly.len = strlen(silly);
error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
if (dentry->d_inode)
nfs_mark_for_revalidate(dentry->d_inode);
if (!error) {
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
d_move(dentry, sdentry);
error = nfs_async_unlink(dir, dentry);
/* If we return 0 we don't unlink */
}
dput(sdentry);
out:
return error;
}
2 changes: 1 addition & 1 deletion include/linux/nfs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,10 +485,10 @@ extern void nfs_release_automount_timer(void);
/*
* linux/fs/nfs/unlink.c
*/
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);
extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry);

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

0 comments on commit 779c517

Please sign in to comment.