nfs: move nfs_sillyrename to unlink.c
...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>
This commit is contained in:
parent
e8582a8b96
commit
779c51795b
3 changed files with 85 additions and 72 deletions
70
fs/nfs/dir.c
70
fs/nfs/dir.c
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue