From: Chas Williams Date: Thu, 9 Dec 2004 16:14:21 +0000 (+0000) Subject: linux-remove-negative-dentry-20041209 X-Git-Tag: BP-disconnected~92 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=f8432c77965a79047429b18ae0ee214a45e4c9a4;p=packages%2Fo%2Fopenafs.git linux-remove-negative-dentry-20041209 FIXES 16735 during unlink, afs sometimes renames the file instead of deleting it. this isnt reflected properly in the dcache in linux. the following patch attempts to address this issue. newname is renamed to afs_newname and exported. afs_linux_unlink() checks to see if the file is open. if so, it creates a negative dcache entry using the name suggested by afs_newname(). then dmove() moves (exchanges) dp and __dp. __dp is now a negative dentry for the old name and is put/dropped. --- diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index a4147277a..d6c86da23 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -1163,18 +1163,63 @@ afs_linux_link(struct dentry *olddp, struct inode *dip, struct dentry *newdp) int afs_linux_unlink(struct inode *dip, struct dentry *dp) { - int code; + int code = EBUSY; cred_t *credp = crref(); const char *name = dp->d_name.name; + struct vcache *tvc = ITOAFS(dp->d_inode); #if defined(AFS_LINUX26_ENV) lock_kernel(); #endif + if (((VREFCOUNT(tvc) > 0) && tvc->opens > 0) + && !(tvc->states & CUnlinked)) { + struct dentry *__dp; + char *__name; + extern char *afs_newname(); + + __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); + + AFS_GLOCK(); + code = afs_rename(ITOAFS(dip), dp->d_name.name, ITOAFS(dip), __dp->d_name.name, credp); + if (!code) { + tvc->mvid = __name; + crhold(credp); + if (tvc->uncred) { + crfree(tvc->uncred); + } + tvc->uncred = credp; + tvc->states |= CUnlinked; + } + AFS_GUNLOCK(); + + if (!code) + d_move(dp, __dp); + dput(__dp); + + goto out; + } + AFS_GLOCK(); code = afs_remove(ITOAFS(dip), name, credp); AFS_GUNLOCK(); if (!code) d_drop(dp); +out: #if defined(AFS_LINUX26_ENV) unlock_kernel(); #endif diff --git a/src/afs/VNOPS/afs_vnop_remove.c b/src/afs/VNOPS/afs_vnop_remove.c index 202fff943..fc5431fff 100644 --- a/src/afs/VNOPS/afs_vnop_remove.c +++ b/src/afs/VNOPS/afs_vnop_remove.c @@ -14,9 +14,7 @@ * afs_IsWired (DUX) * afsremove * afs_remove - * - * Local: - * newname + * afs_newname * */ #include @@ -193,8 +191,8 @@ afsremove(register struct vcache *adp, register struct dcache *tdc, return (0); } -static char * -newname(void) +char * +afs_newname(void) { char *name, *sp, *p = ".__afs"; afs_int32 rd = afs_random() & 0xffff; @@ -412,7 +410,7 @@ afs_remove(OSI_VC_ARG(adp), aname, acred) #endif #endif { - char *unlname = newname(); + char *unlname = afs_newname(); ReleaseWriteLock(&adp->lock); if (tdc)