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

Reply via email to