Module Name: src Committed By: hannken Date: Sun Dec 21 10:48:53 UTC 2014
Modified Files: src/sys/fs/smbfs: smbfs.h smbfs_node.c smbfs_node.h smbfs_smb.c smbfs_vfsops.c smbfs_vnops.c Log Message: Change smbfs from hashlist to vcache. - Use (parent_vnode, name, name_len) as key. - Change smbfs_nget() to return a referenced but unlocked vnode and adapt smbfs_setroot(), smbfs_create(), smbfs_mkdir() and smbfs_lookup(). To generate a diff of this commit: cvs rdiff -u -r1.17 -r1.18 src/sys/fs/smbfs/smbfs.h cvs rdiff -u -r1.52 -r1.53 src/sys/fs/smbfs/smbfs_node.c cvs rdiff -u -r1.13 -r1.14 src/sys/fs/smbfs/smbfs_node.h cvs rdiff -u -r1.46 -r1.47 src/sys/fs/smbfs/smbfs_smb.c cvs rdiff -u -r1.103 -r1.104 src/sys/fs/smbfs/smbfs_vfsops.c cvs rdiff -u -r1.92 -r1.93 src/sys/fs/smbfs/smbfs_vnops.c 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/smbfs/smbfs.h diff -u src/sys/fs/smbfs/smbfs.h:1.17 src/sys/fs/smbfs/smbfs.h:1.18 --- src/sys/fs/smbfs/smbfs.h:1.17 Sun Sep 7 13:13:04 2008 +++ src/sys/fs/smbfs/smbfs.h Sun Dec 21 10:48:53 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs.h,v 1.17 2008/09/07 13:13:04 tron Exp $ */ +/* $NetBSD: smbfs.h,v 1.18 2014/12/21 10:48:53 hannken Exp $ */ /* * Copyright (c) 2000-2001, Boris Popov @@ -82,9 +82,6 @@ struct smbmount { struct smb_share * sm_share; struct smbnode * sm_npstack[SMBFS_MAXPATHCOMP]; int sm_caseopt; - kmutex_t sm_hashlock; - LIST_HEAD(smbnode_hashhead, smbnode) *sm_hash; - u_long sm_hashlen; int sm_didrele; }; Index: src/sys/fs/smbfs/smbfs_node.c diff -u src/sys/fs/smbfs/smbfs_node.c:1.52 src/sys/fs/smbfs/smbfs_node.c:1.53 --- src/sys/fs/smbfs/smbfs_node.c:1.52 Tue Nov 25 12:33:13 2014 +++ src/sys/fs/smbfs/smbfs_node.c Sun Dec 21 10:48:53 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_node.c,v 1.52 2014/11/25 12:33:13 nakayama Exp $ */ +/* $NetBSD: smbfs_node.c,v 1.53 2014/12/21 10:48:53 hannken Exp $ */ /* * Copyright (c) 2000-2001 Boris Popov @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smbfs_node.c,v 1.52 2014/11/25 12:33:13 nakayama Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smbfs_node.c,v 1.53 2014/12/21 10:48:53 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -62,10 +62,6 @@ __KERNEL_RCSID(0, "$NetBSD: smbfs_node.c #include <fs/smbfs/smbfs_node.h> #include <fs/smbfs/smbfs_subr.h> -#define SMBFS_NOHASH(smp, hval) (&(smp)->sm_hash[(hval) & (smp)->sm_hashlen]) - -MALLOC_JUSTDEFINE(M_SMBNODENAME, "SMBFS nname", "SMBFS node name"); - extern int (**smbfs_vnodeop_p)(void *); extern int prtactive; @@ -75,37 +71,58 @@ static const struct genfs_ops smbfs_genf struct pool smbfs_node_pool; -static inline char * -smbfs_name_alloc(const u_char *name, int nmlen) +int +smbfs_loadvnode(struct mount *mp, struct vnode *vp, + const void *key, size_t key_len, const void **new_key) { - u_char *cp; + struct smbnode *np; + + np = pool_get(&smbfs_node_pool, PR_WAITOK); + memset(np, 0, sizeof(*np)); - cp = malloc(nmlen, M_SMBNODENAME, M_WAITOK); - memcpy(cp, name, nmlen); + vp->v_tag = VT_SMBFS; + vp->v_op = smbfs_vnodeop_p; + vp->v_type = VNON; + vp->v_data = np; + genfs_node_init(vp, &smbfs_genfsops); - return cp; -} + mutex_init(&np->n_lock, MUTEX_DEFAULT, IPL_NONE); + np->n_key = kmem_alloc(key_len, KM_SLEEP); + memcpy(np->n_key, key, key_len); + KASSERT(key_len == SMBFS_KEYSIZE(np->n_nmlen)); + np->n_vnode = vp; + np->n_mount = VFSTOSMBFS(mp); -static inline void -smbfs_name_free(u_char *name) -{ - free(name, M_SMBNODENAME); + if (np->n_parent != NULL && (np->n_parent->v_vflag & VV_ROOT) == 0) { + vref(np->n_parent); + np->n_flag |= NREFPARENT; + } + + *new_key = np->n_key; + + return 0; } -static int -smbfs_node_alloc(struct mount *mp, struct vnode *dvp, - const char *name, int nmlen, struct smbfattr *fap, struct vnode **vpp) +int +smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen, + struct smbfattr *fap, struct vnode **vpp) { - struct vattr vattr; - struct smbmount *smp = VFSTOSMBFS(mp); - struct smbnode_hashhead *nhpp; - struct smbnode *np, *np2; + struct smbkey *key; + struct smbmount *smp __diagused; + struct smbnode *np; struct vnode *vp; - u_long hashval; + union { + struct smbkey u_key; + char u_data[64]; + } small_key; int error; + const int key_len = SMBFS_KEYSIZE(nmlen); + + smp = VFSTOSMBFS(mp); /* do not allow allocating root vnode twice */ KASSERT(dvp != NULL || smp->sm_root == NULL); + /* do not call with dot */ KASSERT(nmlen != 1 || name[0] != '.'); @@ -114,11 +131,8 @@ smbfs_node_alloc(struct mount *mp, struc return EINVAL; vp = VTOSMB(VTOSMB(dvp)->n_parent)->n_vnode; vref(vp); - if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY)) == 0) - *vpp = vp; - else - vrele(vp); - return (error); + *vpp = vp; + return 0; } #ifdef DIAGNOSTIC @@ -126,121 +140,71 @@ smbfs_node_alloc(struct mount *mp, struc if (dnp == NULL && dvp != NULL) panic("smbfs_node_alloc: dead parent vnode %p", dvp); #endif - hashval = smbfs_hash(name, nmlen); + + if (key_len > sizeof(small_key)) + key = kmem_alloc(key_len, KM_SLEEP); + else + key = &small_key.u_key; + key->k_parent = dvp; + key->k_nmlen = nmlen; + memcpy(key->k_name, name, nmlen); + retry: - mutex_enter(&smp->sm_hashlock); - nhpp = SMBFS_NOHASH(smp, hashval); - LIST_FOREACH(np, nhpp, n_hash) { - if (np->n_parent != dvp - || np->n_nmlen != nmlen - || memcmp(name, np->n_name, nmlen) != 0) - continue; - vp = SMBTOV(np); - mutex_enter((vp)->v_interlock); - mutex_exit(&smp->sm_hashlock); - if (vget(vp, LK_EXCLUSIVE) != 0) - goto retry; + error = vcache_get(mp, key, key_len, &vp); + if (error) + goto out; + mutex_enter(vp->v_interlock); + np = VTOSMB(vp); + KASSERT(np != NULL); + mutex_enter(&np->n_lock); + mutex_exit(vp->v_interlock); + + if (vp->v_type == VNON) { + /* + * If we don't have node attributes, then it is an + * explicit lookup for an existing vnode. + */ + if (fap == NULL) { + mutex_exit(&np->n_lock); + vrele(vp); + error = ENOENT; + goto out; + } + vp->v_type = fap->fa_attr & SMB_FA_DIR ? VDIR : VREG; + np->n_ino = fap->fa_ino; + np->n_size = fap->fa_size; + + /* new file vnode has to have a parent */ + KASSERT(vp->v_type != VREG || dvp != NULL); + + uvm_vnp_setsize(vp, np->n_size); + } else { + struct vattr vattr; + /* Force cached attributes to be refreshed if stale. */ (void)VOP_GETATTR(vp, &vattr, curlwp->l_cred); /* * If the file type on the server is inconsistent with * what it was when we created the vnode, kill the - * bogus vnode now and fall through to the code below - * to create a new one with the right type. + * bogus vnode now and retry to create a new one with + * the right type. */ if ((vp->v_type == VDIR && (np->n_dosattr & SMB_FA_DIR) == 0) || (vp->v_type == VREG && (np->n_dosattr & SMB_FA_DIR) != 0)) { - VOP_UNLOCK(vp); + mutex_exit(&np->n_lock); vgone(vp); - goto allocnew; - } - *vpp = vp; - return (0); - } - mutex_exit(&smp->sm_hashlock); - -allocnew: - /* - * If we don't have node attributes, then it is an explicit lookup - * for an existing vnode. - */ - if (fap == NULL) - return ENOENT; - - np = pool_get(&smbfs_node_pool, PR_WAITOK); - memset(np, 0, sizeof(*np)); - - error = getnewvnode(VT_SMBFS, mp, smbfs_vnodeop_p, NULL, &vp); - if (error) { - pool_put(&smbfs_node_pool, np); - return error; - } - - if (dvp) { - np->n_parent = dvp; - if (/*vp->v_type == VDIR &&*/ (dvp->v_vflag & VV_ROOT) == 0) { - vref(dvp); - np->n_flag |= NREFPARENT; - } - } - - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - - mutex_enter(&smp->sm_hashlock); - /* - * Check if the vnode wasn't added while we were in getnewvnode/ - * malloc. - */ - LIST_FOREACH(np2, nhpp, n_hash) { - if (np2->n_parent != dvp - || np2->n_nmlen != nmlen - || memcmp(name, np2->n_name, nmlen) != 0) - continue; - mutex_exit(&smp->sm_hashlock); - if ((np->n_flag & NREFPARENT) != 0) - vrele(dvp); - ungetnewvnode(vp); - pool_put(&smbfs_node_pool, np); - goto retry; + goto retry; + } } - - vp->v_type = fap->fa_attr & SMB_FA_DIR ? VDIR : VREG; - vp->v_data = np; - genfs_node_init(vp, &smbfs_genfsops); - - np->n_vnode = vp; - np->n_mount = VFSTOSMBFS(mp); - np->n_nmlen = nmlen; - np->n_name = smbfs_name_alloc(name, nmlen); - np->n_ino = fap->fa_ino; - np->n_size = fap->fa_size; - - /* new file vnode has to have a parent */ - KASSERT(vp->v_type != VREG || dvp != NULL); - - /* Not on hash list, add it now */ - LIST_INSERT_HEAD(nhpp, np, n_hash); - uvm_vnp_setsize(vp, np->n_size); - mutex_exit(&smp->sm_hashlock); - - *vpp = vp; - return 0; -} - -int -smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen, - struct smbfattr *fap, struct vnode **vpp) -{ - struct vnode *vp = NULL; /* XXX gcc 4.8: maybe-uninitialized */ - int error; - - error = smbfs_node_alloc(mp, dvp, name, nmlen, fap, &vp); - if (error) - return error; if (fap) smbfs_attr_cacheenter(vp, fap); *vpp = vp; - return 0; + mutex_exit(&np->n_lock); + +out: + if (key != &small_key.u_key) + kmem_free(key, key_len); + return error; } /* @@ -263,22 +227,25 @@ smbfs_reclaim(void *v) SMBVDEBUG("%.*s,%d\n", (int) np->n_nmlen, np->n_name, vp->v_usecount); - mutex_enter(&smp->sm_hashlock); - dvp = (np->n_parent && (np->n_flag & NREFPARENT)) ? np->n_parent : NULL; - LIST_REMOVE(np, n_hash); - if (smp->sm_root == np) { SMBVDEBUG0("root vnode\n"); smp->sm_root = NULL; } + + vcache_remove(vp->v_mount, np->n_key, SMBFS_KEYSIZE(np->n_nmlen)); + genfs_node_destroy(vp); + + /* To interlock with smbfs_nget(). */ + mutex_enter(vp->v_interlock); vp->v_data = NULL; - mutex_exit(&smp->sm_hashlock); - if (np->n_name) - smbfs_name_free(np->n_name); + mutex_exit(vp->v_interlock); + + mutex_destroy(&np->n_lock); + kmem_free(np->n_key, SMBFS_KEYSIZE(np->n_nmlen)); pool_put(&smbfs_node_pool, np); if (dvp) { vrele(dvp); @@ -323,7 +290,7 @@ smbfs_inactive(void *v) np->n_flag &= ~NOPEN; smbfs_attr_cacheremove(vp); } - *ap->a_recycle = ((np->n_flag & NGONE) != 0); + *ap->a_recycle = ((vp->v_type == VNON) || (np->n_flag & NGONE) != 0); VOP_UNLOCK(vp); return (0); Index: src/sys/fs/smbfs/smbfs_node.h diff -u src/sys/fs/smbfs/smbfs_node.h:1.13 src/sys/fs/smbfs/smbfs_node.h:1.14 --- src/sys/fs/smbfs/smbfs_node.h:1.13 Wed Nov 28 13:34:24 2012 +++ src/sys/fs/smbfs/smbfs_node.h Sun Dec 21 10:48:53 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_node.h,v 1.13 2012/11/28 13:34:24 nakayama Exp $ */ +/* $NetBSD: smbfs_node.h,v 1.14 2014/12/21 10:48:53 hannken Exp $ */ /* * Copyright (c) 2000-2001, Boris Popov @@ -54,10 +54,19 @@ struct smbfs_fctx; +#define SMBFS_KEYSIZE(nmlen) (sizeof(struct smbkey) + (nmlen)) +struct smbkey { + struct vnode * k_parent; /* Parent vnode. */ + u_char k_nmlen; /* Name length. */ + u_char k_name[0]; /* Name (variable length). */ +} __packed; + struct smbnode { struct genfs_node n_gnode; + kmutex_t n_lock; + struct smbkey * n_key; int n_flag; - struct vnode * n_parent; +#define n_parent n_key->k_parent struct vnode * n_vnode; struct smbmount * n_mount; time_t n_attrage; /* attributes cache time */ @@ -70,12 +79,11 @@ struct smbnode { int n_dosattr; u_int16_t n_fid; /* file handle */ int n_rwstate; /* granted access mode */ - u_char n_nmlen; - u_char * n_name; +#define n_nmlen n_key->k_nmlen +#define n_name n_key->k_name struct smbfs_fctx * n_dirseq; /* ff context */ long n_dirofs; /* last ff offset */ struct lockf * n_lockf; /* Locking records of file */ - LIST_ENTRY(smbnode) n_hash; }; #define VTOSMB(vp) ((struct smbnode *)(vp)->v_data) @@ -85,9 +93,10 @@ struct smbfattr; int smbfs_inactive(void *); int smbfs_reclaim(void *); +int smbfs_loadvnode(struct mount *, struct vnode *, + const void *, size_t, const void **); int smbfs_nget(struct mount *, struct vnode *, const char *, int, struct smbfattr *, struct vnode **); -#define smbfs_hash(x, y) hash32_strn((x), (y), HASH32_STR_INIT) int smbfs_readvnode(struct vnode *, struct uio *, kauth_cred_t); int smbfs_writevnode(struct vnode *, struct uio *, kauth_cred_t, int); Index: src/sys/fs/smbfs/smbfs_smb.c diff -u src/sys/fs/smbfs/smbfs_smb.c:1.46 src/sys/fs/smbfs/smbfs_smb.c:1.47 --- src/sys/fs/smbfs/smbfs_smb.c:1.46 Sat Nov 15 18:52:44 2014 +++ src/sys/fs/smbfs/smbfs_smb.c Sun Dec 21 10:48:53 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_smb.c,v 1.46 2014/11/15 18:52:44 nakayama Exp $ */ +/* $NetBSD: smbfs_smb.c,v 1.47 2014/12/21 10:48:53 hannken Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -64,7 +64,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smbfs_smb.c,v 1.46 2014/11/15 18:52:44 nakayama Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smbfs_smb.c,v 1.47 2014/12/21 10:48:53 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -116,7 +116,7 @@ smbfs_getino(struct smbnode *dnp, const #endif u_int32_t ino; - ino = dnp->n_ino + smbfs_hash(name, nmlen); + ino = dnp->n_ino + hash32_strn(name, nmlen, HASH32_STR_INIT); if (ino <= 2) ino += 3; return ino; Index: src/sys/fs/smbfs/smbfs_vfsops.c diff -u src/sys/fs/smbfs/smbfs_vfsops.c:1.103 src/sys/fs/smbfs/smbfs_vfsops.c:1.104 --- src/sys/fs/smbfs/smbfs_vfsops.c:1.103 Mon Jul 14 16:29:50 2014 +++ src/sys/fs/smbfs/smbfs_vfsops.c Sun Dec 21 10:48:53 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_vfsops.c,v 1.103 2014/07/14 16:29:50 maxv Exp $ */ +/* $NetBSD: smbfs_vfsops.c,v 1.104 2014/12/21 10:48:53 hannken Exp $ */ /* * Copyright (c) 2000-2001, Boris Popov @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smbfs_vfsops.c,v 1.103 2014/07/14 16:29:50 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smbfs_vfsops.c,v 1.104 2014/12/21 10:48:53 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -88,6 +88,7 @@ struct vfsops smbfs_vfsops = { .vfs_statvfs = smbfs_statvfs, .vfs_sync = smbfs_sync, .vfs_vget = smbfs_vget, + .vfs_loadvnode = smbfs_loadvnode, .vfs_fhtovp = (void *)eopnotsupp, .vfs_vptofh = (void *)eopnotsupp, .vfs_init = smbfs_init, @@ -205,10 +206,6 @@ smbfs_mount(struct mount *mp, const char smp = malloc(sizeof(*smp), M_SMBFSDATA, M_WAITOK|M_ZERO); mp->mnt_data = smp; - smp->sm_hash = hashinit(desiredvnodes, HASH_LIST, true, - &smp->sm_hashlen); - - mutex_init(&smp->sm_hashlock, MUTEX_DEFAULT, IPL_NONE); smp->sm_share = ssp; smp->sm_root = NULL; smp->sm_args = *args; @@ -261,8 +258,6 @@ smbfs_unmount(struct mount *mp, int mntf smb_share_put(smp->sm_share, &scred); mp->mnt_data = NULL; - hashdone(smp->sm_hash, HASH_LIST, smp->sm_hashlen); - mutex_destroy(&smp->sm_hashlock); free(smp, M_SMBFSDATA); return 0; } @@ -295,14 +290,12 @@ smbfs_setroot(struct mount *mp) * Someone might have already set sm_root while we slept * in smb_lookup or vnode allocation. */ - if (smp->sm_root) - vput(vp); - else { + if (smp->sm_root) { + KASSERT(smp->sm_root == VTOSMB(vp)); + vrele(vp); + } else { vp->v_vflag |= VV_ROOT; smp->sm_root = VTOSMB(vp); - - /* Keep reference, but unlock */ - VOP_UNLOCK(vp); } return (0); Index: src/sys/fs/smbfs/smbfs_vnops.c diff -u src/sys/fs/smbfs/smbfs_vnops.c:1.92 src/sys/fs/smbfs/smbfs_vnops.c:1.93 --- src/sys/fs/smbfs/smbfs_vnops.c:1.92 Fri Nov 7 12:05:58 2014 +++ src/sys/fs/smbfs/smbfs_vnops.c Sun Dec 21 10:48:53 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_vnops.c,v 1.92 2014/11/07 12:05:58 nakayama Exp $ */ +/* $NetBSD: smbfs_vnops.c,v 1.93 2014/12/21 10:48:53 hannken Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -64,7 +64,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smbfs_vnops.c,v 1.92 2014/11/07 12:05:58 nakayama Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smbfs_vnops.c,v 1.93 2014/12/21 10:48:53 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -606,7 +606,6 @@ smbfs_create(void *v) error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, ap->a_vpp); if (error) goto out; - VOP_UNLOCK(*ap->a_vpp); cache_enter(dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); @@ -809,7 +808,6 @@ smbfs_mkdir(void *v) error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); if (error) goto out; - VOP_UNLOCK(vp); *ap->a_vpp = vp; out: @@ -1347,46 +1345,23 @@ smbfs_lookup(void *v) if (isdot) return (EISDIR); - if (flags & ISDOTDOT) - VOP_UNLOCK(dvp); error = smbfs_nget(mp, dvp, name, nmlen, &fattr, vpp); - if (flags & ISDOTDOT) - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); if (error) return (error); - if (*vpp != dvp) - VOP_UNLOCK(*vpp); return (0); } if (isdot) { - - /* - * "." lookup - */ vref(dvp); *vpp = dvp; - } else if (flags & ISDOTDOT) { - - /* - * ".." lookup - */ - VOP_UNLOCK(dvp); - error = smbfs_nget(mp, dvp, name, nmlen, NULL, vpp); - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); - if (error) { - return error; - } + error = 0; } else { - /* - * Other lookups. - */ - error = smbfs_nget(mp, dvp, name, nmlen, &fattr, vpp); - if (error) - return error; + error = smbfs_nget(mp, dvp, name, nmlen, + ((flags & ISDOTDOT) ? NULL : &fattr), vpp); } + if (error) + return error; - KASSERT(error == 0); if (cnp->cn_nameiop != DELETE || !islastcn) { VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_mtime.tv_sec; cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, @@ -1399,7 +1374,5 @@ smbfs_lookup(void *v) #endif } - if (*vpp != dvp) - VOP_UNLOCK(*vpp); return (0); }