kernel - cycle vnode in cache_unlink()
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 1 Feb 2013 17:57:55 +0000 (09:57 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 1 Feb 2013 17:57:55 +0000 (09:57 -0800)
* cache_unlink() and cache_rename() are called by VFS's to update the
  namecache after a file deletion or rename.  cache_rename() also calls
  cache_unlink().

* Add code to this function which cycles any vnode attached to the
  namecache entry for the case where its refs are 0.  This will
  trigger VOP_INACTIVE and allow the VFS to detect file deletions.

  Generally speaking this means that VFS's no longer have to detect
  deleted files in code paths outside of VOP_INACTIVE w/regards to
  forcing a reclaim on the vnode.

* HAMMER2 now depends on this behavior.  The change in behavior allows
  HAMMER2 to do away with inode backpointers from chain structures,
  greatly simplifying the code and removing a chicken-egg dependency.

* Other VFSs (HAMMER, TMPFS, UFS) may be adjusted in the future but for
  now their file deletion code outside of VOP_INACTIVE is being left
  intact.

sys/kern/vfs_cache.c

index 8ae5540..19b44be 100644 (file)
@@ -1417,9 +1417,19 @@ cache_rename(struct nchandle *fnch, struct nchandle *tnch)
 }
 
 /*
- * Perform actions consistent with unlinking a file.  The namecache
- * entry is marked DESTROYED so it no longer shows up in searches,
+ * Perform actions consistent with unlinking a file.  The passed-in ncp
+ * must be locked.
+ *
+ * The ncp is marked DESTROYED so it no longer shows up in searches,
  * and will be physically deleted when the vnode goes away.
+ *
+ * If the related vnode has no refs then we cycle it through vget()/vput()
+ * to (possibly if we don't have a ref race) trigger a deactivation,
+ * allowing the VFS to trivially detect and recycle the deleted vnode
+ * via VOP_INACTIVE().
+ *
+ * NOTE: _cache_rename() will automatically call _cache_unlink() on the
+ *      target ncp.
  */
 void
 cache_unlink(struct nchandle *nch)
@@ -1430,7 +1440,23 @@ cache_unlink(struct nchandle *nch)
 static void
 _cache_unlink(struct namecache *ncp)
 {
+       struct vnode *vp;
+
+       /*
+        * Causes lookups to fail and allows another ncp with the same
+        * name to be created under ncp->nc_parent.
+        */
        ncp->nc_flag |= NCF_DESTROYED;
+
+       /*
+        * Attempt to trigger a deactivation.
+        */
+       if ((ncp->nc_flag & NCF_UNRESOLVED) == 0 &&
+           (vp = ncp->nc_vp) != NULL &&
+           !sysref_isactive(&vp->v_sysref)) {
+               if (vget(vp, LK_SHARED) == 0)
+                       vput(vp);
+       }
 }
 
 /*