Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Give a p2k node an internal state. This allows us to do proper



details:   https://anonhg.NetBSD.org/src/rev/0e08b8c34978
branches:  trunk
changeset: 747947:0e08b8c34978
user:      pooka <pooka%NetBSD.org@localhost>
date:      Tue Oct 06 16:23:03 2009 +0000

description:
Give a p2k node an internal state.  This allows us to do proper
reference counting and not release nodes based just on puffs'
impression of if they are free.

This also allows us to reclaim vnodes already in inactive if the
file system so desires.  Some file systems, most notably ffs, change
file state already in inactive.  This could lead to a deadlock in
the middle of inactive and reclaim if some other puffs operation
was processed in between (as exposed by haad's open(at) test
program).

Also, properly thread the componentname from lookup to the actual
vnode operation.  This required the changes the rump componentname
routines.  Yes, the rename case is truly mindbogglingly disgusting.
Puke for yourself.

diffstat:

 lib/libp2k/p2k.c                    |  631 ++++++++++++++++++++++++-----------
 sys/rump/include/rump/rump.h        |    7 +-
 sys/rump/librump/rumpvfs/rump_vfs.c |   24 +-
 3 files changed, 451 insertions(+), 211 deletions(-)

diffs (truncated from 1090 to 300 lines):

diff -r 0a1632879985 -r 0e08b8c34978 lib/libp2k/p2k.c
--- a/lib/libp2k/p2k.c  Tue Oct 06 13:45:01 2009 +0000
+++ b/lib/libp2k/p2k.c  Tue Oct 06 16:23:03 2009 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: p2k.c,v 1.16 2009/08/04 13:39:18 pooka Exp $   */
+/*     $NetBSD: p2k.c,v 1.17 2009/10/06 16:23:03 pooka Exp $   */
 
 /*
  * Copyright (c) 2007 Antti Kantee.  All Rights Reserved.
@@ -49,6 +49,7 @@
 #include <sys/lock.h>
 #include <sys/namei.h>
 #include <sys/dirent.h>
+#include <sys/hash.h>
 
 #include <assert.h>
 #include <errno.h>
@@ -62,6 +63,33 @@
 
 PUFFSOP_PROTOS(p2k)
 
+LIST_HEAD(p2k_vp_hash, p2k_node);
+#define NHASHBUCK (1<<16)
+struct p2k_mount {
+       struct vnode *p2m_rvp;
+       struct p2k_vp_hash p2m_vphash[NHASHBUCK];
+       int p2m_nvnodes;
+};
+
+struct p2k_node {
+       struct vnode *p2n_vp;
+       struct componentname *p2n_cn;
+
+       /*
+        * Ok, then, uhm, we need .. *drumroll*.. two componentname
+        * storages for rename.  This is because the source dir is
+        * unlocked after the first lookup, and someone else might
+        * race in here.  However, we know it's not another rename
+        * because of the kernel rename lock.  And we need two since
+        * srcdir and targdir might be the same.  It's a wonderful world.
+        */
+       struct componentname *p2n_cn_ren_src, *p2n_cn_ren_targ;
+
+       LIST_ENTRY(p2k_node) p2n_entries;
+};
+
+#define OPC2VP(opc) (((struct p2k_node *)opc)->p2n_vp)
+
 static kauth_cred_t
 cred_create(const struct puffs_cred *pcr)
 {
@@ -88,14 +116,14 @@
 }
 
 static struct componentname *
-makecn(const struct puffs_cn *pcn)
+makecn(const struct puffs_cn *pcn, int myflags)
 {
        kauth_cred_t cred;
 
        cred = cred_create(pcn->pcn_cred);
        /* LINTED: prehistoric types in first two args */
-       return rump_makecn(pcn->pcn_nameiop, pcn->pcn_flags, pcn->pcn_name,
-           pcn->pcn_namelen, cred, curlwp);
+       return rump_makecn(pcn->pcn_nameiop, pcn->pcn_flags | myflags,
+           pcn->pcn_name, pcn->pcn_namelen, cred, curlwp);
 }
 
 static __inline void
@@ -120,11 +148,69 @@
 clearlwp(struct puffs_usermount *pu)
 {
 
-       /*
-        * XXX: For unmount we release this already in the operation.
-        */
-       if (__predict_false(puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED))
-               rump_clear_curlwp();
+       rump_clear_curlwp();
+}
+
+static __inline struct p2k_vp_hash *
+gethash(struct p2k_mount *p2m, struct vnode *vp)
+{
+       uint32_t hash;
+
+       hash = hash32_buf(&vp, sizeof(vp), HASH32_BUF_INIT);
+       return &p2m->p2m_vphash[hash % NHASHBUCK];
+}
+
+/*
+ * Find node based on hash of vnode pointer.  If vnode is found,
+ * releases one reference to vnode based on the fact that we just
+ * performed a lookup for it.
+ *
+ * If the optinal p2n_storage parameter is passed, it is used instead
+ * of allocating more memory.  This allows for easier error recovery.
+ */
+static struct p2k_node *
+getp2n(struct p2k_mount *p2m, struct vnode *vp, bool initial,
+       struct p2k_node *p2n_storage)
+{
+       struct p2k_vp_hash *hl;
+       struct p2k_node *p2n = NULL;
+
+       /* p2n_storage => initial */
+       assert(!p2n_storage || initial);
+
+       hl = gethash(p2m, vp);
+       if (!initial)
+               LIST_FOREACH(p2n, hl, p2n_entries)
+                       if (p2n->p2n_vp == vp)
+                               break;
+
+       hl = gethash(p2m, vp);
+       if (p2n) {
+               rump_vp_rele(vp);
+       } else {
+               if (p2n_storage)
+                       p2n = p2n_storage;
+               else
+                       p2n = malloc(sizeof(*p2n));
+               if (!p2n) {
+                       rump_vp_rele(vp);
+                       return NULL;
+               }
+               memset(p2n, 0, sizeof(*p2n));
+               LIST_INSERT_HEAD(hl, p2n, p2n_entries);
+               p2n->p2n_vp = vp;
+       }
+       return p2n;
+}
+
+static void
+freep2n(struct p2k_node *p2n)
+{
+
+       assert(p2n->p2n_vp == NULL);
+       assert(p2n->p2n_cn == NULL);
+       LIST_REMOVE(p2n, p2n_entries);
+       free(p2n);
 }
 
 /*ARGSUSED*/
@@ -145,6 +231,20 @@
                abort();
 }
 
+/* just to avoid annoying loop when singlestepping */
+static void
+allocp2m(struct ukfs *ukfs)
+{
+       struct p2k_mount *p2m;
+       int i;
+
+       p2m = malloc(sizeof(*p2m));
+       p2m->p2m_nvnodes = 0;
+       for (i = 0; i < NHASHBUCK; i++)
+               LIST_INIT(&p2m->p2m_vphash[i]);
+       ukfs_setspecific(ukfs, p2m);
+}
+
 int
 p2k_run_fs(const char *vfsname, const char *devpath, const char *mountpath,
        int mntflags, void *arg, size_t alen, uint32_t puffs_flags)
@@ -152,9 +252,9 @@
        char typebuf[PUFFS_TYPELEN];
        struct puffs_ops *pops;
        struct puffs_usermount *pu = NULL;
-       struct puffs_node *pn_root;
-       struct vnode *rvp;
+       struct p2k_node *p2n_root;
        struct ukfs *ukfs = NULL;
+       struct p2k_mount *p2m = NULL;
        extern int puffs_fakecc;
        int rv = -1, sverrno;
        bool dodaemon;
@@ -234,19 +334,19 @@
        ukfs = ukfs_mount(vfsname, devpath, mountpath, mntflags, arg, alen);
        if (ukfs == NULL)
                goto out;
+       allocp2m(ukfs);
+       p2m = ukfs_getspecific(ukfs);
 
-       rvp = ukfs_getrvp(ukfs);
-       pn_root = puffs_pn_new(pu, rvp);
-       puffs_setroot(pu, pn_root);
+       p2m->p2m_rvp = ukfs_getrvp(ukfs);
+       p2n_root = getp2n(p2m, p2m->p2m_rvp, true, NULL);
        puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH);
        puffs_setstacksize(pu, PUFFS_STACKSIZE_MIN);
        puffs_fakecc = 1;
-
        puffs_set_prepost(pu, makelwp, clearlwp);
        puffs_set_errnotify(pu, p2k_errcatcher);
 
        puffs_setspecific(pu, ukfs);
-       if ((rv = puffs_mount(pu, mountpath, mntflags, rvp))== -1)
+       if ((rv = puffs_mount(pu, mountpath, mntflags, p2n_root))== -1)
                goto out;
        rv = puffs_mainloop(pu);
        puffs_exit(pu, 1);
@@ -255,6 +355,8 @@
 
  out:
        sverrno = errno;
+       if (p2m)
+               free(p2m);
        if (ukfs)
                ukfs_release(ukfs, UKFS_RELFLAG_FORCE);
        if (pu)
@@ -267,12 +369,6 @@
        return rv;
 }
 
-/* XXX: vn_lock() */
-#define VLE(a) RUMP_VOP_LOCK(a, LK_EXCLUSIVE)
-#define VLS(a) RUMP_VOP_LOCK(a, LK_SHARED)
-#define VUL(a) RUMP_VOP_UNLOCK(a, 0);
-#define AUL(a) assert(RUMP_VOP_ISLOCKED(a) == 0)
-
 int
 p2k_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp)
 {
@@ -286,11 +382,20 @@
 p2k_fs_unmount(struct puffs_usermount *pu, int flags)
 {
        struct ukfs *fs = puffs_getspecific(pu);
+       struct p2k_mount *p2m = ukfs_getspecific(fs);
+       int error = 0;
 
-       rump_clear_curlwp(); /* XXX: ukfs uses curlwp */
-       ukfs_release(fs, UKFS_RELFLAG_FORCE);
+       rump_clear_curlwp(); /* ukfs does its own curlwp tricks */
 
-       return 0;
+       rump_vp_rele(p2m->p2m_rvp);
+       if (ukfs_release(fs, 0) != 0) {
+               ukfs_release(fs, UKFS_RELFLAG_FORCE);
+               error = 0;
+       }
+       free(p2m);
+
+       rump_setup_curlwp(0, 1, 1);
+       return error;
 }
 
 int
@@ -314,20 +419,28 @@
        struct puffs_newinfo *pni)
 {
        struct mount *mp = ukfs_getmp(puffs_getspecific(pu));
+       struct p2k_mount *p2m = ukfs_getspecific(puffs_getspecific(pu));
+       struct p2k_node *p2n;
        struct vnode *vp;
        enum vtype vtype;
        voff_t vsize;
-       uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */
+       uint64_t rdev; /* XXX: allows running this on NetBSD 5.0 */
        int rv;
 
        rv = rump_vfs_fhtovp(mp, fid, &vp);
        if (rv)
                return rv;
+       RUMP_VOP_UNLOCK(vp, 0);
 
-       puffs_newinfo_setcookie(pni, vp);
+       p2n = getp2n(p2m, vp, false, NULL);
+       if (p2n == NULL)
+               return ENOMEM;
+
+       puffs_newinfo_setcookie(pni, p2n);
        rump_getvninfo(vp, &vtype, &vsize, (void *)&rdev);
        puffs_newinfo_setvtype(pni, vtype);
        puffs_newinfo_setsize(pni, vsize);
+       /* LINTED: yea, it'll lose accuracy, but that's life */
        puffs_newinfo_setrdev(pni, rdev);
 
        return 0;
@@ -348,29 +461,79 @@
 p2k_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
        struct puffs_newinfo *pni, const struct puffs_cn *pcn)
 {
+       struct p2k_mount *p2m = ukfs_getspecific(puffs_getspecific(pu));
+       struct p2k_node *p2n_dir = opc, *p2n;
        struct componentname *cn;
-       struct vnode *vp;
+       struct vnode *dvp = p2n_dir->p2n_vp, *vp;
        enum vtype vtype;
        voff_t vsize;
        uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */
        int rv;
 
-       cn = makecn(pcn);
-       VLE(opc);
-       rv = RUMP_VOP_LOOKUP(opc, &vp, cn);
-       VUL(opc);
-       freecn(cn, RUMPCN_ISLOOKUP);
+       cn = makecn(pcn, 0);
+       RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);



Home | Main Index | Thread Index | Old Index