diff --git a/sys/fs/msdosfs/denode.h b/sys/fs/msdosfs/denode.h index 5d68d6f..4fd306c 100644 --- a/sys/fs/msdosfs/denode.h +++ b/sys/fs/msdosfs/denode.h @@ -207,9 +207,6 @@ struct denode { ((dep)->de_Attributes & ATTR_DIRECTORY) ? 0 : (dep)->de_FileSize), \ putushort((dp)->deHighClust, (dep)->de_StartCluster >> 16)) -#define de_forw de_chain[0] -#define de_back de_chain[1] - #ifdef _KERNEL #define VTODE(vp) ((struct denode *)(vp)->v_data) diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c index d461484..e2ff102 100644 --- a/sys/fs/msdosfs/msdosfs_denode.c +++ b/sys/fs/msdosfs/msdosfs_denode.c @@ -144,11 +144,11 @@ deget(pmp, dirclust, diroffset, depp) } /* - * Do the MALLOC before the getnewvnode since doing so afterward + * Do the malloc before the getnewvnode since doing so afterward * might cause a bogus v_data pointer to get dereferenced * elsewhere if MALLOC should block. */ - ldep = malloc(sizeof(struct denode), M_MSDOSFSNODE, M_WAITOK); + ldep = malloc(sizeof(struct denode), M_MSDOSFSNODE, M_WAITOK | M_ZERO); /* * Directory entry was not in cache, have to create a vnode and @@ -161,16 +161,14 @@ deget(pmp, dirclust, diroffset, depp) free(ldep, M_MSDOSFSNODE); return error; } - bzero((caddr_t)ldep, sizeof *ldep); nvp->v_data = ldep; ldep->de_vnode = nvp; ldep->de_flag = 0; ldep->de_dirclust = dirclust; ldep->de_diroffset = diroffset; ldep->de_inode = inode; - fc_purge(ldep, 0); /* init the fat cache for this denode */ - lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL); + fc_purge(ldep, 0); /* init the fat cache for this denode */ error = insmntque(nvp, mntp); if (error != 0) { free(ldep, M_MSDOSFSNODE); @@ -184,9 +182,8 @@ deget(pmp, dirclust, diroffset, depp) return (error); } if (xvp != NULL) { - /* XXX: Not sure this is right */ - nvp = xvp; - ldep->de_vnode = nvp; + *depp = xvp->v_data; + return (0); } ldep->de_pmp = pmp; @@ -595,7 +592,7 @@ msdosfs_inactive(ap) /* * Ignore denodes related to stale file handles. */ - if (dep->de_Name[0] == SLOT_DELETED) + if (dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY) goto out; /* @@ -623,7 +620,7 @@ out: printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n", vrefcnt(vp), dep->de_Name[0]); #endif - if (dep->de_Name[0] == SLOT_DELETED) + if (dep->de_Name[0] == SLOT_DELETED || dep->de_Name[0] == SLOT_EMPTY) vrecycle(vp, td); return (error); } diff --git a/sys/fs/msdosfs/msdosfs_fat.c b/sys/fs/msdosfs/msdosfs_fat.c index 7fae9c0..64c4244 100644 --- a/sys/fs/msdosfs/msdosfs_fat.c +++ b/sys/fs/msdosfs/msdosfs_fat.c @@ -60,19 +60,6 @@ #include #include -/* - * Fat cache stats. - */ -static int fc_fileextends; /* # of file extends */ -static int fc_lfcempty; /* # of time last file cluster cache entry - * was empty */ -static int fc_bmapcalls; /* # of times pcbmap was called */ - -#define LMMAX 20 -static int fc_lmdistance[LMMAX];/* counters for how far off the last - * cluster mapped entry was. */ -static int fc_largedistance; /* off by more than LMMAX */ - static int chainalloc(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith, u_long *retcluster, u_long *got); @@ -90,6 +77,9 @@ static __inline void usemap_alloc(struct msdosfsmount *pmp, u_long cn); static __inline void usemap_free(struct msdosfsmount *pmp, u_long cn); +static int clusteralloc1(struct msdosfsmount *pmp, u_long start, + u_long count, u_long fillwith, u_long *retcluster, + u_long *got); static void fatblock(pmp, ofs, bnp, sizep, bop) @@ -152,14 +142,9 @@ pcbmap(dep, findcn, bnp, cnp, sp) struct msdosfsmount *pmp = dep->de_pmp; u_long bsize; - fc_bmapcalls++; - - /* - * If they don't give us someplace to return a value then don't - * bother doing anything. - */ - if (bnp == NULL && cnp == NULL && sp == NULL) - return (0); + KASSERT(bnp != NULL || cnp != NULL || sp != NULL, + ("pcbmap: extra call")); + ASSERT_VOP_ELOCKED(DETOV(dep), "pcbmap"); cn = dep->de_StartCluster; /* @@ -203,10 +188,6 @@ pcbmap(dep, findcn, bnp, cnp, sp) */ i = 0; fc_lookup(dep, findcn, &i, &cn); - if ((bn = findcn - i) >= LMMAX) - fc_largedistance++; - else - fc_lmdistance[bn]++; /* * Handle all other files or directories the normal way. @@ -289,6 +270,8 @@ fc_lookup(dep, findcn, frcnp, fsrcnp) u_long cn; struct fatcache *closest = 0; + ASSERT_VOP_LOCKED(DETOV(dep), "fc_lookup"); + for (i = 0; i < FC_SIZE; i++) { cn = dep->de_fc[i].fc_frcn; if (cn != FCE_EMPTY && cn <= findcn) { @@ -314,6 +297,8 @@ fc_purge(dep, frcn) int i; struct fatcache *fcp; + ASSERT_VOP_ELOCKED(DETOV(dep), "fc_purge"); + fcp = dep->de_fc; for (i = 0; i < FC_SIZE; i++, fcp++) { if (fcp->fc_frcn >= frcn) @@ -427,6 +412,7 @@ usemap_alloc(pmp, cn) u_long cn; { + MSDOSFS_ASSERT_MP_LOCKED(pmp); pmp->pm_inusemap[cn / N_INUSEBITS] |= 1 << (cn % N_INUSEBITS); pmp->pm_freeclustercount--; } @@ -437,6 +423,7 @@ usemap_free(pmp, cn) u_long cn; { + MSDOSFS_ASSERT_MP_LOCKED(pmp); pmp->pm_freeclustercount++; pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1 << (cn % N_INUSEBITS)); } @@ -450,17 +437,17 @@ clusterfree(pmp, cluster, oldcnp) int error; u_long oldcn; - usemap_free(pmp, cluster); error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE); - if (error) { - usemap_alloc(pmp, cluster); + if (error) return (error); - } /* * If the cluster was successfully marked free, then update * the count of free clusters, and turn off the "allocated" * bit in the "in use" cluster bit map. */ + MSDOSFS_LOCK_MP(pmp); + usemap_free(pmp, cluster); + MSDOSFS_UNLOCK_MP(pmp); if (oldcnp) *oldcnp = oldcn; return (0); @@ -678,6 +665,8 @@ chainlength(pmp, start, count) u_int map; u_long len; + MSDOSFS_ASSERT_MP_LOCKED(pmp); + max_idx = pmp->pm_maxcluster / N_INUSEBITS; idx = start / N_INUSEBITS; start %= N_INUSEBITS; @@ -726,6 +715,8 @@ chainalloc(pmp, start, count, fillwith, retcluster, got) int error; u_long cl, n; + MSDOSFS_ASSERT_MP_LOCKED(pmp); + for (cl = start, n = count; n-- > 0;) usemap_alloc(pmp, cl++); @@ -758,19 +749,28 @@ chainalloc(pmp, start, count, fillwith, retcluster, got) * got - how many clusters were actually allocated. */ int -clusteralloc(pmp, start, count, fillwith, retcluster, got) - struct msdosfsmount *pmp; - u_long start; - u_long count; - u_long fillwith; - u_long *retcluster; - u_long *got; +clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count, + u_long fillwith, u_long *retcluster, u_long *got) +{ + int error; + + MSDOSFS_LOCK_MP(pmp); + error = clusteralloc1(pmp, start, count, fillwith, retcluster, got); + MSDOSFS_UNLOCK_MP(pmp); + return (error); +} + +static int +clusteralloc1(struct msdosfsmount *pmp, u_long start, u_long count, + u_long fillwith, u_long *retcluster, u_long *got) { u_long idx; u_long len, newst, foundl, cn, l; u_long foundcn = 0; /* XXX: foundcn could be used unititialized */ u_int map; + MSDOSFS_ASSERT_MP_LOCKED(pmp); + #ifdef MSDOSFS_DEBUG printf("clusteralloc(): find %lu clusters\n", count); #endif @@ -906,6 +906,8 @@ fillinusemap(pmp) int error; u_long bn, bo, bsize, byteoffset; + MSDOSFS_ASSERT_MP_LOCKED(pmp); + /* * Mark all clusters in use, we mark the free ones in the fat scan * loop further down. @@ -991,10 +993,8 @@ extendfile(dep, count, bpp, ncp, flags) * If the "file's last cluster" cache entry is empty, and the file * is not empty, then fill the cache entry by calling pcbmap(). */ - fc_fileextends++; if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY && dep->de_StartCluster != 0) { - fc_lfcempty++; error = pcbmap(dep, 0xffff, 0, &cn, 0); /* we expect it to return E2BIG */ if (error != E2BIG) diff --git a/sys/fs/msdosfs/msdosfs_fileno.c b/sys/fs/msdosfs/msdosfs_fileno.c index ff1f2b7..b56fb43 100644 --- a/sys/fs/msdosfs/msdosfs_fileno.c +++ b/sys/fs/msdosfs/msdosfs_fileno.c @@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include @@ -59,9 +58,6 @@ __FBSDID("$FreeBSD$"); static MALLOC_DEFINE(M_MSDOSFSFILENO, "msdosfs_fileno", "MSDOSFS fileno mapping node"); -static struct mtx fileno_mtx; -MTX_SYSINIT(fileno, &fileno_mtx, "MSDOSFS fileno", MTX_DEF); - RB_PROTOTYPE(msdosfs_filenotree, msdosfs_fileno, mf_tree, msdosfs_fileno_compare) @@ -117,30 +113,30 @@ msdosfs_fileno_map(mp, fileno) } if (fileno < FILENO_FIRST_DYN) return ((uint32_t)fileno); - mtx_lock(&fileno_mtx); + MSDOSFS_LOCK_MP(pmp); key.mf_fileno64 = fileno; mf = RB_FIND(msdosfs_filenotree, &pmp->pm_filenos, &key); if (mf != NULL) { mapped = mf->mf_fileno32; - mtx_unlock(&fileno_mtx); + MSDOSFS_UNLOCK_MP(pmp); return (mapped); } if (pmp->pm_nfileno < FILENO_FIRST_DYN) panic("msdosfs_fileno_map: wraparound"); - mtx_unlock(&fileno_mtx); + MSDOSFS_UNLOCK_MP(pmp); mf = malloc(sizeof(*mf), M_MSDOSFSFILENO, M_WAITOK); - mtx_lock(&fileno_mtx); + MSDOSFS_LOCK_MP(pmp); tmf = RB_FIND(msdosfs_filenotree, &pmp->pm_filenos, &key); if (tmf != NULL) { mapped = tmf->mf_fileno32; - mtx_unlock(&fileno_mtx); + MSDOSFS_UNLOCK_MP(pmp); free(mf, M_MSDOSFSFILENO); return (mapped); } mf->mf_fileno64 = fileno; mapped = mf->mf_fileno32 = pmp->pm_nfileno++; RB_INSERT(msdosfs_filenotree, &pmp->pm_filenos, mf); - mtx_unlock(&fileno_mtx); + MSDOSFS_UNLOCK_MP(pmp); return (mapped); } diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c index 8186763..3cecd73 100644 --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -75,6 +75,8 @@ #include #include +static const char msdosfs_lock_msg[] = "fatlk"; + /* Mount options that we support. */ static const char *msdosfs_opts[] = { "async", "noatime", "noclusterr", "noclusterw", @@ -466,6 +468,8 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp) pmp->pm_cp = cp; pmp->pm_bo = bo; + lockinit(&pmp->pm_fatlock, 0, msdosfs_lock_msg, 0, 0); + /* * Initialize ownerships and permissions, since nothing else will * initialize them iff we are mounting root. @@ -716,7 +720,10 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp) /* * Have the inuse map filled in. */ - if ((error = fillinusemap(pmp)) != 0) + MSDOSFS_LOCK_MP(pmp); + error = fillinusemap(pmp); + MSDOSFS_UNLOCK_MP(pmp); + if (error != 0) goto error_exit; /* @@ -745,6 +752,7 @@ mountmsdosfs(struct vnode *devvp, struct mount *mp) mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; + mp->mnt_kern_flag |= MNTK_MPSAFE; MNT_IUNLOCK(mp); if (pmp->pm_flags & MSDOSFS_LARGEFS) @@ -762,6 +770,7 @@ error_exit: g_topology_unlock(); PICKUP_GIANT(); } + lockdestroy(&pmp->pm_fatlock); if (pmp) { if (pmp->pm_inusemap) free(pmp->pm_inusemap, M_MSDOSFSFAT); @@ -837,6 +846,7 @@ msdosfs_unmount(struct mount *mp, int mntflags) free(pmp->pm_inusemap, M_MSDOSFSFAT); if (pmp->pm_flags & MSDOSFS_LARGEFS) msdosfs_fileno_free(mp); + lockdestroy(&pmp->pm_fatlock); free(pmp, M_MSDOSFSMNT); mp->mnt_data = NULL; MNT_ILOCK(mp); diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h index bfe3ec3..2951b2c 100644 --- a/sys/fs/msdosfs/msdosfsmount.h +++ b/sys/fs/msdosfs/msdosfsmount.h @@ -53,6 +53,9 @@ #ifdef _KERNEL +#include +#include +#include #include #ifdef MALLOC_DECLARE @@ -106,7 +109,9 @@ struct msdosfsmount { void *pm_u2d; /* Unicode->DOS iconv handle */ void *pm_d2u; /* DOS->Local iconv handle */ u_int32_t pm_nfileno; /* next 32-bit fileno */ - RB_HEAD(msdosfs_filenotree, msdosfs_fileno) pm_filenos; /* 64<->32-bit fileno mapping */ + RB_HEAD(msdosfs_filenotree, msdosfs_fileno) + pm_filenos; /* 64<->32-bit fileno mapping */ + struct lock pm_fatlock; /* lockmgr protecting allocations and rb tree */ }; /* @@ -215,6 +220,13 @@ void msdosfs_fileno_init(struct mount *); void msdosfs_fileno_free(struct mount *); uint32_t msdosfs_fileno_map(struct mount *, uint64_t); +#define MSDOSFS_LOCK_MP(pmp) \ + lockmgr(&(pmp)->pm_fatlock, LK_EXCLUSIVE, NULL) +#define MSDOSFS_UNLOCK_MP(pmp) \ + lockmgr(&(pmp)->pm_fatlock, LK_RELEASE, NULL) +#define MSDOSFS_ASSERT_MP_LOCKED(pmp) \ + lockmgr_assert(&(pmp)->pm_fatlock, KA_XLOCKED) + #endif /* _KERNEL */ /*