Fix races in ihashget that were introduced when I introduced the
authorMatthew Dillon <dillon@dragonflybsd.org>
Sat, 18 Oct 2003 20:15:10 +0000 (20:15 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Sat, 18 Oct 2003 20:15:10 +0000 (20:15 +0000)
lwkt_gettoken() API to interlock the vnode and hash table ops.

Report-by: David Rhodus.
sys/vfs/hpfs/hpfs_hash.c
sys/vfs/isofs/cd9660/cd9660_node.c
sys/vfs/msdosfs/msdosfs_denode.c
sys/vfs/ufs/ufs_ihash.c

index 7c67c2d..55260ad 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
  * $FreeBSD: src/sys/fs/hpfs/hpfs_hash.c,v 1.1 1999/12/09 19:09:58 semenu Exp $
- * $DragonFly: src/sys/vfs/hpfs/hpfs_hash.c,v 1.7 2003/08/15 07:26:15 dillon Exp $
+ * $DragonFly: src/sys/vfs/hpfs/hpfs_hash.c,v 1.8 2003/10/18 20:15:05 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -92,27 +92,6 @@ hpfs_hphashlookup(dev, ino)
        return (hp);
 }
 
-#if 0
-struct hpfsnode *
-hpfs_hphashget(dev, ino)
-       dev_t dev;
-       lsn_t ino;
-{
-       struct hpfsnode *hp;
-
-loop:
-       lwkt_gettoken(&hpfs_hphash_token);
-       for (hp = HPNOHASH(dev, ino)->lh_first; hp; hp = hp->h_hash.le_next) {
-               if (ino == hp->h_no && dev == hp->h_dev) {
-                       LOCKMGR(&hp->h_intlock, LK_EXCLUSIVE | LK_INTERLOCK, &hpfs_hphash_token, NULL);
-                       return (hp);
-               }
-       }
-       lwkt_reltoken(&hpfs_hphash_token);
-       return (hp);
-}
-#endif
-
 struct vnode *
 hpfs_hphashvget(dev, ino, td)
        dev_t dev;
@@ -135,7 +114,11 @@ loop:
                                gen = lwkt_regettoken(&hpfs_hphash_token);
                                goto loop;
                        }
-                       lwkt_reltoken(&hpfs_hphash_token);
+                       if (lwkt_reltoken(&hpfs_hphash_token) != gen) {
+                               vput(vp);
+                               gen = lwkt_gettoken(&hpfs_hphash_token);
+                               goto loop;
+                       }
                        return (vp);
                }
        }
index 9dc2ed5..5b93e97 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)cd9660_node.c       8.2 (Berkeley) 1/23/94
  * $FreeBSD: src/sys/isofs/cd9660/cd9660_node.c,v 1.29.2.1 2000/07/08 14:35:56 bp Exp $
- * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.c,v 1.7 2003/08/20 09:56:32 rob Exp $
+ * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_node.c,v 1.8 2003/10/18 20:15:06 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -102,16 +102,27 @@ cd9660_ihashget(dev, inum)
        struct thread *td = curthread;          /* XXX */
        struct iso_node *ip;
        struct vnode *vp;
+       int gen;
 
+       gen = lwkt_gettoken(&cd9660_ihash_token);
 loop:
-       lwkt_gettoken(&cd9660_ihash_token);
        for (ip = isohashtbl[INOHASH(dev, inum)]; ip; ip = ip->i_next) {
                if (inum == ip->i_number && dev == ip->i_dev) {
                        vp = ITOV(ip);
                        lwkt_gettoken(&vp->v_interlock); /* YYY */
-                       lwkt_reltoken(&cd9660_ihash_token);
-                       if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td))
+                       if (lwkt_gentoken(&cd9660_ihash_token, &gen) != 0) {
+                               lwkt_reltoken(&vp->v_interlock);
+                               goto loop;
+                       }
+                       if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
+                               lwkt_gentoken(&cd9660_ihash_token, &gen);
+                               goto loop;
+                       }
+                       if (lwkt_reltoken(&cd9660_ihash_token) != gen) {
+                               vput(vp);
+                               gen = lwkt_gettoken(&cd9660_ihash_token);
                                goto loop;
+                       }
                        return (vp);
                }
        }
index 45c4f2c..b4e7c43 100644 (file)
@@ -1,5 +1,5 @@
 /* $FreeBSD: src/sys/msdosfs/msdosfs_denode.c,v 1.47.2.3 2002/08/22 16:20:15 trhodes Exp $ */
-/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_denode.c,v 1.8 2003/08/20 09:56:32 rob Exp $ */
+/* $DragonFly: src/sys/vfs/msdosfs/msdosfs_denode.c,v 1.9 2003/10/18 20:15:08 dillon Exp $ */
 /*     $NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $  */
 
 /*-
@@ -127,9 +127,10 @@ msdosfs_hashget(dev, dirclust, diroff)
        struct thread *td = curthread;  /* XXX */
        struct denode *dep;
        struct vnode *vp;
+       int gen;
 
+       gen = lwkt_gettoken(&dehash_token);
 loop:
-       lwkt_gettoken(&dehash_token);
        for (dep = DEHASH(dev, dirclust, diroff); dep; dep = dep->de_next) {
                if (dirclust == dep->de_dirclust
                    && diroff == dep->de_diroffset
@@ -137,9 +138,19 @@ loop:
                    && dep->de_refcnt != 0) {
                        vp = DETOV(dep);
                        lwkt_gettoken(&vp->v_interlock);
-                       lwkt_reltoken(&dehash_token);
-                       if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td))
+                       if (lwkt_gentoken(&dehash_token, &gen) != 0) {
+                               lwkt_reltoken(&vp->v_interlock);
+                               goto loop;
+                       }
+                       if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) {
+                               lwkt_gentoken(&dehash_token, &gen);
+                               goto loop;
+                       }
+                       if (lwkt_reltoken(&dehash_token) != gen) {
+                               vput(vp);
+                               gen = lwkt_gettoken(&dehash_token);
                                goto loop;
+                       }
                        return (dep);
                }
        }
index ff7ad7c..dc8334e 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_ihash.c,v 1.20 1999/08/28 00:52:29 peter Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_ihash.c,v 1.6 2003/08/07 21:17:44 dillon Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_ihash.c,v 1.7 2003/10/18 20:15:10 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -91,6 +91,14 @@ ufs_ihashlookup(dev, inum)
 /*
  * Use the device/inum pair to find the incore inode, and return a pointer
  * to it. If it is in core, but locked, wait for it.
+ *
+ * Any time we potentially block we must regenerate the token using 
+ * lwkt_gentoken(), which at the same time checks the generation number
+ * indicating whether another entity stole the token while we were blocked.
+ * In the best case lwkt_gentoken().   The code below is probably overkill,
+ * but it is particularly important to check the generation number after
+ * acquiring the vnode lock to ensure that the inode association is still
+ * valid.
  */
 struct vnode *
 ufs_ihashget(dev_t dev, ino_t inum)
@@ -99,14 +107,13 @@ ufs_ihashget(dev_t dev, ino_t inum)
        struct inode *ip;
        struct vnode *vp;
        int gen;
-       int vgen;
 
        gen = lwkt_gettoken(&ufs_ihash_token);
 loop:
        for (ip = INOHASH(dev, inum)->lh_first; ip; ip = ip->i_hash.le_next) {
                if (inum == ip->i_number && dev == ip->i_dev) {
                        vp = ITOV(ip);
-                       vgen = lwkt_gettoken(&vp->v_interlock);
+                       lwkt_gettoken(&vp->v_interlock);
                        if (lwkt_gentoken(&ufs_ihash_token, &gen) != 0) {
                                lwkt_reltoken(&vp->v_interlock);
                                goto loop;
@@ -115,7 +122,11 @@ loop:
                                lwkt_gentoken(&ufs_ihash_token, &gen);
                                goto loop;
                        }
-                       lwkt_reltoken(&ufs_ihash_token);
+                       if (lwkt_reltoken(&ufs_ihash_token) != gen) {
+                               vput(vp);
+                               gen = lwkt_gettoken(&ufs_ihash_token);
+                               goto loop;
+                       }
                        return (vp);
                }
        }