Module Name: src Committed By: hannken Date: Sun May 28 16:36:37 UTC 2017
Modified Files: src/sys/fs/smbfs: smbfs_node.c smbfs_node.h smbfs_vnops.c Log Message: When a vnode has an invalid type because the type changed on the server replace vgone() with new operation smbfs_uncache() that removes the vnode from the name cache and changes the vcache key to an unique and illegal key to prevent further lookups. To generate a diff of this commit: cvs rdiff -u -r1.57 -r1.58 src/sys/fs/smbfs/smbfs_node.c cvs rdiff -u -r1.15 -r1.16 src/sys/fs/smbfs/smbfs_node.h cvs rdiff -u -r1.94 -r1.95 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_node.c diff -u src/sys/fs/smbfs/smbfs_node.c:1.57 src/sys/fs/smbfs/smbfs_node.c:1.58 --- src/sys/fs/smbfs/smbfs_node.c:1.57 Fri May 26 14:34:20 2017 +++ src/sys/fs/smbfs/smbfs_node.c Sun May 28 16:36:37 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_node.c,v 1.57 2017/05/26 14:34:20 riastradh Exp $ */ +/* $NetBSD: smbfs_node.c,v 1.58 2017/05/28 16:36:37 hannken Exp $ */ /* * Copyright (c) 2000-2001 Boris Popov @@ -35,10 +35,11 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: smbfs_node.c,v 1.57 2017/05/26 14:34:20 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smbfs_node.c,v 1.58 2017/05/28 16:36:37 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/atomic.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/malloc.h> @@ -191,7 +192,8 @@ retry: if ((vp->v_type == VDIR && (np->n_dosattr & SMB_FA_DIR) == 0) || (vp->v_type == VREG && (np->n_dosattr & SMB_FA_DIR) != 0)) { mutex_exit(&np->n_lock); - vgone(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + smbfs_uncache(vp); goto retry; } } @@ -207,6 +209,54 @@ out: } /* + * Remove vnode that changed its type on the server from + * the vnode cache and the name cache. + */ +void +smbfs_uncache(struct vnode *vp) +{ + static uint32_t gen = 0; + int error __diagused; + char newname[10]; + struct mount *mp = vp->v_mount; + struct smbnode *np = VTOSMB(vp); + struct smbkey *key = np->n_key, *oldkey, *newkey; + int key_len = SMBFS_KEYSIZE(key->k_nmlen), newkey_len; + + /* Setup old key as current key. */ + oldkey = kmem_alloc(key_len, KM_SLEEP); + memcpy(oldkey, key, key_len); + + /* Setup new key as unique and illegal name with colon. */ + snprintf(newname, sizeof(newname), ":%08x", atomic_inc_uint_nv(&gen)); + newkey = kmem_alloc(SMBFS_KEYSIZE(strlen(newname)), KM_SLEEP); + newkey->k_parent = NULL; + newkey->k_nmlen = strlen(newname); + memcpy(newkey->k_name, newname, newkey->k_nmlen); + newkey_len = SMBFS_KEYSIZE(newkey->k_nmlen); + + /* Release parent and mark as gone. */ + if (np->n_parent && (np->n_flag & NREFPARENT)) { + vrele(np->n_parent); + np->n_flag &= ~NREFPARENT; + } + np->n_flag |= NGONE; + + /* Rekey the node. */ + error = vcache_rekey_enter(mp, vp, oldkey, key_len, newkey, newkey_len); + KASSERT(error == 0); + np->n_key = newkey; + vcache_rekey_exit(mp, vp, oldkey, key_len, newkey, newkey_len); + + /* Purge from name cache and cleanup. */ + cache_purge(vp); + kmem_free(key, key_len); + kmem_free(oldkey, key_len); + + vput(vp); +} + +/* * Free smbnode, and give vnode back to system */ int Index: src/sys/fs/smbfs/smbfs_node.h diff -u src/sys/fs/smbfs/smbfs_node.h:1.15 src/sys/fs/smbfs/smbfs_node.h:1.16 --- src/sys/fs/smbfs/smbfs_node.h:1.15 Fri Jan 2 09:48:01 2015 +++ src/sys/fs/smbfs/smbfs_node.h Sun May 28 16:36:37 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_node.h,v 1.15 2015/01/02 09:48:01 martin Exp $ */ +/* $NetBSD: smbfs_node.h,v 1.16 2017/05/28 16:36:37 hannken Exp $ */ /* * Copyright (c) 2000-2001, Boris Popov @@ -97,6 +97,7 @@ int smbfs_loadvnode(struct mount *, stru const void *, size_t, const void **); int smbfs_nget(struct mount *, struct vnode *, const char *, int, struct smbfattr *, struct vnode **); +void smbfs_uncache(struct vnode *); 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_vnops.c diff -u src/sys/fs/smbfs/smbfs_vnops.c:1.94 src/sys/fs/smbfs/smbfs_vnops.c:1.95 --- src/sys/fs/smbfs/smbfs_vnops.c:1.94 Wed Apr 26 03:02:48 2017 +++ src/sys/fs/smbfs/smbfs_vnops.c Sun May 28 16:36:37 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: smbfs_vnops.c,v 1.94 2017/04/26 03:02:48 riastradh Exp $ */ +/* $NetBSD: smbfs_vnops.c,v 1.95 2017/05/28 16:36:37 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.94 2017/04/26 03:02:48 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: smbfs_vnops.c,v 1.95 2017/05/28 16:36:37 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -1269,8 +1269,7 @@ smbfs_lookup(void *v) cache_purge(newvp); if (newvp != dvp) { if (killit) { - VOP_UNLOCK(newvp); - vgone(newvp); + smbfs_uncache(newvp); } else vput(newvp); } else