]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
STABLE14-linux-remove-negative-dentry-20041209
authorChas Williams <chas@cmf.nrl.navy.mil>
Mon, 13 Dec 2004 19:35:02 +0000 (19:35 +0000)
committerDerrick Brashear <shadow@dementia.org>
Mon, 13 Dec 2004 19:35:02 +0000 (19:35 +0000)
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)

src/afs/LINUX/osi_vnodeops.c
src/afs/VNOPS/afs_vnop_remove.c

index a4147277ada8cc408e72e87f49e3fb607185fa5f..d6c86da239f1f178c0d8eec2410363b58efcc0c0 100644 (file)
@@ -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
index 202fff9435e588caf83acd2e6f8eab447aa75ef4..fc5431fffb934dcae0cc1b81e3478d56121bb3b2 100644 (file)
@@ -14,9 +14,7 @@
  * afs_IsWired (DUX)
  * afsremove
  * afs_remove
- *
- * Local:
- * newname
+ * afs_newname
  *
  */
 #include <afsconfig.h>
@@ -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)