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