From ec352e0bfd6f324c6b95a3b1e816809c24004e84 Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Sun, 27 Dec 2009 11:06:01 +0000 Subject: [PATCH] Abstract out Linux sillyrename function In order to keep the dcache happy, the Linux client has its own sillyrename function. Abstract this out from afs_linux_unlink into a function of its own (afs_linux_sillyrename) so we can make use of it from other vnodeops. Change-Id: I298251c400dfc22efb3bacaa72612b28a5409112 Reviewed-on: http://gerrit.openafs.org/1034 Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear --- src/afs/LINUX/osi_vnodeops.c | 112 +++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 46 deletions(-) diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index e89d18ebd2..6543efde72 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -1115,6 +1115,66 @@ afs_linux_link(struct dentry *olddp, struct inode *dip, struct dentry *newdp) return afs_convert_code(code); } +/* We have to have a Linux specific sillyrename function, because we + * also have to keep the dcache up to date when we're doing a silly + * rename - so we don't want the generic vnodeops doing this behind our + * back. + */ + +static int +afs_linux_sillyrename(struct inode *dir, struct dentry *dentry, + cred_t *credp) +{ + struct vcache *tvc = VTOAFS(dentry->d_inode); + struct dentry *__dp = NULL; + char *__name = NULL; + int code; + + do { + dput(__dp); + + AFS_GLOCK(); + if (__name) + osi_FreeSmallSpace(__name); + __name = afs_newname(); + AFS_GUNLOCK(); + + __dp = lookup_one_len(__name, dentry->d_parent, strlen(__name)); + + if (IS_ERR(__dp)) { + osi_FreeSmallSpace(__name); + return EBUSY; + } + } while (__dp->d_inode != NULL); + + AFS_GLOCK(); + code = afs_rename(VTOAFS(dir), (char *)dentry->d_name.name, + VTOAFS(dir), (char *)__dp->d_name.name, + credp); + if (!code) { + tvc->mvid = (void *) __name; + crhold(credp); + if (tvc->uncred) { + crfree(tvc->uncred); + } + tvc->uncred = credp; + tvc->f.states |= CUnlinked; + afs_linux_set_nfsfs_renamed(dentry); + } else { + osi_FreeSmallSpace(__name); + } + AFS_GUNLOCK(); + + if (!code) { + __dp->d_time = hgetlo(VTOAFS(dir)->f.m.DataVersion); + d_move(dentry, __dp); + } + dput(__dp); + + return code; +} + + static int afs_linux_unlink(struct inode *dip, struct dentry *dp) { @@ -1124,59 +1184,19 @@ afs_linux_unlink(struct inode *dip, struct dentry *dp) struct vcache *tvc = VTOAFS(dp->d_inode); afs_maybe_lock_kernel(); + if (VREFCOUNT(tvc) > 1 && tvc->opens > 0 && !(tvc->f.states & CUnlinked)) { - struct dentry *__dp; - char *__name; - - __dp = NULL; - __name = NULL; - do { - dput(__dp); - - AFS_GLOCK(); - if (__name) - osi_FreeSmallSpace(__name); - __name = afs_newname(); - AFS_GUNLOCK(); - - __dp = lookup_one_len(__name, dp->d_parent, strlen(__name)); - - if (IS_ERR(__dp)) - goto out; - } while (__dp->d_inode != NULL); + code = afs_linux_sillyrename(dip, dp, credp); + } else { AFS_GLOCK(); - code = afs_rename(VTOAFS(dip), (char *)dp->d_name.name, VTOAFS(dip), (char *)__dp->d_name.name, credp); - if (!code) { - tvc->mvid = (void *) __name; - crhold(credp); - if (tvc->uncred) { - crfree(tvc->uncred); - } - tvc->uncred = credp; - tvc->f.states |= CUnlinked; - afs_linux_set_nfsfs_renamed(dp); - } else { - osi_FreeSmallSpace(__name); - } + code = afs_remove(VTOAFS(dip), (char *)name, credp); AFS_GUNLOCK(); - - if (!code) { - __dp->d_time = hgetlo(VTOAFS(dip)->f.m.DataVersion); - d_move(dp, __dp); - } - dput(__dp); - - goto out; + if (!code) + d_drop(dp); } - AFS_GLOCK(); - code = afs_remove(VTOAFS(dip), (char *)name, credp); - AFS_GUNLOCK(); - if (!code) - d_drop(dp); -out: afs_maybe_unlock_kernel(); crfree(credp); return afs_convert_code(code);