From: Chas Williams Date: Mon, 13 Dec 2004 19:35:02 +0000 (+0000) Subject: STABLE14-linux-remove-negative-dentry-20041209 X-Git-Tag: openafs-devel-1_3_76~8 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=91390f3ca3700234e2b461e4949028a1b96a0c17;p=packages%2Fo%2Fopenafs.git STABLE14-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. (cherry picked from commit f8432c77965a79047429b18ae0ee214a45e4c9a4) --- 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)