Module Name:    src
Committed By:   hannken
Date:           Tue Jul  8 09:21:52 UTC 2014

Modified Files:
        src/sys/fs/msdosfs: denode.h msdosfs_denode.c msdosfs_lookup.c
            msdosfs_vfsops.c msdosfs_vnops.c msdosfsmount.h

Log Message:
Change msdosfs from hashlist to vcache:
- Use (dir_cluster, dir_offset, dir_generation) as key, where
  dir_generation is non-zero and unique for unlinked but open nodes.
- Change deget() to return a vnode as it is unsafe to return a
  referenced but unlocked denode.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/fs/msdosfs/denode.h
cvs rdiff -u -r1.49 -r1.50 src/sys/fs/msdosfs/msdosfs_denode.c
cvs rdiff -u -r1.32 -r1.33 src/sys/fs/msdosfs/msdosfs_lookup.c
cvs rdiff -u -r1.108 -r1.109 src/sys/fs/msdosfs/msdosfs_vfsops.c
cvs rdiff -u -r1.89 -r1.90 src/sys/fs/msdosfs/msdosfs_vnops.c
cvs rdiff -u -r1.19 -r1.20 src/sys/fs/msdosfs/msdosfsmount.h

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

Modified files:

Index: src/sys/fs/msdosfs/denode.h
diff -u src/sys/fs/msdosfs/denode.h:1.23 src/sys/fs/msdosfs/denode.h:1.24
--- src/sys/fs/msdosfs/denode.h:1.23	Sat Jan 26 19:45:02 2013
+++ src/sys/fs/msdosfs/denode.h	Tue Jul  8 09:21:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: denode.h,v 1.23 2013/01/26 19:45:02 christos Exp $	*/
+/*	$NetBSD: denode.h,v 1.24 2014/07/08 09:21:52 hannken Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -153,15 +153,21 @@ struct fatcache {
  * This is the in memory variant of a dos directory entry.  It is usually
  * contained within a vnode.
  */
+struct denode_key {
+	u_long dk_dirclust;	/* cluster of the directory file containing this entry */
+	u_long dk_diroffset;	/* offset of this entry in the directory cluster */
+	void *dk_dirgen;	/* non zero and unique for unlinked nodes */
+};
 struct denode {
 	struct genfs_node de_gnode;
-	LIST_ENTRY(denode) de_hash;
 	struct vnode *de_vnode;	/* addr of vnode we are part of */
 	struct vnode *de_devvp;	/* vnode of blk dev we live on */
 	u_long de_flag;		/* flag bits */
 	dev_t de_dev;		/* device where direntry lives */
-	u_long de_dirclust;	/* cluster of the directory file containing this entry */
-	u_long de_diroffset;	/* offset of this entry in the directory cluster */
+	struct denode_key de_key;
+#define de_dirclust de_key.dk_dirclust
+#define de_diroffset de_key.dk_diroffset
+#define de_dirgen de_key.dk_dirgen
 	u_long de_fndoffset;	/* offset of found dir entry */
 	int de_fndcnt;		/* number of slots before de_fndoffset */
 	long de_refcnt;		/* reference count */
@@ -303,7 +309,11 @@ int msdosfs_update(struct vnode *, const
 int createde(struct denode *, struct denode *,
 		struct denode **, struct componentname *);
 int deextend(struct denode *, u_long, struct kauth_cred *);
+#ifdef MAKEFS
 int deget(struct msdosfsmount *, u_long, u_long, struct denode **);
+#else
+int deget(struct msdosfsmount *, u_long, u_long, struct vnode **);
+#endif
 int detrunc(struct denode *, u_long, int, struct kauth_cred *);
 int deupdat(struct denode *, int);
 int doscheckpath(struct denode *, struct denode *);
@@ -311,7 +321,6 @@ int dosdirempty(struct denode *);
 int readde(struct denode *, struct buf **, struct direntry **);
 int readep(struct msdosfsmount *, u_long, u_long,
 		struct buf **, struct direntry **);
-void reinsert(struct denode *);
 int removede(struct denode *, struct denode *);
 int uniqdosname(struct denode *, struct componentname *, u_char *);
 int findwin95(struct denode *);

Index: src/sys/fs/msdosfs/msdosfs_denode.c
diff -u src/sys/fs/msdosfs/msdosfs_denode.c:1.49 src/sys/fs/msdosfs/msdosfs_denode.c:1.50
--- src/sys/fs/msdosfs/msdosfs_denode.c:1.49	Fri May 30 08:42:35 2014
+++ src/sys/fs/msdosfs/msdosfs_denode.c	Tue Jul  8 09:21:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdosfs_denode.c,v 1.49 2014/05/30 08:42:35 hannken Exp $	*/
+/*	$NetBSD: msdosfs_denode.c,v 1.50 2014/07/08 09:21:52 hannken Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: msdosfs_denode.c,v 1.49 2014/05/30 08:42:35 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_denode.c,v 1.50 2014/07/08 09:21:52 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -72,14 +72,6 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_deno
 #include <fs/msdosfs/denode.h>
 #include <fs/msdosfs/fat.h>
 
-LIST_HEAD(ihashhead, denode) *dehashtbl;
-u_long dehash;			/* size of hash table - 1 */
-#define	DEHASH(dev, dcl, doff) \
-    (((dev) + (dcl) + (doff) / sizeof(struct direntry)) & dehash)
-
-kmutex_t msdosfs_ihash_lock;
-kmutex_t msdosfs_hashlock;
-
 struct pool msdosfs_denode_pool;
 
 extern int prtactive;
@@ -138,10 +130,6 @@ static const struct genfs_ops msdosfs_ge
 	.gop_markupdate = msdosfs_gop_markupdate,
 };
 
-static struct denode *msdosfs_hashget(dev_t, u_long, u_long, int);
-static void msdosfs_hashins(struct denode *);
-static void msdosfs_hashrem(struct denode *);
-
 MALLOC_DECLARE(M_MSDOSFSFAT);
 
 void
@@ -155,112 +143,33 @@ msdosfs_init(void)
 	    "msdosnopl", &pool_allocator_nointr, IPL_NONE);
 	pool_init(&fh_pool, sizeof(struct fh_node), 0, 0, 0,
 	    "msdosfhpl", &pool_allocator_nointr, IPL_NONE);
-	dehashtbl = hashinit(desiredvnodes / 2, HASH_LIST, true, &dehash);
 	rb_tree_init(&fh_rbtree, &fh_rbtree_ops);
-	mutex_init(&msdosfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE);
 	mutex_init(&fh_lock, MUTEX_DEFAULT, IPL_NONE);
-	mutex_init(&msdosfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
 }
 
 /*
- * Reinitialize inode hash table.
+ * Reinitialize.
  */
 
 void
 msdosfs_reinit(void)
 {
-	struct denode *dep;
-	struct ihashhead *oldhash, *hash;
-	u_long oldmask, mask, val;
-	int i;
-
-	hash = hashinit(desiredvnodes / 2, HASH_LIST, true, &mask);
-
-	mutex_enter(&msdosfs_ihash_lock);
-	oldhash = dehashtbl;
-	oldmask = dehash;
-	dehashtbl = hash;
-	dehash = mask;
-	for (i = 0; i <= oldmask; i++) {
-		while ((dep = LIST_FIRST(&oldhash[i])) != NULL) {
-			LIST_REMOVE(dep, de_hash);
-			val = DEHASH(dep->de_dev, dep->de_dirclust,
-			    dep->de_diroffset);
-			LIST_INSERT_HEAD(&hash[val], dep, de_hash);
-		}
-	}
-	mutex_exit(&msdosfs_ihash_lock);
-	hashdone(oldhash, HASH_LIST, oldmask);
+
 }
 
 void
 msdosfs_done(void)
 {
-	hashdone(dehashtbl, HASH_LIST, dehash);
 	pool_destroy(&msdosfs_denode_pool);
 	pool_destroy(&fh_pool);
-	mutex_destroy(&msdosfs_ihash_lock);
 	mutex_destroy(&fh_lock);
-	mutex_destroy(&msdosfs_hashlock);
 	malloc_type_detach(M_MSDOSFSTMP);
 	malloc_type_detach(M_MSDOSFSFAT);
 	malloc_type_detach(M_MSDOSFSMNT);
 }
 
-static struct denode *
-msdosfs_hashget(dev_t dev, u_long dirclust, u_long diroff, int flags)
-{
-	struct denode *dep;
-	struct vnode *vp;
-
-loop:
-	mutex_enter(&msdosfs_ihash_lock);
-	LIST_FOREACH(dep, &dehashtbl[DEHASH(dev, dirclust, diroff)], de_hash) {
-		if (dirclust == dep->de_dirclust &&
-		    diroff == dep->de_diroffset &&
-		    dev == dep->de_dev &&
-		    dep->de_refcnt != 0) {
-			vp = DETOV(dep);
-			if (flags == 0) {
-				mutex_exit(&msdosfs_ihash_lock);
-			} else {
-				mutex_enter(vp->v_interlock);
-				mutex_exit(&msdosfs_ihash_lock);
-				if (vget(vp, flags))
-					goto loop;
-			}
-			return (dep);
-		}
-	}
-	mutex_exit(&msdosfs_ihash_lock);
-	return (NULL);
-}
-
-static void
-msdosfs_hashins(struct denode *dep)
-{
-	struct ihashhead *depp;
-	int val;
-
-	KASSERT(mutex_owned(&msdosfs_hashlock));
-
-	mutex_enter(&msdosfs_ihash_lock);
-	val = DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
-	depp = &dehashtbl[val];
-	LIST_INSERT_HEAD(depp, dep, de_hash);
-	mutex_exit(&msdosfs_ihash_lock);
-}
-
-static void
-msdosfs_hashrem(struct denode *dep)
-{
-	mutex_enter(&msdosfs_ihash_lock);
-	LIST_REMOVE(dep, de_hash);
-	mutex_exit(&msdosfs_ihash_lock);
-}
-
 /*
- * If deget() succeeds it returns with the gotten denode locked().
+ * If deget() succeeds it returns with the gotten denode unlocked.
  *
  * pmp	     - address of msdosfsmount structure of the filesystem containing
  *	       the denode of interest.  The pm_dev field and the address of
@@ -269,26 +178,18 @@ msdosfs_hashrem(struct denode *dep)
  *	       diroffset is relative to the beginning of the root directory,
  *	       otherwise it is cluster relative.
  * diroffset - offset past begin of cluster of denode we want
- * depp	     - returns the address of the gotten denode.
+ * vpp	     - returns the address of the gotten vnode.
  */
 int
-deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct denode **depp)
+deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
+    struct vnode **vpp)
 	/* pmp:	 so we know the maj/min number */
 	/* dirclust:		 cluster this dir entry came from */
 	/* diroffset:		 index of entry within the cluster */
-	/* depp:		 returns the addr of the gotten denode */
+	/* vpp:			 returns the addr of the gotten vnode */
 {
 	int error;
-	extern int (**msdosfs_vnodeop_p)(void *);
-	struct direntry *direntptr;
-	struct denode *ldep;
-	struct vnode *nvp;
-	struct buf *bp;
-
-#ifdef MSDOSFS_DEBUG
-	printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
-	    pmp, dirclust, diroffset, depp);
-#endif
+	struct denode_key key;
 
 	/*
 	 * On FAT32 filesystems, root is a (more or less) normal
@@ -297,78 +198,59 @@ deget(struct msdosfsmount *pmp, u_long d
 	if (FAT32(pmp) && dirclust == MSDOSFSROOT)
 		dirclust = pmp->pm_rootdirblk;
 
-	/*
-	 * See if the denode is in the denode cache. Use the location of
-	 * the directory entry to compute the hash value. For subdir use
-	 * address of "." entry. For root dir (if not FAT32) use cluster
-	 * MSDOSFSROOT, offset MSDOSFSROOT_OFS
-	 *
-	 * NOTE: The check for de_refcnt > 0 below insures the denode being
-	 * examined does not represent an unlinked but still open file.
-	 * These files are not to be accessible even when the directory
-	 * entry that represented the file happens to be reused while the
-	 * deleted file is still open.
-	 */
- retry:
-	ldep = msdosfs_hashget(pmp->pm_dev, dirclust, diroffset, LK_EXCLUSIVE);
-	if (ldep) {
-		*depp = ldep;
-		return (0);
-	}
+	memset(&key, 0, sizeof(key));
+	key.dk_dirclust = dirclust;
+	key.dk_diroffset = diroffset;
+	/* key.dk_dirgen = NULL; */
 
-	/*
-	 * Directory entry was not in cache, have to create a vnode and
-	 * copy it from the passed disk buffer.
-	 */
-	error = getnewvnode(VT_MSDOSFS, pmp->pm_mountp, msdosfs_vnodeop_p,
-	    NULL, &nvp);
-	if (error) {
-		*depp = 0;
-		return (error);
-	}
-	ldep = pool_get(&msdosfs_denode_pool, PR_WAITOK);
+	error = vcache_get(pmp->pm_mountp, &key, sizeof(key), vpp);
+	return error;
+}
 
-	/*
-	 * If someone beat us to it, put back the freshly allocated
-	 * vnode/inode pair and retry.
-	 */
-	mutex_enter(&msdosfs_hashlock);
-	if (msdosfs_hashget(pmp->pm_dev, dirclust, diroffset, 0)) {
-		mutex_exit(&msdosfs_hashlock);
-		ungetnewvnode(nvp);
-		pool_put(&msdosfs_denode_pool, ldep);
-		goto retry;
-	}
-	memset(ldep, 0, sizeof *ldep);
-	nvp->v_data = ldep;
-	ldep->de_vnode = nvp;
-	ldep->de_flag = 0;
-	ldep->de_devvp = 0;
-	ldep->de_lockf = 0;
-	ldep->de_dev = pmp->pm_dev;
-	ldep->de_dirclust = dirclust;
-	ldep->de_diroffset = diroffset;
-	fc_purge(ldep, 0);	/* init the FAT cache for this denode */
+int
+msdosfs_loadvnode(struct mount *mp, struct vnode *vp,
+    const void *key, size_t key_len, const void **new_key)
+{
+	bool is_root;
+	int error;
+	extern int (**msdosfs_vnodeop_p)(void *);
+	struct msdosfsmount *pmp;
+	struct direntry *direntptr;
+	struct denode *ldep;
+	struct buf *bp;
+	struct denode_key dkey;
 
-	/*
-	 * Insert the denode into the hash queue and lock the denode so it
-	 * can't be accessed until we've read it in and have done what we
-	 * need to it.
-	 */
-	vn_lock(nvp, LK_EXCLUSIVE | LK_RETRY);
-	genfs_node_init(nvp, &msdosfs_genfsops);
-	msdosfs_hashins(ldep);
-	mutex_exit(&msdosfs_hashlock);
+	KASSERT(key_len == sizeof(dkey));
+	memcpy(&dkey, key, key_len);
+	KASSERT(dkey.dk_dirgen == NULL);
+
+	pmp = VFSTOMSDOSFS(mp);
+	is_root = ((dkey.dk_dirclust == MSDOSFSROOT ||
+	    (FAT32(pmp) && dkey.dk_dirclust == pmp->pm_rootdirblk)) &&
+	    dkey.dk_diroffset == MSDOSFSROOT_OFS);
 
+#ifdef MSDOSFS_DEBUG
+	printf("loadvnode(pmp %p, dirclust %lu, diroffset %lx, vp %p)\n",
+	    pmp, dkey.dk_dirclust, dkey.dk_diroffset, vp);
+#endif
+
+	ldep = pool_get(&msdosfs_denode_pool, PR_WAITOK);
+	memset(ldep, 0, sizeof *ldep);
+	/* ldep->de_flag = 0; */
+	/* ldep->de_devvp = 0; */
+	/* ldep->de_lockf = 0; */
+	ldep->de_dev = pmp->pm_dev;
+	ldep->de_dirclust = dkey.dk_dirclust;
+	ldep->de_diroffset = dkey.dk_diroffset;
 	ldep->de_pmp = pmp;
 	ldep->de_devvp = pmp->pm_devvp;
 	ldep->de_refcnt = 1;
+	fc_purge(ldep, 0);	/* init the FAT cache for this denode */
+
 	/*
 	 * Copy the directory entry into the denode area of the vnode.
 	 */
-	if ((dirclust == MSDOSFSROOT
-	     || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
-	    && diroffset == MSDOSFSROOT_OFS) {
+	if (is_root) {
 		/*
 		 * Directory entry for the root directory. There isn't one,
 		 * so we manufacture one. We should probably rummage
@@ -376,15 +258,14 @@ deget(struct msdosfsmount *pmp, u_long d
 		 * exists), and then use the time and date from that entry
 		 * as the time and date for the root denode.
 		 */
-		nvp->v_vflag |= VV_ROOT; /* should be further down XXX */
-
 		ldep->de_Attributes = ATTR_DIRECTORY;
 		if (FAT32(pmp))
 			ldep->de_StartCluster = pmp->pm_rootdirblk;
 			/* de_FileSize will be filled in further down */
 		else {
 			ldep->de_StartCluster = MSDOSFSROOT;
-			ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec;
+			ldep->de_FileSize = pmp->pm_rootdirsize *
+			    pmp->pm_BytesPerSec;
 		}
 		/*
 		 * fill in time and date so that dos2unixtime() doesn't
@@ -401,12 +282,11 @@ deget(struct msdosfsmount *pmp, u_long d
 		ldep->de_MDate = ldep->de_CDate;
 		/* leave the other fields as garbage */
 	} else {
-		error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
+		error = readep(pmp, ldep->de_dirclust, ldep->de_diroffset,
+		    &bp, &direntptr);
 		if (error) {
-			ldep->de_devvp = NULL;
-			ldep->de_Name[0] = SLOT_DELETED;
-			vput(nvp);
-			return (error);
+			pool_put(&msdosfs_denode_pool, ldep);
+			return error;
 		}
 		DE_INTERNALIZE(ldep, direntptr);
 		brelse(bp, 0);
@@ -414,7 +294,7 @@ deget(struct msdosfsmount *pmp, u_long d
 
 	/*
 	 * Fill in a few fields of the vnode and finish filling in the
-	 * denode.  Then return the address of the found denode.
+	 * denode.
 	 */
 	if (ldep->de_Attributes & ATTR_DIRECTORY) {
 		/*
@@ -425,21 +305,30 @@ deget(struct msdosfsmount *pmp, u_long d
 		 */
 		u_long size;
 
-		nvp->v_type = VDIR;
+		vp->v_type = VDIR;
 		if (ldep->de_StartCluster != MSDOSFSROOT) {
 			error = pcbmap(ldep, CLUST_END, 0, &size, 0);
 			if (error == E2BIG) {
 				ldep->de_FileSize = de_cn2off(pmp, size);
 				error = 0;
 			} else
-				printf("deget(): pcbmap returned %d\n", error);
+				printf("loadvnode(): pcbmap returned %d\n",
+				    error);
 		}
 	} else
-		nvp->v_type = VREG;
+		vp->v_type = VREG;
 	vref(ldep->de_devvp);
-	*depp = ldep;
-	uvm_vnp_setsize(nvp, ldep->de_FileSize);
-	return (0);
+	if (is_root)
+		vp->v_vflag |= VV_ROOT;
+	vp->v_tag = VT_MSDOSFS;
+	vp->v_op = msdosfs_vnodeop_p;
+	vp->v_data = ldep;
+	ldep->de_vnode = vp;
+	genfs_node_init(vp, &msdosfs_genfsops);
+	uvm_vnp_setsize(vp, ldep->de_FileSize);
+	*new_key = &ldep->de_key;
+
+	return 0;
 }
 
 int
@@ -641,29 +530,6 @@ deextend(struct denode *dep, u_long leng
 	return (deupdat(dep, 1));
 }
 
-/*
- * Move a denode to its correct hash queue after the file it represents has
- * been moved to a new directory.
- */
-void
-reinsert(struct denode *dep)
-{
-	/*
-	 * Fix up the denode cache.  If the denode is for a directory,
-	 * there is nothing to do since the hash is based on the starting
-	 * cluster of the directory file and that hasn't changed.  If for a
-	 * file the hash is based on the location of the directory entry,
-	 * so we must remove it from the cache and re-enter it with the
-	 * hash based on the new location of the directory entry.
-	 */
-	if (dep->de_Attributes & ATTR_DIRECTORY)
-		return;
-	mutex_enter(&msdosfs_hashlock);
-	msdosfs_hashrem(dep);
-	msdosfs_hashins(dep);
-	mutex_exit(&msdosfs_hashlock);
-}
-
 int
 msdosfs_reclaim(void *v)
 {
@@ -683,9 +549,9 @@ msdosfs_reclaim(void *v)
 	if (prtactive && vp->v_usecount > 1)
 		vprint("msdosfs_reclaim(): pushing active", vp);
 	/*
-	 * Remove the denode from its hash chain.
+	 * Remove the denode from the vnode cache.
 	 */
-	msdosfs_hashrem(dep);
+	vcache_remove(vp->v_mount, &dep->de_key, sizeof(dep->de_key));
 	/*
 	 * Purge old data structures associated with the denode.
 	 */

Index: src/sys/fs/msdosfs/msdosfs_lookup.c
diff -u src/sys/fs/msdosfs/msdosfs_lookup.c:1.32 src/sys/fs/msdosfs/msdosfs_lookup.c:1.33
--- src/sys/fs/msdosfs/msdosfs_lookup.c:1.32	Fri Feb  7 15:29:21 2014
+++ src/sys/fs/msdosfs/msdosfs_lookup.c	Tue Jul  8 09:21:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdosfs_lookup.c,v 1.32 2014/02/07 15:29:21 hannken Exp $	*/
+/*	$NetBSD: msdosfs_lookup.c,v 1.33 2014/07/08 09:21:52 hannken Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -52,7 +52,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: msdosfs_lookup.c,v 1.32 2014/02/07 15:29:21 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_lookup.c,v 1.33 2014/07/08 09:21:52 hannken Exp $");
 
 #include <sys/param.h>
 
@@ -64,6 +64,7 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_look
 #include <sys/dirent.h>
 #include <sys/buf.h>
 #include <sys/vnode.h>
+#include <sys/atomic.h>
 #else
 #include <ffs/buf.h>
 #endif /* _KERNEL */
@@ -113,9 +114,7 @@ msdosfs_lookup(void *v)
 	int blsize;
 	int isadir;		/* ~0 if found direntry is a directory	 */
 	u_long scn;		/* starting cluster number		 */
-	struct vnode *pdp;
 	struct denode *dp;
-	struct denode *tdp;
 	struct msdosfsmount *pmp;
 	struct buf *bp = 0;
 	struct direntry *dep;
@@ -217,7 +216,7 @@ msdosfs_lookup(void *v)
 	 * Search the directory pointed at by vdp for the name pointed at
 	 * by cnp->cn_nameptr.
 	 */
-	tdp = NULL;
+
 	/*
 	 * The outer loop ranges over the clusters that make up the
 	 * directory.  Note that the root directory is different from all
@@ -491,11 +490,8 @@ foundroot:
 			*vpp = vdp;
 			return (0);
 		}
-		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
-			return (error);
-		*vpp = DETOV(tdp);
-		VOP_UNLOCK(*vpp);
-		return (0);
+		error = deget(pmp, cluster, blkoff, vpp);
+		return error;
 	}
 
 	/*
@@ -523,48 +519,15 @@ foundroot:
 		if (dp->de_StartCluster == scn && isadir)
 			return (EISDIR);
 
-		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
-			return (error);
-		*vpp = DETOV(tdp);
-		VOP_UNLOCK(*vpp);
-		return (0);
+		error = deget(pmp, cluster, blkoff, vpp);
+		return error;
 	}
 
-	/*
-	 * Step through the translation in the name.  We do not `vput' the
-	 * directory because we may need it again if a symbolic link
-	 * is relative to the current directory.  Instead we save it
-	 * unlocked as "pdp".  We must get the target inode before unlocking
-	 * the directory to insure that the inode will not be removed
-	 * before we get it.  We prevent deadlock by always fetching
-	 * inodes from the root, moving down the directory tree. Thus
-	 * when following backward pointers ".." we must unlock the
-	 * parent directory before getting the requested directory.
-	 * There is a potential race condition here if both the current
-	 * and parent directories are removed before the VFS_VGET for the
-	 * inode associated with ".." returns.  We hope that this occurs
-	 * infrequently since we cannot avoid this race condition without
-	 * implementing a sophisticated deadlock detection algorithm.
-	 * Note also that this simple deadlock detection scheme will not
-	 * work if the file system has any hard links other than ".."
-	 * that point backwards in the directory structure.
-	 */
-	pdp = vdp;
-	if (flags & ISDOTDOT) {
-		VOP_UNLOCK(pdp);	/* race to get the inode */
-		error = deget(pmp, cluster, blkoff, &tdp);
-		vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
-		if (error) {
-			return error;
-		}
-		*vpp = DETOV(tdp);
-	} else if (dp->de_StartCluster == scn && isadir) {
+	if (dp->de_StartCluster == scn && isadir) {
 		vref(vdp);	/* we want ourself, ie "." */
 		*vpp = vdp;
-	} else {
-		if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
-			return (error);
-		*vpp = DETOV(tdp);
+	} else if ((error = deget(pmp, cluster, blkoff, vpp)) != 0) {
+		return error;
 	}
 
 	/*
@@ -572,9 +535,6 @@ foundroot:
 	 */
 	cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags);
 
-	if (*vpp != vdp)
-		VOP_UNLOCK(*vpp);
-
 	return 0;
 }
 #endif /* _KERNEL */
@@ -707,6 +667,7 @@ createde(struct denode *dep, struct deno
 	 */
 	if (depp) {
 		u_long diroffset = clusoffset;
+
 		if (dep->de_Attributes & ATTR_DIRECTORY) {
 			dirclust = dep->de_StartCluster;
 			if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
@@ -716,10 +677,16 @@ createde(struct denode *dep, struct deno
 			else
 				diroffset = 0;
 		}
+#ifdef MAKEFS
 		error = deget(pmp, dirclust, diroffset, depp);
-#ifndef MAKEFS
+#else
+		struct vnode *vp;
+
+		error = deget(pmp, dirclust, diroffset, &vp);
 		if (error == 0)
-			VOP_UNLOCK(DETOV(*depp));
+			*depp = VTODE(vp);
+		else
+			*depp = NULL;
 #endif
 		return error;
 	}
@@ -935,9 +902,24 @@ doscheckpath(struct denode *source, stru
 		vput(DETOV(dep));
 		brelse(bp, 0);
 		bp = NULL;
+#ifdef MAKEFS
 		/* NOTE: deget() clears dep on error */
 		if ((error = deget(pmp, scn, 0, &dep)) != 0)
 			break;
+#else
+		struct vnode *vp;
+
+		dep = NULL;
+		error = deget(pmp, scn, 0, &vp);
+		if (error)
+			break;
+		error = vn_lock(vp, LK_EXCLUSIVE);
+		if (error) {
+			vrele(vp);
+			break;
+		}
+		dep = VTODE(vp);
+#endif
 	}
 out:
 	if (bp)
@@ -1019,7 +1001,20 @@ removede(struct denode *pdep, struct den
 	    dep->de_Name, dep, offset);
 #endif
 
-	dep->de_refcnt--;
+	if (--dep->de_refcnt == 0) {
+#ifndef MAKEFS
+		struct denode_key old_key = dep->de_key;
+		struct denode_key new_key = dep->de_key;
+
+		KASSERT(new_key.dk_dirgen == NULL);
+		new_key.dk_dirgen = dep;
+		vcache_rekey_enter(pmp->pm_mountp, DETOV(dep), &old_key,
+		    sizeof(old_key), &new_key, sizeof(new_key));
+		dep->de_key = new_key;
+		vcache_rekey_exit(pmp->pm_mountp, DETOV(dep), &old_key,
+		    sizeof(old_key), &dep->de_key, sizeof(dep->de_key));
+#endif
+	}
 	offset += sizeof(struct direntry);
 	do {
 		offset -= sizeof(struct direntry);

Index: src/sys/fs/msdosfs/msdosfs_vfsops.c
diff -u src/sys/fs/msdosfs/msdosfs_vfsops.c:1.108 src/sys/fs/msdosfs/msdosfs_vfsops.c:1.109
--- src/sys/fs/msdosfs/msdosfs_vfsops.c:1.108	Sat May 24 16:34:03 2014
+++ src/sys/fs/msdosfs/msdosfs_vfsops.c	Tue Jul  8 09:21:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdosfs_vfsops.c,v 1.108 2014/05/24 16:34:03 christos Exp $	*/
+/*	$NetBSD: msdosfs_vfsops.c,v 1.109 2014/07/08 09:21:52 hannken Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.108 2014/05/24 16:34:03 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.109 2014/07/08 09:21:52 hannken Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -96,8 +96,6 @@ MODULE(MODULE_CLASS_VFS, msdos, NULL);
 #define MSDOSFS_NAMEMAX(pmp) \
 	(pmp)->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12
 
-VFS_PROTOS(msdosfs);
-
 int msdosfs_mountfs(struct vnode *, struct mount *, struct lwp *,
     struct msdosfs_args *);
 
@@ -129,6 +127,7 @@ struct vfsops msdosfs_vfsops = {
 	.vfs_statvfs = msdosfs_statvfs,
 	.vfs_sync = msdosfs_sync,
 	.vfs_vget = msdosfs_vget,
+	.vfs_loadvnode = msdosfs_loadvnode,
 	.vfs_fhtovp = msdosfs_fhtovp,
 	.vfs_vptofh = msdosfs_vptofh,
 	.vfs_init = msdosfs_init,
@@ -910,16 +909,20 @@ int
 msdosfs_root(struct mount *mp, struct vnode **vpp)
 {
 	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
-	struct denode *ndep;
 	int error;
 
 #ifdef MSDOSFS_DEBUG
 	printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
 #endif
-	if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0)
-		return (error);
-	*vpp = DETOV(ndep);
-	return (0);
+	if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, vpp)) != 0)
+		return error;
+	error = vn_lock(*vpp, LK_EXCLUSIVE);
+	if (error) {
+		vrele(*vpp);
+		*vpp = NULL;
+		return error;
+	}
+	return 0;
 }
 
 int
@@ -1019,7 +1022,6 @@ msdosfs_fhtovp(struct mount *mp, struct 
 {
 	struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
 	struct defid defh;
-	struct denode *dep;
 	uint32_t gen;
 	int error;
 
@@ -1037,14 +1039,19 @@ msdosfs_fhtovp(struct mount *mp, struct 
 		*vpp = NULLVP;
 		return error;
 	}
-	error = deget(pmp, defh.defid_dirclust, defh.defid_dirofs, &dep);
+	error = deget(pmp, defh.defid_dirclust, defh.defid_dirofs, vpp);
 	if (error) {
 		DPRINTF(("deget %d\n", error));
 		*vpp = NULLVP;
-		return (error);
+		return error;
 	}
-	*vpp = DETOV(dep);
-	return (0);
+	error = vn_lock(*vpp, LK_EXCLUSIVE);
+	if (error) {
+		vrele(*vpp);
+		*vpp = NULLVP;
+		return error;
+	}
+	return 0;
 }
 
 int

Index: src/sys/fs/msdosfs/msdosfs_vnops.c
diff -u src/sys/fs/msdosfs/msdosfs_vnops.c:1.89 src/sys/fs/msdosfs/msdosfs_vnops.c:1.90
--- src/sys/fs/msdosfs/msdosfs_vnops.c:1.89	Thu Jan 23 10:13:56 2014
+++ src/sys/fs/msdosfs/msdosfs_vnops.c	Tue Jul  8 09:21:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdosfs_vnops.c,v 1.89 2014/01/23 10:13:56 hannken Exp $	*/
+/*	$NetBSD: msdosfs_vnops.c,v 1.90 2014/07/08 09:21:52 hannken Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.89 2014/01/23 10:13:56 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.90 2014/07/08 09:21:52 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -1072,18 +1072,25 @@ abortit:
 		}
 		cache_purge(fvp);
 		if (!doingdirectory) {
+			struct denode_key old_key = ip->de_key;
+			struct denode_key new_key = ip->de_key;
+
 			error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
-				       &ip->de_dirclust, 0);
+				       &new_key.dk_dirclust, 0);
 			if (error) {
 				/* XXX should really panic here, fs is corrupt */
 				VOP_UNLOCK(fvp);
 				goto bad;
 			}
-			ip->de_diroffset = to_diroffset;
-			if (ip->de_dirclust != MSDOSFSROOT)
-				ip->de_diroffset &= pmp->pm_crbomask;
+			new_key.dk_diroffset = to_diroffset;
+			if (new_key.dk_dirclust != MSDOSFSROOT)
+				new_key.dk_diroffset &= pmp->pm_crbomask;
+			vcache_rekey_enter(pmp->pm_mountp, fvp, &old_key,
+			    sizeof(old_key), &new_key, sizeof(new_key));
+			ip->de_key = new_key;
+			vcache_rekey_exit(pmp->pm_mountp, fvp, &old_key,
+			    sizeof(old_key), &ip->de_key, sizeof(ip->de_key));
 		}
-		reinsert(ip);
 	}
 
 	/*

Index: src/sys/fs/msdosfs/msdosfsmount.h
diff -u src/sys/fs/msdosfs/msdosfsmount.h:1.19 src/sys/fs/msdosfs/msdosfsmount.h:1.20
--- src/sys/fs/msdosfs/msdosfsmount.h:1.19	Sat Jan 26 16:51:51 2013
+++ src/sys/fs/msdosfs/msdosfsmount.h	Tue Jul  8 09:21:52 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdosfsmount.h,v 1.19 2013/01/26 16:51:51 christos Exp $	*/
+/*	$NetBSD: msdosfsmount.h,v 1.20 2014/07/08 09:21:52 hannken Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -251,5 +251,9 @@ void msdosfs_init(void);
 void msdosfs_reinit(void);
 void msdosfs_done(void);
 
+#ifndef MAKEFS
+VFS_PROTOS(msdosfs);
+#endif
+
 #endif /* _KERNEL || MAKEFS */
 #endif /* _MSDOSFS_MSDOSFSMOUNT_H_ */

Reply via email to