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_ */