Author: kib
Date: Thu Jan 29 11:03:57 2009
New Revision: 187887
URL: http://svn.freebsd.org/changeset/base/187887

Log:
  MFC r186560:
  After the pfs_vncache_mutex is dropped, another thread may attempt to
  do pfs_vncache_alloc() for the same pfs_node and pid. In this case, we
  could end up with two vnodes for the pair. Recheck the cache under the
  locked pfs_vncache_mutex after all sleeping operations are done.
  
  Do not call free() on the struct pfs_vdata after insmntque() failure,
  because vp->v_data points to the structure, and pseudofs_reclaim()
  frees it by the call to pfs_vncache_free().
  
  MFC r186981 (by marcus):
  vput the vnode.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/fs/pseudofs/pseudofs_vncache.c

Modified: stable/7/sys/fs/pseudofs/pseudofs_vncache.c
==============================================================================
--- stable/7/sys/fs/pseudofs/pseudofs_vncache.c Thu Jan 29 10:49:21 2009        
(r187886)
+++ stable/7/sys/fs/pseudofs/pseudofs_vncache.c Thu Jan 29 11:03:57 2009        
(r187887)
@@ -111,7 +111,7 @@ int
 pfs_vncache_alloc(struct mount *mp, struct vnode **vpp,
                  struct pfs_node *pn, pid_t pid)
 {
-       struct pfs_vdata *pvd;
+       struct pfs_vdata *pvd, *pvd2;
        struct vnode *vp;
        int error;
 
@@ -146,19 +146,11 @@ retry:
                }
        }
        mtx_unlock(&pfs_vncache_mutex);
-       ++pfs_vncache_misses;
 
        /* nope, get a new one */
        MALLOC(pvd, struct pfs_vdata *, sizeof *pvd, M_PFSVNCACHE, M_WAITOK);
-       mtx_lock(&pfs_vncache_mutex);
-       if (++pfs_vncache_entries > pfs_vncache_maxentries)
-               pfs_vncache_maxentries = pfs_vncache_entries;
-       mtx_unlock(&pfs_vncache_mutex);
        error = getnewvnode("pseudofs", mp, &pfs_vnodeops, vpp);
        if (error) {
-               mtx_lock(&pfs_vncache_mutex);
-               --pfs_vncache_entries;
-               mtx_unlock(&pfs_vncache_mutex);
                FREE(pvd, M_PFSVNCACHE);
                return (error);
        }
@@ -200,14 +192,36 @@ retry:
        vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curthread);
        error = insmntque(*vpp, mp);
        if (error != 0) {
-               mtx_lock(&pfs_vncache_mutex);
-               --pfs_vncache_entries;
-               mtx_unlock(&pfs_vncache_mutex);
-               FREE(pvd, M_PFSVNCACHE);
                *vpp = NULLVP;
                return (error);
        }
+retry2:
        mtx_lock(&pfs_vncache_mutex);
+       /*
+        * Other thread may race with us, creating the entry we are
+        * going to insert into the cache. Recheck after
+        * pfs_vncache_mutex is reacquired.
+        */
+       for (pvd2 = pfs_vncache; pvd2; pvd2 = pvd2->pvd_next) {
+               if (pvd2->pvd_pn == pn && pvd2->pvd_pid == pid &&
+                   pvd2->pvd_vnode->v_mount == mp) {
+                       vp = pvd2->pvd_vnode;
+                       VI_LOCK(vp);
+                       mtx_unlock(&pfs_vncache_mutex);
+                       if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, curthread) == 
0) {
+                               ++pfs_vncache_hits;
+                               vgone(*vpp);
+                               vput(*vpp);
+                               *vpp = vp;
+                               cache_purge(vp);
+                               return (0);
+                       }
+                       goto retry2;
+               }
+       }
+       ++pfs_vncache_misses;
+       if (++pfs_vncache_entries > pfs_vncache_maxentries)
+               pfs_vncache_maxentries = pfs_vncache_entries;
        pvd->pvd_prev = NULL;
        pvd->pvd_next = pfs_vncache;
        if (pvd->pvd_next)
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to