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.
This commit is contained in:
hannken 2017-05-28 16:36:37 +00:00
parent a8045334ce
commit 5dc331fb8e
3 changed files with 58 additions and 8 deletions

View File

@ -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;
}
}
@ -206,6 +208,54 @@ out:
return error;
}
/*
* 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
*/

View File

@ -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 *, struct vnode *,
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);

View File

@ -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