[BACK]Return to vfs_subr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/vfs_subr.c between version 1.308.2.2 and 1.308.2.3

version 1.308.2.2, 2007/12/08 15:52:45 version 1.308.2.3, 2007/12/10 19:31:48
Line 107  __KERNEL_RCSID(0, "$NetBSD$");
Line 107  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/filedesc.h>  #include <sys/filedesc.h>
 #include <sys/kauth.h>  #include <sys/kauth.h>
 #include <sys/atomic.h>  #include <sys/atomic.h>
   #include <sys/kthread.h>
   
 #include <miscfs/specfs/specdev.h>  #include <miscfs/specfs/specdev.h>
 #include <miscfs/syncfs/syncfs.h>  #include <miscfs/syncfs/syncfs.h>
Line 122  extern int vfs_magiclinks; /* 1 => expan
Line 123  extern int vfs_magiclinks; /* 1 => expan
   
 static vnodelst_t vnode_free_list = TAILQ_HEAD_INITIALIZER(vnode_free_list);  static vnodelst_t vnode_free_list = TAILQ_HEAD_INITIALIZER(vnode_free_list);
 static vnodelst_t vnode_hold_list = TAILQ_HEAD_INITIALIZER(vnode_hold_list);  static vnodelst_t vnode_hold_list = TAILQ_HEAD_INITIALIZER(vnode_hold_list);
   static vnodelst_t vrele_list = TAILQ_HEAD_INITIALIZER(vrele_list);
   
   static int vrele_pending;
   static kmutex_t vrele_lock;
   static kcondvar_t vrele_cv;
   
 pool_cache_t vnode_cache;  pool_cache_t vnode_cache;
   
Line 131  MALLOC_DEFINE(M_VNODE, "vnodes", "Dynami
Line 137  MALLOC_DEFINE(M_VNODE, "vnodes", "Dynami
  * Local declarations.   * Local declarations.
  */   */
   
   static void vrele_thread(void *);
 static void insmntque(vnode_t *, struct mount *);  static void insmntque(vnode_t *, struct mount *);
 static int getdevvp(dev_t, vnode_t **, enum vtype);  static int getdevvp(dev_t, vnode_t **, enum vtype);
 static vnode_t *getcleanvnode(void);;  static vnode_t *getcleanvnode(void);;
 void vpanic(vnode_t *, const char *);  void vpanic(vnode_t *, const char *);
   static void vrelenow(vnode_t *);
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
 void  void
Line 148  vpanic(vnode_t *vp, const char *msg)
Line 156  vpanic(vnode_t *vp, const char *msg)
 #define vpanic(vp, msg) /* nothing */  #define vpanic(vp, msg) /* nothing */
 #endif  #endif
   
   void
   vn_init1(void)
   {
   
           /* Create deferred release thread. */
           mutex_init(&vrele_lock, MUTEX_DEFAULT, IPL_NONE);
           cv_init(&vrele_cv, "vrele");
           if (kthread_create(PRI_VM, KTHREAD_MPSAFE, NULL, vrele_thread,
               NULL, NULL, "vrele"))
                   panic("fork vrele");
   }
   
 int  int
 vfs_drainvnodes(long target, struct lwp *l)  vfs_drainvnodes(long target, struct lwp *l)
 {  {
Line 733  checkalias(vnode_t *nvp, dev_t nvp_rdev,
Line 753  checkalias(vnode_t *nvp, dev_t nvp_rdev,
 loop:  loop:
         mutex_enter(&spechash_lock);          mutex_enter(&spechash_lock);
         for (vp = *vpp; vp; vp = vp->v_specnext) {          for (vp = *vpp; vp; vp = vp->v_specnext) {
                   if (vp->v_specinfo == NULL) {
                           vpanic(vp, "checkalias: no specinfo");
                   }
                 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)                  if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
                         continue;                          continue;
                 /*                  /*
Line 755  loop:
Line 778  loop:
                  */                   */
                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))                  if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
                         goto loop;                          goto loop;
                   mutex_enter(&spechash_lock);
                 if (vp->v_specinfo == NULL) {                  if (vp->v_specinfo == NULL) {
                           mutex_exit(&spechash_lock);
                         vput(vp);                          vput(vp);
                         goto loop;                          goto loop;
                 }                  }
                 mutex_enter(&spechash_lock);  
                 break;                  break;
         }          }
         if (vp == NULL || vp->v_tag != VT_NON || vp->v_type != VBLK) {          if (vp == NULL || vp->v_tag != VT_NON || vp->v_type != VBLK) {
Line 769  loop:
Line 793  loop:
                 if (nvp->v_specinfo == NULL) {                  if (nvp->v_specinfo == NULL) {
                         mutex_exit(&spechash_lock);                          mutex_exit(&spechash_lock);
                         uvm_wait("checkalias");                          uvm_wait("checkalias");
                           if (vp != NULL)
                                   vput(vp);
                         goto loop;                          goto loop;
                 }                  }
   
Line 892  vput(vnode_t *vp)
Line 918  vput(vnode_t *vp)
 void  void
 vrelel(vnode_t *vp, int doinactive, int onhead)  vrelel(vnode_t *vp, int doinactive, int onhead)
 {  {
         bool recycle;  
   
         KASSERT(mutex_owned(&vp->v_interlock));          KASSERT(mutex_owned(&vp->v_interlock));
         KASSERT((vp->v_iflag & VI_MARKER) == 0);          KASSERT((vp->v_iflag & VI_MARKER) == 0);
         KASSERT(vp->v_freelisthd == NULL);  
   
         if (vp->v_op == dead_vnodeop_p && (vp->v_iflag & VI_CLEAN) == 0) {          if (vp->v_op == dead_vnodeop_p && (vp->v_iflag & VI_CLEAN) == 0) {
                 vpanic(vp, "dead but not clean");                  vpanic(vp, "dead but not clean");
Line 911  vrelel(vnode_t *vp, int doinactive, int 
Line 935  vrelel(vnode_t *vp, int doinactive, int 
                 mutex_exit(&vp->v_interlock);                  mutex_exit(&vp->v_interlock);
                 return;                  return;
         }          }
   
           /*
            * If the vnode has been cleaned out, release it now.
            */
           if ((vp->v_iflag & VI_CLEAN) != 0) {
                   vrelenow(vp);
                   return;
           }
   
           /*
            * Otherwise, defer reclaim to the kthread; we donate it our
            * last reference.
            */
         if (vp->v_usecount <= 0 || vp->v_writecount != 0) {          if (vp->v_usecount <= 0 || vp->v_writecount != 0) {
                 vpanic(vp, "vput: bad ref count");                  vpanic(vp, "vput: bad ref count");
         }          }
           if ((vp->v_iflag & VI_INACTPEND) == 0) {
                   vp->v_iflag |= VI_INACTPEND;
                   mutex_enter(&vrele_lock);
                   TAILQ_INSERT_TAIL(&vrele_list, vp, v_freelist);
                   if (++vrele_pending > (desiredvnodes >> 8))
                           cv_signal(&vrele_cv);
                   mutex_exit(&vrele_lock);
           }
           mutex_exit(&vp->v_interlock);
   }
   
   static void
   vrelenow(vnode_t *vp)
   {
           bool recycle;
           int error;
   
           KASSERT(mutex_owned(&vp->v_interlock));
   
         /*          /*
          * If not clean, deactivate the vnode, but preserve our reference           * If not clean, deactivate the vnode, but preserve
          * across the call to VOP_INACTIVE() to prevent another thread from           * our reference across the call to VOP_INACTIVE().
          * trying to do the same.  
          */           */
         recycle = false;          recycle = false;
         if ((vp->v_iflag & VI_CLEAN) == 0) {          if ((vp->v_iflag & VI_CLEAN) == 0) {
                 if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK) == 0) {                  error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY);
                   if (error == 0) {
                         VOP_INACTIVE(vp, &recycle);                          VOP_INACTIVE(vp, &recycle);
                   } else {
                           /* XXX */
                           vprint("vrelenow: unable to lock %p", vp);
                 }                  }
                   /*
                    * The vnode may have gained another reference
                    * while being deactivated.
                    */
                 mutex_enter(&vp->v_interlock);                  mutex_enter(&vp->v_interlock);
                 if (vp->v_usecount > 1) {                  if (vp->v_usecount > 1) {
                         /*  
                          * Gained another reference while being  
                          * deactivated.  
                          */  
                         vp->v_usecount--;                          vp->v_usecount--;
                         mutex_exit(&vp->v_interlock);                          mutex_exit(&vp->v_interlock);
                         return;                          return;
Line 938  vrelel(vnode_t *vp, int doinactive, int 
Line 996  vrelel(vnode_t *vp, int doinactive, int 
         }          }
   
         /*          /*
          * Recycle the vnode if the file is now unused (unlinked),           * Take care of space accounting.
          * otherwise just free it.  
          *           *
          * XXXAD may need to re-inactivate due to race w/another           * XXXAD may need to re-inactivate due to race w/another
          * thread gaining and dropping a reference above.           * thread gaining and dropping a reference above.
Line 950  vrelel(vnode_t *vp, int doinactive, int 
Line 1007  vrelel(vnode_t *vp, int doinactive, int 
         }          }
         vp->v_iflag &= ~(VI_TEXT|VI_EXECMAP|VI_WRMAP|VI_MAPPED);          vp->v_iflag &= ~(VI_TEXT|VI_EXECMAP|VI_WRMAP|VI_MAPPED);
         vp->v_vflag &= ~VV_MAPPED;          vp->v_vflag &= ~VV_MAPPED;
   
           /*
            * Recycle the vnode if the file is now unused (unlinked),
            * otherwise just free it.
            */
         if (recycle) {          if (recycle) {
                 vclean(vp, DOCLOSE);                  vclean(vp, DOCLOSE);
         }          }
   
         KASSERT(vp->v_usecount > 0);          KASSERT(vp->v_usecount > 0);
         KASSERT(vp->v_freelisthd == NULL);  
   
         if (vp->v_op == dead_vnodeop_p && (vp->v_iflag & VI_CLEAN) == 0) {          if (vp->v_op == dead_vnodeop_p &&
               (vp->v_iflag & VI_CLEAN) == 0) {
                 vpanic(vp, "dead but not clean");                  vpanic(vp, "dead but not clean");
         }          }
   
Line 1005  vrele(vnode_t *vp)
Line 1066  vrele(vnode_t *vp)
         vrelel(vp, 1, 0);          vrelel(vp, 1, 0);
 }  }
   
   static void
   vrele_thread(void *cookie)
   {
           vnode_t *vp;
   
           for (;;) {
                   mutex_enter(&vrele_lock);
                   while (TAILQ_EMPTY(&vrele_list)) {
                           cv_timedwait(&vrele_cv, &vrele_lock, hz);
                   }
                   vp = TAILQ_FIRST(&vrele_list);
                   TAILQ_REMOVE(&vrele_list, vp, v_freelist);
                   vrele_pending--;
                   mutex_exit(&vrele_lock);
   
                   /*
                    * If not the last reference, then ignore the vnode
                    * and look for more work.
                    */
                   mutex_enter(&vp->v_interlock);
                   KASSERT((vp->v_iflag & VI_INACTPEND) != 0);
                   vp->v_iflag &= ~VI_INACTPEND;
                   if (vp->v_usecount > 1) {
                           vp->v_usecount--;
                           mutex_exit(&vp->v_interlock);
                           continue;
                   }
   
                   /* Otherwise, release it. */
                   vrelenow(vp);
           }
   }
   
 /*  /*
  * Page or buffer structure gets a reference.   * Page or buffer structure gets a reference.
  * Called with v_interlock held.   * Called with v_interlock held.
Line 1070  vref(vnode_t *vp)
Line 1164  vref(vnode_t *vp)
                 vpanic(vp, "vref: usecount overflow");                  vpanic(vp, "vref: usecount overflow");
         }          }
         mutex_exit(&vp->v_interlock);          mutex_exit(&vp->v_interlock);
   
         KASSERT(vp->v_freelisthd == NULL);  
 }  }
   
 /*  /*
Line 1146  vflush(struct mount *mp, vnode_t *skipvp
Line 1238  vflush(struct mount *mp, vnode_t *skipvp
                         mutex_enter(&mntvnode_lock);                          mutex_enter(&mntvnode_lock);
                         continue;                          continue;
                 }                  }
                 KASSERT(vp->v_freelisthd == NULL);  
                 /*                  /*
                  * If FORCECLOSE is set, forcibly close the vnode.                   * If FORCECLOSE is set, forcibly close the vnode.
                  * For block or character devices, revert to an                   * For block or character devices, revert to an
Line 1190  vclean(vnode_t *vp, int flags)
Line 1281  vclean(vnode_t *vp, int flags)
 {  {
         lwp_t *l = curlwp;          lwp_t *l = curlwp;
         bool recycle, active;          bool recycle, active;
           struct specinfo *si;
   
         KASSERT(mutex_owned(&vp->v_interlock));          KASSERT(mutex_owned(&vp->v_interlock));
         KASSERT((vp->v_iflag & VI_MARKER) == 0);          KASSERT((vp->v_iflag & VI_MARKER) == 0);
         KASSERT(vp->v_usecount != 0);          KASSERT(vp->v_usecount != 0);
         KASSERT(vp->v_freelisthd == NULL);  
   
         /* If cleaning is already in progress wait until done and return. */          /* If cleaning is already in progress wait until done and return. */
         if (vp->v_iflag & VI_XLOCK) {          if (vp->v_iflag & VI_XLOCK) {
Line 1211  vclean(vnode_t *vp, int flags)
Line 1302  vclean(vnode_t *vp, int flags)
          * Prevent the vnode from being recycled or brought into use           * Prevent the vnode from being recycled or brought into use
          * while we clean it out.           * while we clean it out.
          */           */
         if (vp->v_iflag & VI_XLOCK) {  
                 vpanic(vp, "vclean: deadlock");  
         }  
         vp->v_iflag |= VI_XLOCK;          vp->v_iflag |= VI_XLOCK;
         if (vp->v_iflag & VI_EXECMAP) {          if (vp->v_iflag & VI_EXECMAP) {
                 atomic_add_int(&uvmexp.execpages, -vp->v_uobj.uo_npages);                  atomic_add_int(&uvmexp.execpages, -vp->v_uobj.uo_npages);
Line 1221  vclean(vnode_t *vp, int flags)
Line 1309  vclean(vnode_t *vp, int flags)
         }          }
         vp->v_iflag &= ~(VI_TEXT|VI_EXECMAP);          vp->v_iflag &= ~(VI_TEXT|VI_EXECMAP);
         active = (vp->v_usecount > 1);          active = (vp->v_usecount > 1);
           VOP_LOCK(vp, LK_EXCLUSIVE | LK_INTERLOCK);
         /*  
          * Even if the count is zero, the VOP_INACTIVE routine may still  
          * have the object locked while it cleans it out.  For  
          * active vnodes, it ensures that no other activity can  
          * occur while the underlying object is being cleaned out.  
          *  
          * We drain the lock to make sure we are the last one trying to  
          * get it and immediately resurrect the lock.  Future accesses  
          * for locking this _vnode_ will be protected by VXLOCK.  However,  
          * upper layers might be using the _lock_ in case the file system  
          * exported it and might access it while the vnode lingers in  
          * deadfs.  
          *  
          * XXXAD not true any more.  
          */  
         VOP_LOCK(vp, LK_DRAIN | LK_RESURRECT | LK_INTERLOCK);  
   
         /*          /*
          * Clean out any cached data associated with the vnode.           * Clean out any cached data associated with the vnode.
Line 1258  vclean(vnode_t *vp, int flags)
Line 1330  vclean(vnode_t *vp, int flags)
                         VOP_CLOSE(vp, FNONBLOCK, NOCRED);                          VOP_CLOSE(vp, FNONBLOCK, NOCRED);
   
                 if ((vp->v_type == VBLK || vp->v_type == VCHR) &&                  if ((vp->v_type == VBLK || vp->v_type == VCHR) &&
                     vp->v_specinfo != 0) {                      vp->v_specinfo != NULL) {
                         mutex_enter(&spechash_lock);                          mutex_enter(&spechash_lock);
                         if (vp->v_hashchain != NULL) {                          if (vp->v_hashchain != NULL) {
                                 if (*vp->v_hashchain == vp) {                                  if (*vp->v_hashchain == vp) {
Line 1292  vclean(vnode_t *vp, int flags)
Line 1364  vclean(vnode_t *vp, int flags)
                                         vp->v_iflag &= ~VI_ALIASED;                                          vp->v_iflag &= ~VI_ALIASED;
                                 }                                  }
                         }                          }
                         mutex_exit(&spechash_lock);                          si = vp->v_specinfo;
                         FREE(vp->v_specinfo, M_VNODE);  
                         vp->v_specinfo = NULL;                          vp->v_specinfo = NULL;
                           mutex_exit(&spechash_lock);
                           FREE(si, M_VNODE);
                 }                  }
         }          }
   
Line 1425  vcount(vnode_t *vp)
Line 1498  vcount(vnode_t *vp)
   
 loop:  loop:
         mutex_enter(&spechash_lock);          mutex_enter(&spechash_lock);
           mutex_enter(&vp->v_interlock);
         if ((vp->v_iflag & VI_ALIASED) == 0) {          if ((vp->v_iflag & VI_ALIASED) == 0) {
                   count = vp->v_usecount + ((vp->v_iflag & VI_INACTPEND) != 0);
                   mutex_exit(&vp->v_interlock);
                 mutex_exit(&spechash_lock);                  mutex_exit(&spechash_lock);
                 return (vp->v_usecount);                  return (count);
         }          }
           mutex_exit(&vp->v_interlock);
         for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) {          for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) {
                 vnext = vq->v_specnext;                  vnext = vq->v_specnext;
                 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)                  if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)

Legend:
Removed from v.1.308.2.2  
changed lines
  Added in v.1.308.2.3

CVSweb <webmaster@jp.NetBSD.org>