Author: kib
Date: Sun Apr 24 10:47:56 2011
New Revision: 220985
URL: http://svn.freebsd.org/changeset/base/220985

Log:
  VFS sometimes is unable to inactivate a vnode when vnode use count
  goes to zero. E.g., the vnode might be only shared-locked at the time of
  vput() call. Such vnodes are kept in the hash, so they can be found later.
  
  If ffs_valloc() allocated an inode that has its vnode cached in hash, and
  still owing the inactivation, then vget() call from ffs_valloc() clears
  VI_OWEINACT, and then the vnode is reused for the newly allocated inode.
  
  The problem is, the vnode is not reclaimed before it is put to the new
  use. ffs_valloc() recycles vnode vm object, but this is not enough.
  In particular, at least v_vflag should be cleared, and several bits of
  UFS state need to be removed.
  
  It is very inconvenient to call vgone() at this point. Instead, move
  some parts of ufs_reclaim() into helper function ufs_prepare_reclaim(),
  and call the helper from VOP_RECLAIM and ffs_valloc().
  
  Reviewed by:  mckusick
  Tested by:    pho
  MFC after:    3 weeks

Modified:
  head/sys/ufs/ffs/ffs_alloc.c
  head/sys/ufs/ufs/ufs_extern.h
  head/sys/ufs/ufs/ufs_inode.c

Modified: head/sys/ufs/ffs/ffs_alloc.c
==============================================================================
--- head/sys/ufs/ffs/ffs_alloc.c        Sun Apr 24 10:41:13 2011        
(r220984)
+++ head/sys/ufs/ffs/ffs_alloc.c        Sun Apr 24 10:47:56 2011        
(r220985)
@@ -1012,8 +1012,9 @@ dup_alloc:
                ip->i_din2->di_birthtime = ts.tv_sec;
                ip->i_din2->di_birthnsec = ts.tv_nsec;
        }
+       ufs_prepare_reclaim(*vpp);
        ip->i_flag = 0;
-       vnode_destroy_vobject(*vpp);
+       (*vpp)->v_vflag = 0;
        (*vpp)->v_type = VNON;
        if (fs->fs_magic == FS_UFS2_MAGIC)
                (*vpp)->v_op = &ffs_vnodeops2;

Modified: head/sys/ufs/ufs/ufs_extern.h
==============================================================================
--- head/sys/ufs/ufs/ufs_extern.h       Sun Apr 24 10:41:13 2011        
(r220984)
+++ head/sys/ufs/ufs/ufs_extern.h       Sun Apr 24 10:47:56 2011        
(r220985)
@@ -76,6 +76,7 @@ int    ufs_inactive(struct vop_inactive_ar
 int     ufs_init(struct vfsconf *);
 void    ufs_itimes(struct vnode *vp);
 int     ufs_lookup(struct vop_cachedlookup_args *);
+void    ufs_prepare_reclaim(struct vnode *vp);
 int     ufs_readdir(struct vop_readdir_args *);
 int     ufs_reclaim(struct vop_reclaim_args *);
 void    ffs_snapgone(struct inode *);

Modified: head/sys/ufs/ufs/ufs_inode.c
==============================================================================
--- head/sys/ufs/ufs/ufs_inode.c        Sun Apr 24 10:41:13 2011        
(r220984)
+++ head/sys/ufs/ufs/ufs_inode.c        Sun Apr 24 10:47:56 2011        
(r220985)
@@ -172,6 +172,31 @@ out:
        return (error);
 }
 
+void
+ufs_prepare_reclaim(struct vnode *vp)
+{
+       struct inode *ip;
+#ifdef QUOTA
+       int i;
+#endif
+
+       ip = VTOI(vp);
+
+       vnode_destroy_vobject(vp);
+#ifdef QUOTA
+       for (i = 0; i < MAXQUOTAS; i++) {
+               if (ip->i_dquot[i] != NODQUOT) {
+                       dqrele(vp, ip->i_dquot[i]);
+                       ip->i_dquot[i] = NODQUOT;
+               }
+       }
+#endif
+#ifdef UFS_DIRHASH
+       if (ip->i_dirhash != NULL)
+               ufsdirhash_free(ip);
+#endif
+}
+
 /*
  * Reclaim an inode so that it can be used for other purposes.
  */
@@ -185,14 +210,9 @@ ufs_reclaim(ap)
        struct vnode *vp = ap->a_vp;
        struct inode *ip = VTOI(vp);
        struct ufsmount *ump = ip->i_ump;
-#ifdef QUOTA
-       int i;
-#endif
 
-       /*
-        * Destroy the vm object and flush associated pages.
-        */
-       vnode_destroy_vobject(vp);
+       ufs_prepare_reclaim(vp);
+
        if (ip->i_flag & IN_LAZYMOD)
                ip->i_flag |= IN_MODIFIED;
        UFS_UPDATE(vp, 0);
@@ -200,21 +220,7 @@ ufs_reclaim(ap)
         * Remove the inode from its hash chain.
         */
        vfs_hash_remove(vp);
-       /*
-        * Purge old data structures associated with the inode.
-        */
-#ifdef QUOTA
-       for (i = 0; i < MAXQUOTAS; i++) {
-               if (ip->i_dquot[i] != NODQUOT) {
-                       dqrele(vp, ip->i_dquot[i]);
-                       ip->i_dquot[i] = NODQUOT;
-               }
-       }
-#endif
-#ifdef UFS_DIRHASH
-       if (ip->i_dirhash != NULL)
-               ufsdirhash_free(ip);
-#endif
+
        /*
         * Lock the clearing of v_data so ffs_lock() can inspect it
         * prior to obtaining the lock.
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to