Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src Msdosfs on-disk meta data is not sufficient to create or val...
details: https://anonhg.NetBSD.org/src/rev/f32ed316e311
branches: trunk
changeset: 763813:f32ed316e311
user: hannken <hannken%NetBSD.org@localhost>
date: Mon Apr 04 19:16:58 2011 +0000
description:
Msdosfs on-disk meta data is not sufficient to create or validate file handles.
Maintain a tree of file handles, create nodes from msdosfs_vptofh() and keep
them until either the file gets unlinked or the file system gets unmounted.
Fixes the msdosfs part of PR #43745 (fhopen of an unlinked file causes problems
on multiple file systems)
diffstat:
sys/fs/msdosfs/denode.h | 8 +-
sys/fs/msdosfs/msdosfs_denode.c | 155 +++++++++++++++++++++++++++++++++++++++-
sys/fs/msdosfs/msdosfs_vfsops.c | 25 ++++-
tests/fs/vfs/t_vfsops.c | 4 +-
4 files changed, 179 insertions(+), 13 deletions(-)
diffs (truncated from 328 to 300 lines):
diff -r 40a4bab25b78 -r f32ed316e311 sys/fs/msdosfs/denode.h
--- a/sys/fs/msdosfs/denode.h Mon Apr 04 19:08:42 2011 +0000
+++ b/sys/fs/msdosfs/denode.h Mon Apr 04 19:16:58 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: denode.h,v 1.18 2010/04/08 16:04:35 pooka Exp $ */
+/* $NetBSD: denode.h,v 1.19 2011/04/04 19:16:58 hannken Exp $ */
/*-
* Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -249,9 +249,7 @@
u_int32_t defid_dirclust; /* cluster this dir entry came from */
u_int32_t defid_dirofs; /* offset of entry within the cluster */
-#if 0
u_int32_t defid_gen; /* generation number */
-#endif
};
/*
@@ -310,5 +308,9 @@
void msdosfs_gop_markupdate(struct vnode *, int);
void msdosfs_detimes(struct denode *, const struct timespec *,
const struct timespec *, const struct timespec *, int);
+int msdosfs_fh_enter(struct msdosfsmount *, uint32_t, uint32_t, uint32_t *);
+int msdosfs_fh_remove(struct msdosfsmount *, uint32_t, uint32_t);
+int msdosfs_fh_lookup(struct msdosfsmount *, uint32_t, uint32_t, uint32_t *);
+void msdosfs_fh_destroy(struct msdosfsmount *);
#endif /* _KERNEL */
#endif /* _MSDOSFS_DENODE_H_ */
diff -r 40a4bab25b78 -r f32ed316e311 sys/fs/msdosfs/msdosfs_denode.c
--- a/sys/fs/msdosfs/msdosfs_denode.c Mon Apr 04 19:08:42 2011 +0000
+++ b/sys/fs/msdosfs/msdosfs_denode.c Mon Apr 04 19:16:58 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: msdosfs_denode.c,v 1.42 2011/03/22 20:33:51 hannken Exp $ */
+/* $NetBSD: msdosfs_denode.c,v 1.43 2011/04/04 19:16:58 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.42 2011/03/22 20:33:51 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_denode.c,v 1.43 2011/04/04 19:16:58 hannken Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -84,6 +84,53 @@
extern int prtactive;
+struct fh_key {
+ struct msdosfsmount *fhk_mount;
+ uint32_t fhk_dircluster;
+ uint32_t fhk_diroffset;
+};
+struct fh_node {
+ struct rb_node fh_rbnode;
+ struct fh_key fh_key;
+#define fh_mount fh_key.fhk_mount
+#define fh_dircluster fh_key.fhk_dircluster
+#define fh_diroffset fh_key.fhk_diroffset
+ uint32_t fh_gen;
+};
+
+static int
+fh_compare_node_fh(void *ctx, const void *b, const void *key)
+{
+ const struct fh_node * const pnp = b;
+ const struct fh_key * const fhp = key;
+
+ /* msdosfs_fh_destroy() below depends on first sorting on fh_mount. */
+ if (pnp->fh_mount != fhp->fhk_mount)
+ return (intptr_t)pnp->fh_mount - (intptr_t)fhp->fhk_mount;
+ if (pnp->fh_dircluster != fhp->fhk_dircluster)
+ return pnp->fh_dircluster - fhp->fhk_dircluster;
+ return pnp->fh_diroffset - fhp->fhk_diroffset;
+}
+
+static int
+fh_compare_nodes(void *ctx, const void *parent, const void *node)
+{
+ const struct fh_node * const np = node;
+
+ return fh_compare_node_fh(ctx, parent, &np->fh_key);
+}
+
+static uint32_t fh_generation;
+static kmutex_t fh_lock;
+static struct pool fh_pool;
+static rb_tree_t fh_rbtree;
+static const rb_tree_ops_t fh_rbtree_ops = {
+ .rbto_compare_nodes = fh_compare_nodes,
+ .rbto_compare_key = fh_compare_node_fh,
+ .rbto_node_offset = offsetof(struct fh_node, fh_rbnode),
+ .rbto_context = NULL
+};
+
static const struct genfs_ops msdosfs_genfsops = {
.gop_size = genfs_size,
.gop_alloc = msdosfs_gop_alloc,
@@ -106,8 +153,12 @@
malloc_type_attach(M_MSDOSFSTMP);
pool_init(&msdosfs_denode_pool, sizeof(struct denode), 0, 0, 0,
"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);
}
@@ -147,7 +198,9 @@
{
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);
@@ -686,6 +739,8 @@
error = detrunc(dep, (u_long)0, 0, NOCRED);
}
dep->de_Name[0] = SLOT_DELETED;
+ msdosfs_fh_remove(dep->de_pmp,
+ dep->de_dirclust, dep->de_diroffset);
}
deupdat(dep, 0);
out:
@@ -727,3 +782,99 @@
dep->de_flag |= mask;
}
}
+
+int
+msdosfs_fh_enter(struct msdosfsmount *pmp,
+ uint32_t dircluster, uint32_t diroffset, uint32_t *genp)
+{
+ struct fh_key fhkey;
+ struct fh_node *fhp;
+
+ fhkey.fhk_mount = pmp;
+ fhkey.fhk_dircluster = dircluster;
+ fhkey.fhk_diroffset = diroffset;
+
+ mutex_enter(&fh_lock);
+ fhp = rb_tree_find_node(&fh_rbtree, &fhkey);
+ if (fhp == NULL) {
+ mutex_exit(&fh_lock);
+ fhp = pool_get(&fh_pool, PR_WAITOK);
+ mutex_enter(&fh_lock);
+ fhp->fh_key = fhkey;
+ fhp->fh_gen = fh_generation++;
+ rb_tree_insert_node(&fh_rbtree, fhp);
+ }
+ *genp = fhp->fh_gen;
+ mutex_exit(&fh_lock);
+ return 0;
+}
+
+int
+msdosfs_fh_remove(struct msdosfsmount *pmp,
+ uint32_t dircluster, uint32_t diroffset)
+{
+ struct fh_key fhkey;
+ struct fh_node *fhp;
+
+ fhkey.fhk_mount = pmp;
+ fhkey.fhk_dircluster = dircluster;
+ fhkey.fhk_diroffset = diroffset;
+
+ mutex_enter(&fh_lock);
+ fhp = rb_tree_find_node(&fh_rbtree, &fhkey);
+ if (fhp == NULL) {
+ mutex_exit(&fh_lock);
+ return ENOENT;
+ }
+ rb_tree_remove_node(&fh_rbtree, fhp);
+ mutex_exit(&fh_lock);
+ pool_put(&fh_pool, fhp);
+ return 0;
+}
+
+int
+msdosfs_fh_lookup(struct msdosfsmount *pmp,
+ uint32_t dircluster, uint32_t diroffset, uint32_t *genp)
+{
+ struct fh_key fhkey;
+ struct fh_node *fhp;
+
+ fhkey.fhk_mount = pmp;
+ fhkey.fhk_dircluster = dircluster;
+ fhkey.fhk_diroffset = diroffset;
+
+ mutex_enter(&fh_lock);
+ fhp = rb_tree_find_node(&fh_rbtree, &fhkey);
+ if (fhp == NULL) {
+ mutex_exit(&fh_lock);
+ return ESTALE;
+ }
+ *genp = fhp->fh_gen;
+ mutex_exit(&fh_lock);
+ return 0;
+}
+
+void
+msdosfs_fh_destroy(struct msdosfsmount *pmp)
+{
+ struct fh_key fhkey;
+ struct fh_node *fhp, *nfhp;
+
+ fhkey.fhk_mount = pmp;
+ fhkey.fhk_dircluster = 0;
+ fhkey.fhk_diroffset = 0;
+
+ mutex_enter(&fh_lock);
+ for (fhp = rb_tree_find_node_geq(&fh_rbtree, &fhkey);
+ fhp != NULL && fhp->fh_mount == pmp; fhp = nfhp) {
+ nfhp = rb_tree_iterate(&fh_rbtree, fhp, RB_DIR_RIGHT);
+ rb_tree_remove_node(&fh_rbtree, fhp);
+ pool_put(&fh_pool, fhp);
+ }
+#ifdef DIAGNOSTIC
+ RB_TREE_FOREACH(fhp, &fh_rbtree) {
+ KASSERT(fhp->fh_mount != pmp);
+ }
+#endif
+ mutex_exit(&fh_lock);
+}
diff -r 40a4bab25b78 -r f32ed316e311 sys/fs/msdosfs/msdosfs_vfsops.c
--- a/sys/fs/msdosfs/msdosfs_vfsops.c Mon Apr 04 19:08:42 2011 +0000
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c Mon Apr 04 19:16:58 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: msdosfs_vfsops.c,v 1.89 2010/12/27 18:49:42 hannken Exp $ */
+/* $NetBSD: msdosfs_vfsops.c,v 1.90 2011/04/04 19:16:58 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.89 2010/12/27 18:49:42 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.90 2011/04/04 19:16:58 hannken Exp $");
#if defined(_KERNEL_OPT)
#include "opt_compat_netbsd.h"
@@ -887,6 +887,7 @@
(void) VOP_CLOSE(pmp->pm_devvp,
pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED);
vput(pmp->pm_devvp);
+ msdosfs_fh_destroy(pmp);
free(pmp->pm_inusemap, M_MSDOSFSFAT);
free(pmp, M_MSDOSFSMNT);
mp->mnt_data = NULL;
@@ -1009,6 +1010,7 @@
struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
struct defid defh;
struct denode *dep;
+ uint32_t gen;
int error;
if (fhp->fid_len != sizeof(struct defid)) {
@@ -1016,8 +1018,15 @@
sizeof(struct defid)));
return EINVAL;
}
-
memcpy(&defh, fhp, sizeof(defh));
+ error = msdosfs_fh_lookup(pmp, defh.defid_dirclust, defh.defid_dirofs,
+ &gen);
+ if (error == 0 && gen != defh.defid_gen)
+ error = ESTALE;
+ if (error) {
+ *vpp = NULLVP;
+ return error;
+ }
error = deget(pmp, defh.defid_dirclust, defh.defid_dirofs, &dep);
if (error) {
DPRINTF(("deget %d\n", error));
@@ -1031,8 +1040,10 @@
int
msdosfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
{
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(vp->v_mount);
struct denode *dep;
struct defid defh;
+ int error;
if (*fh_size < sizeof(struct defid)) {
*fh_size = sizeof(struct defid);
@@ -1044,9 +1055,11 @@
defh.defid_len = sizeof(struct defid);
defh.defid_dirclust = dep->de_dirclust;
defh.defid_dirofs = dep->de_diroffset;
- /* defh.defid_gen = dep->de_gen; */
Home |
Main Index |
Thread Index |
Old Index