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