Subject: Now: Fs suspension take 2
To: Bill Studenmund <wrstuden@netbsd.org>
From: Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
List: tech-kern
Date: 08/03/2006 16:11:29
--bp/iNruPH9dso1Pn
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Wed, Jul 05, 2006 at 10:30:32AM -0700, Bill Studenmund wrote:
> On Tue, Jul 04, 2006 at 04:23:55PM +0200, Juergen Hannken-Illjes wrote:
> > On Mon, Jul 03, 2006 at 03:51:35PM -0700, Jason Thorpe wrote:

[snip]

> > 2) Put all gates inside the file systems as
> 
> My preference.

Ok, the attached diff puts transaction locks so we can suspend ffs file systems.

- The fstrans implementation goes to files sys/fstrans.h and kern/vfs_trans.c.

- Add new VFS operation VFS_SUSPENDCTL(MP, C) to request a file system to
  suspend/resume.

- Transaction locks are used if mnt_iflag has IMNT_HAS_TRANS.  Otherwise the
  current (vn_start_write) are used.  With this diff IMNT_HAS_TRANS gets
  set for ffs type file systems if kernel option NEWVNGATE is set.

- The ufs_lock/ufs_unlock part may look strange but it is ok to ignore
  vnode lock requests for the thread currently suspending.

- I left the throttling part of my first attempt because it is only needed
  for multiple softdep enabled file systems on the same disk.  This problem
  should be solved by a congestion control inside softdep.

-- 
Juergen Hannken-Illjes - hannken@eis.cs.tu-bs.de - TU Braunschweig (Germany)

--bp/iNruPH9dso1Pn
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="Current.diff"

Index: sys/sys/fstrans.h
--- /dev/null	2006-07-30 17:17:49.000000000 +0200
+++ sys/sys/fstrans.h	2006-07-28 16:53:32.000000000 +0200
@@ -0,0 +1,64 @@
+/*	$NetBSD: Exp $	*/
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Juergen Hannken-Illjes.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * File system transaction operations.
+ */
+
+#ifndef _SYS_FSTRANS_H_
+#define	_SYS_FSTRANS_H_
+
+#define	FSTRANS_NOWAIT	0x0001		/* fstrans_*: no wait */
+#define	FSTRANS_SHARED	0x0002		/* fstrans_*: shared lock */
+#define	FSTRANS_EXCL	0x0004		/* fstrans_*: exclusive lock */
+
+#define SUSPEND_SUSPEND	0x0001		/* VFS_SUSPENDCTL: suspend */
+#define SUSPEND_RESUME	0x0002		/* VFS_SUSPENDCTL: resume */
+
+int	fstrans_start(struct mount *, int);
+void	fstrans_done(struct mount *);
+int	fstrans_status(struct mount *, int);
+void	fstrans_exit(struct lwp *);
+#ifdef DEBUG
+void	fstrans_list_all(void);
+#endif
+
+int	vfs_suspend(struct mount *, int);
+void	vfs_resume(struct mount *);
+
+#endif /* _SYS_FSTRANS_H_ */
Index: sys/sys/fstypes.h
===================================================================
RCS file: /cvsroot/src/sys/sys/fstypes.h,v
retrieving revision 1.12
diff -p -u -4 -r1.12 fstypes.h
--- sys/sys/fstypes.h	14 Jul 2006 18:30:35 -0000	1.12
+++ sys/sys/fstypes.h	30 Jul 2006 16:54:08 -0000
@@ -205,8 +205,9 @@ typedef struct fhandle	fhandle_t;
 #define	IMNT_SUSPEND	0x00000008	/* request upper write suspension */
 #define	IMNT_SUSPENDLOW	0x00000010	/* request lower write suspension */
 #define	IMNT_SUSPENDED	0x00000020	/* write operations are suspended */
 #define	IMNT_DTYPE	0x00000040	/* returns d_type fields */
+#define	IMNT_HAS_TRANS	0x00000080	/* supports transactions */
 
 #define __MNT_FLAGS \
 	__MNT_BASIC_FLAGS \
 	__MNT_EXPORTED_FLAGS \
@@ -249,8 +250,9 @@ typedef struct fhandle	fhandle_t;
 	"\01MNT_RDONLY"
 
 #define __IMNT_FLAG_BITS \
 	"\20" \
+	"\10IMNT_HAS_TRANS" \
 	"\07IMNT_DTYPE" \
 	"\06IMNT_SUSPENDED" \
 	"\05IMNT_SUSPENDLOW" \
 	"\04IMNT_SUSPEND" \
Index: sys/sys/lwp.h
===================================================================
RCS file: /cvsroot/src/sys/sys/lwp.h,v
retrieving revision 1.40
diff -p -u -4 -r1.40 lwp.h
--- sys/sys/lwp.h	20 Jul 2006 00:17:10 -0000	1.40
+++ sys/sys/lwp.h	30 Jul 2006 16:54:09 -0000
@@ -74,8 +74,9 @@ struct	lwp {
 	int	l_holdcnt;	/* If non-zero, don't swap. */
 	void	*l_ctxlink;	/* uc_link {get,set}context */
 	int	l_dupfd;	/* Sideways return value from cloning devices XXX */
 	struct sadata_vp *l_savp; /* SA "virtual processor" */
+	void	*l_vntrans;	/* vn_trans private data */
 
 	int	l_locks;       	/* DEBUG: lockmgr count of held locks */
 	void	*l_private;	/* svr4-style lwp-private data */
 
Index: sys/sys/mount.h
===================================================================
RCS file: /cvsroot/src/sys/sys/mount.h,v
retrieving revision 1.146
diff -p -u -4 -r1.146 mount.h
--- sys/sys/mount.h	14 Jul 2006 18:29:40 -0000	1.146
+++ sys/sys/mount.h	30 Jul 2006 16:54:09 -0000
@@ -97,8 +97,9 @@ struct mount {
 	struct vnode	*mnt_vnodecovered;	/* vnode we mounted on */
 	struct vnode	*mnt_syncer;		/* syncer vnode */
 	struct vnodelst	mnt_vnodelist;		/* list of vnodes this mount */
 	struct lock	mnt_lock;		/* mount structure lock */
+	struct lock	mnt_trans_lock;		/* mount transaction lock */
 	int		mnt_flag;		/* flags */
 	int		mnt_iflag;		/* internal flags */
 	int		mnt_fs_bshift;		/* offset shift for lblkno */
 	int		mnt_dev_bshift;		/* shift for device sectors */
@@ -208,8 +209,9 @@ struct vfsops {
 				    struct timespec *);
 	int	(*vfs_extattrctl) (struct mount *, int,
 				    struct vnode *, int, const char *,
 				    struct lwp *);
+	int	(*vfs_suspendctl) (struct mount *, int);
 	const struct vnodeopv_desc * const *vfs_opv_descs;
 	int	vfs_refcount;
 	LIST_ENTRY(vfsops) vfs_list;
 };
@@ -229,8 +231,9 @@ struct vfsops {
 #define	VFS_VPTOFH(VP, FIDP, FIDSZP)  (*(VP)->v_mount->mnt_op->vfs_vptofh)(VP, FIDP, FIDSZP)
 #define VFS_SNAPSHOT(MP, VP, TS)  (*(MP)->mnt_op->vfs_snapshot)(MP, VP, TS)
 #define	VFS_EXTATTRCTL(MP, C, VP, AS, AN, L) \
 	(*(MP)->mnt_op->vfs_extattrctl)(MP, C, VP, AS, AN, L)
+#define VFS_SUSPENDCTL(MP, C)     (*(MP)->mnt_op->vfs_suspendctl)(MP, C)
 
 struct vfs_hooks {
 	void	(*vh_unmount)(struct mount *);
 };
@@ -289,8 +292,9 @@ void	vfs_reinit(void);
 struct vfsops *vfs_getopsbyname(const char *);
 
 int	vfs_stdextattrctl(struct mount *, int, struct vnode *,
 	    int, const char *, struct lwp *);
+int	vfs_stdsuspendctl(struct mount *, int);
 
 extern	CIRCLEQ_HEAD(mntlist, mount) mountlist;	/* mounted filesystem list */
 extern	struct vfsops *vfssw[];			/* filesystem type table */
 extern	int nvfssw;
Index: sys/sys/vnode.h
===================================================================
RCS file: /cvsroot/src/sys/sys/vnode.h,v
retrieving revision 1.155
diff -p -u -4 -r1.155 vnode.h
--- sys/sys/vnode.h	23 Jun 2006 14:13:02 -0000	1.155
+++ sys/sys/vnode.h	30 Jul 2006 16:54:09 -0000
@@ -493,17 +493,8 @@ struct vop_generic_args {
 #define	VDESC(OP) (& __CONCAT(OP,_desc))
 #define	VOFFSET(OP) (VDESC(OP)->vdesc_offset)
 
 /*
- * Functions to gate filesystem write operations. Declared static inline
- * here because they usually go into time critical code paths.
- */
-#include <sys/mount.h>
-
-int vn_start_write(struct vnode *, struct mount **, int);
-void vn_finished_write(struct mount *, int);
-
-/*
  * Finally, include the default set of vnode operations.
  */
 #include <sys/vnode_if.h>
 
@@ -571,8 +562,10 @@ int	vn_cow_establish(struct vnode *, int
             void *);
 int	vn_cow_disestablish(struct vnode *, int (*)(void *, struct buf *),
             void *);
 void	vn_ra_allocctx(struct vnode *);
+int	vn_start_write(struct vnode *, struct mount **, int);
+void	vn_finished_write(struct mount *, int);
 
 /* initialise global vnode management */
 void	vntblinit(void);
 
@@ -586,10 +579,8 @@ int	getvnode(struct filedesc *, int, str
 
 /* see vfssubr(9) */
 void	vfs_getnewfsid(struct mount *);
 int	vfs_drainvnodes(long target, struct lwp *);
-void	vfs_write_resume(struct mount *);
-int	vfs_write_suspend(struct mount *, int, int);
 void	vfs_timestamp(struct timespec *);
 #ifdef DDB
 void	vfs_vnode_print(struct vnode *, int, void (*)(const char *, ...));
 void	vfs_mount_print(struct mount *, int, void (*)(const char *, ...));
Index: sys/kern/vfs_trans.c
--- /dev/null	2006-07-30 17:17:49.000000000 +0200
+++ sys/kern/vfs_trans.c	2006-07-30 17:51:51.000000000 +0200
@@ -0,0 +1,322 @@
+/*	$NetBSD: Exp $	*/
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Juergen Hannken-Illjes.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: $");
+
+/*
+ * File system transaction operations.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/fstrans.h>
+
+#include <miscfs/syncfs/syncfs.h>
+
+struct fstrans_entry {
+	struct fstrans_entry *fte_succ;
+	struct mount *fte_mount;
+	int fte_count;
+	int fte_flags;
+};
+
+static struct lock vfs_suspend_lock =	/* Serialize suspensions. */
+    LOCK_INITIALIZER(PUSER, "suspwt", 0, 0);
+
+POOL_INIT(fstrans_pl, sizeof(struct fstrans_entry), 0, 0, 0, "vntrans", NULL);
+
+/*
+ * Clear transition locks on thread exit.
+ */
+void
+fstrans_exit(struct lwp *l)
+{
+	struct fstrans_entry *fte, *ftn;
+
+	for (fte = l->l_vntrans; fte; fte = ftn) {
+		KASSERT(fte->fte_mount == NULL);
+		KASSERT(fte->fte_count == 0);
+		ftn = fte->fte_succ;
+		pool_put(&fstrans_pl, fte);
+	}
+}
+
+/*
+ * Start a transaction.  If this thread already has a transaction on this
+ * file system increment the reference counter.
+ * A thread with an exclusive transaction lock may get a shared one.
+ * A thread with a shared transaction lock cannot get an exclusive one.
+ */
+int
+fstrans_start(struct mount *mp, int flags)
+{
+	int error, lflags, pflags;
+	struct fstrans_entry *fte, *new_fte;
+
+	KASSERT((flags & (FSTRANS_SHARED | FSTRANS_EXCL)) == FSTRANS_SHARED ||
+	    (flags & (FSTRANS_SHARED | FSTRANS_EXCL)) == FSTRANS_EXCL);
+
+	pflags = 0;
+	lflags = (flags & FSTRANS_SHARED) ? LK_SHARED : LK_EXCLUSIVE;
+	if ((flags & FSTRANS_NOWAIT) != 0) {
+		pflags |= PR_NOWAIT;
+		lflags |= LK_NOWAIT;
+	}
+
+	if (mp == NULL)
+		return 0;
+	if ((mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
+		return 0;
+
+	new_fte = NULL;
+	for (fte = curlwp->l_vntrans; fte; fte = fte->fte_succ) {
+		if (fte->fte_mount == NULL && new_fte == NULL)
+			new_fte = fte;
+		if (fte->fte_mount == mp) {
+			KASSERT(fte->fte_count > 0);
+			KASSERT(fte->fte_flags != 0);
+			if (fte->fte_flags == FSTRANS_SHARED &&
+			    (flags & FSTRANS_EXCL) == FSTRANS_EXCL)
+				panic("fstrans_start: cannot upgrade lock");
+			fte->fte_count += 1;
+			return 0;
+		}
+	}
+
+	if (new_fte == NULL) {
+		if ((new_fte = pool_get(&fstrans_pl, pflags)) == NULL)
+			return EWOULDBLOCK;
+		new_fte->fte_mount = NULL;
+		new_fte->fte_count = 0;
+		new_fte->fte_flags = 0;
+		new_fte->fte_succ = curlwp->l_vntrans;
+		curlwp->l_vntrans = new_fte;
+	}
+
+	KASSERT(new_fte->fte_mount == NULL);
+	KASSERT(new_fte->fte_count == 0);
+
+	if ((error = lockmgr(&mp->mnt_trans_lock, lflags, NULL)) != 0)
+		return error;
+
+	new_fte->fte_mount = mp;
+	new_fte->fte_count = 1;
+	new_fte->fte_flags = (flags & (FSTRANS_SHARED | FSTRANS_EXCL));
+
+	return 0;
+}
+
+/*
+ * Finish a transaction.
+ */
+void
+fstrans_done(struct mount *mp)
+{
+	struct fstrans_entry *fte;
+
+	if (mp == NULL)
+		return;
+	if ((mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
+		return;
+
+	for (fte = curlwp->l_vntrans; fte; fte = fte->fte_succ) {
+		if (fte->fte_mount == mp) {
+			fte->fte_count -= 1;
+			if (fte->fte_count > 0)
+				return;
+			break;
+		}
+	}
+
+	KASSERT(fte != NULL);
+	KASSERT(fte->fte_mount == mp);
+	KASSERT(fte->fte_count == 0);
+	fte->fte_mount = NULL;
+	fte->fte_flags = 0;
+
+	lockmgr(&mp->mnt_trans_lock, LK_RELEASE, NULL);
+}
+
+/*
+ * Check if this thread has at least this level of transaction lock.
+ */
+int
+fstrans_status(struct mount *mp, int flags)
+{
+	struct fstrans_entry *fte;
+
+	KASSERT(flags == FSTRANS_SHARED || flags == FSTRANS_EXCL);
+
+	if (mp == NULL)
+		return 0;
+	if ((mp->mnt_iflag & IMNT_HAS_TRANS) == 0)
+		return 0;
+
+	for (fte = curlwp->l_vntrans; fte; fte = fte->fte_succ)
+		if (fte->fte_mount == mp)
+			break;
+
+	if (fte == NULL)
+		return 0;
+
+	KASSERT(fte->fte_mount == mp);
+	KASSERT(fte->fte_count > 0);
+	return (fte->fte_flags == flags ||
+	    (fte->fte_flags == FSTRANS_EXCL && flags == FSTRANS_SHARED));
+}
+
+/*
+ * Request a filesystem to suspend all operations.
+ */
+int
+vfs_suspend(struct mount *mp, int nowait)
+{
+	struct lwp *l = curlwp;	/* XXX */
+	int error, flags;
+
+	flags = LK_EXCLUSIVE;
+	if (nowait)
+		flags |= LK_NOWAIT;
+	if (lockmgr(&vfs_suspend_lock, flags, NULL) != 0)
+		return EWOULDBLOCK;
+
+	if ((mp->mnt_iflag & IMNT_HAS_TRANS) != 0) {
+		lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL);
+
+		if ((error = VFS_SUSPENDCTL(mp, SUSPEND_SUSPEND)) != 0)
+			lockmgr(&vfs_suspend_lock, LK_RELEASE, NULL);
+
+		return error;
+	}
+
+	KASSERT((mp->mnt_iflag &
+	    (IMNT_SUSPEND|IMNT_SUSPENDLOW|IMNT_SUSPENDED)) == 0);
+
+	mp->mnt_iflag |= IMNT_SUSPEND;
+
+	simple_lock(&mp->mnt_slock);
+	if (mp->mnt_writeopcountupper > 0)
+		ltsleep(&mp->mnt_writeopcountupper, PUSER - 1, "suspwt",
+			0, &mp->mnt_slock);
+	simple_unlock(&mp->mnt_slock);
+
+	error = VFS_SYNC(mp, MNT_WAIT, l->l_proc->p_cred, l);
+	if (error) {
+		vfs_resume(mp);
+		return error;
+	}
+	mp->mnt_iflag |= IMNT_SUSPENDLOW;
+
+	simple_lock(&mp->mnt_slock);
+	if (mp->mnt_writeopcountlower > 0)
+		ltsleep(&mp->mnt_writeopcountlower, PUSER - 1, "suspwt",
+			0, &mp->mnt_slock);
+	mp->mnt_iflag |= IMNT_SUSPENDED;
+	simple_unlock(&mp->mnt_slock);
+
+	return 0;
+}
+
+/*
+ * Request a filesystem to resume all operations.
+ */
+void
+vfs_resume(struct mount *mp)
+{
+
+	if ((mp->mnt_iflag & IMNT_HAS_TRANS) != 0) {
+		VFS_SUSPENDCTL(mp, SUSPEND_RESUME);
+		lockmgr(&syncer_lock, LK_RELEASE, NULL);
+		lockmgr(&vfs_suspend_lock, LK_RELEASE, NULL);
+		return;
+	}
+
+	if ((mp->mnt_iflag & IMNT_SUSPEND) == 0)
+		return;
+	mp->mnt_iflag &= ~(IMNT_SUSPEND | IMNT_SUSPENDLOW | IMNT_SUSPENDED);
+	wakeup(&mp->mnt_flag);
+
+	lockmgr(&vfs_suspend_lock, LK_RELEASE, NULL);
+}
+
+/*
+ * Default vfs_suspendctl routine for file systems that do not support it.
+ */
+/*ARGSUSED*/
+int
+vfs_stdsuspendctl(struct mount *mp, int mode)
+{
+	return EOPNOTSUPP;
+}
+
+#ifdef DEBUG
+static void
+fstrans_print(struct proc *p, struct lwp *l)
+{
+	char prefix[9];
+	struct fstrans_entry *fte;
+
+	snprintf(prefix, sizeof(prefix), "%d.%d", p->p_pid, l->l_lid);
+	for (fte = l->l_vntrans; fte; fte = fte->fte_succ) {
+		if (fte->fte_count == 0)
+			continue;
+		printf("%-8s (%s) %s %d\n", prefix,
+		    fte->fte_mount->mnt_stat.f_mntonname,
+		    fte->fte_flags == FSTRANS_SHARED ? "shared" : "excl",
+		    fte->fte_count);
+		prefix[0] = '\0';
+	}
+}
+
+void
+fstrans_list_all(void)
+{
+	const struct proclist_desc *pd;
+	struct proc *p;
+	struct lwp *l;
+
+	printf("Fstrans locks by lwp:\n");
+	for (pd = proclists; pd->pd_list != NULL; pd++)
+		LIST_FOREACH(p, pd->pd_list, p_list)
+			LIST_FOREACH(l, &p->p_lwps, l_sibling)
+				fstrans_print(p, l);
+}
+#endif
Index: sys/miscfs/genfs/genfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/genfs/genfs_vnops.c,v
retrieving revision 1.127
diff -p -u -4 -r1.127 genfs_vnops.c
--- sys/miscfs/genfs/genfs_vnops.c	22 Jul 2006 08:49:13 -0000	1.127
+++ sys/miscfs/genfs/genfs_vnops.c	30 Jul 2006 16:54:08 -0000
@@ -49,8 +49,9 @@ __KERNEL_RCSID(0, "$NetBSD: genfs_vnops.
 #include <sys/poll.h>
 #include <sys/mman.h>
 #include <sys/file.h>
 #include <sys/kauth.h>
+#include <sys/fstrans.h>
 
 #include <miscfs/genfs/genfs.h>
 #include <miscfs/genfs/genfs_node.h>
 #include <miscfs/specfs/specdev.h>
@@ -457,8 +458,9 @@ genfs_getpages(void *v)
 	kauth_cred_t cred = curproc->p_cred;		/* XXXUBC curlwp */
 	boolean_t async = (flags & PGO_SYNCIO) == 0;
 	boolean_t write = (ap->a_access_type & VM_PROT_WRITE) != 0;
 	boolean_t sawhole = FALSE;
+	boolean_t has_trans = FALSE;
 	boolean_t overwrite = (flags & PGO_OVERWRITE) != 0;
 	boolean_t blockalloc = write && (flags & PGO_NOBLOCKALLOC) == 0;
 	voff_t origvsize;
 	UVMHIST_FUNC("genfs_getpages"); UVMHIST_CALLED(ubchist);
@@ -714,8 +716,15 @@ startover:
 	/*
 	 * read the desired page(s).
 	 */
 
+	if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0) {
+		if (pgs != pgs_onstack)
+			free(pgs, M_DEVBUF);
+		return error;
+	}
+	has_trans = TRUE;
+
 	totalbytes = npages << PAGE_SHIFT;
 	bytes = MIN(totalbytes, MAX(diskeof - startoffset, 0));
 	tailbytes = totalbytes - bytes;
 	skipbytes = 0;
@@ -877,8 +886,10 @@ loopdone:
 		UVMHIST_LOG(ubchist, "returning 0 (async)",0,0,0,0);
 		lockmgr(&gp->g_glock, LK_RELEASE, NULL);
 		if (pgs != pgs_onstack)
 			free(pgs, M_DEVBUF);
+		if (has_trans)
+			fstrans_done(vp->v_mount);
 		return (0);
 	}
 	if (bp != NULL) {
 		error = biowait(mbp);
@@ -937,8 +948,10 @@ loopdone:
 		simple_unlock(&uobj->vmobjlock);
 		UVMHIST_LOG(ubchist, "returning error %d", error,0,0,0);
 		if (pgs != pgs_onstack)
 			free(pgs, M_DEVBUF);
+		if (has_trans)
+			fstrans_done(vp->v_mount);
 		return (error);
 	}
 
 out:
@@ -982,8 +995,10 @@ out:
 		    orignpages * sizeof(struct vm_page *));
 	}
 	if (pgs != pgs_onstack)
 		free(pgs, M_DEVBUF);
+	if (has_trans)
+		fstrans_done(vp->v_mount);
 	return (0);
 }
 
 /*
@@ -1063,9 +1078,12 @@ genfs_putpages(void *v)
 	boolean_t pagedaemon = curproc == uvm.pagedaemon_proc;
 	struct lwp *l = curlwp ? curlwp : &lwp0;
 	struct genfs_node *gp = VTOG(vp);
 	int dirtygen;
+	int tflag = (flags & (PGO_SYNCIO|PGO_CLEANIT)) != 0 ?
+	    FSTRANS_SHARED : (FSTRANS_SHARED|FSTRANS_NOWAIT);
 	boolean_t modified = FALSE;
+	boolean_t has_trans = FALSE;
 	boolean_t cleanall;
 
 	UVMHIST_FUNC("genfs_putpages"); UVMHIST_CALLED(ubchist);
 
@@ -1374,9 +1392,13 @@ genfs_putpages(void *v)
 				TAILQ_INSERT_AFTER(&uobj->memq, pg, &curmp,
 				    listq);
 			}
 			simple_unlock(slock);
-			error = GOP_WRITE(vp, pgs, npages, flags);
+			if (!has_trans &&
+			    (error = fstrans_start(vp->v_mount, tflag)) == 0)
+				has_trans = TRUE;
+			if (has_trans)
+				error = GOP_WRITE(vp, pgs, npages, flags);
 			simple_lock(slock);
 			if (by_list) {
 				pg = TAILQ_NEXT(&curmp, listq);
 				TAILQ_REMOVE(&uobj->memq, &curmp, listq);
@@ -1454,8 +1476,12 @@ skip_scan:
 		}
 		splx(s);
 	}
 	simple_unlock(&uobj->vmobjlock);
+
+	if (has_trans)
+		fstrans_done(vp->v_mount);
+
 	return (error);
 }
 
 int
Index: sys/ufs/ufs/ufs_bmap.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_bmap.c,v
retrieving revision 1.40
diff -p -u -4 -r1.40 ufs_bmap.c
--- sys/ufs/ufs/ufs_bmap.c	4 Apr 2006 17:12:57 -0000	1.40
+++ sys/ufs/ufs/ufs_bmap.c	30 Jul 2006 16:54:12 -0000
@@ -46,8 +46,9 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_bmap.c,v
 #include <sys/vnode.h>
 #include <sys/mount.h>
 #include <sys/resourcevar.h>
 #include <sys/trace.h>
+#include <sys/fstrans.h>
 
 #include <miscfs/specfs/specdev.h>
 
 #include <ufs/ufs/inode.h>
@@ -80,8 +81,10 @@ ufs_bmap(void *v)
 		struct vnode **a_vpp;
 		daddr_t *a_bnp;
 		int *a_runp;
 	} */ *ap = v;
+	int error;
+
 	/*
 	 * Check for underlying vnode requests and ensure that logical
 	 * to physical mapping is requested.
 	 */
@@ -89,10 +92,14 @@ ufs_bmap(void *v)
 		*ap->a_vpp = VTOI(ap->a_vp)->i_devvp;
 	if (ap->a_bnp == NULL)
 		return (0);
 
-	return (ufs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL,
-	    ap->a_runp, ufs_issequential));
+	if ((error = fstrans_start(ap->a_vp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
+	error = ufs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL,
+	    ap->a_runp, ufs_issequential);
+	fstrans_done(ap->a_vp->v_mount);
+	return error;
 }
 
 /*
  * Indirect blocks are now on the vnode for the file.  They are given negative
Index: sys/ufs/ufs/ufs_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_extern.h,v
retrieving revision 1.49
diff -p -u -4 -r1.49 ufs_extern.h
--- sys/ufs/ufs/ufs_extern.h	14 May 2006 21:33:39 -0000	1.49
+++ sys/ufs/ufs/ufs_extern.h	30 Jul 2006 16:54:12 -0000
@@ -65,12 +65,12 @@ int	ufs_create(void *);
 int	ufs_getattr(void *);
 int	ufs_inactive(void *);
 #define	ufs_fcntl	genfs_fcntl
 #define	ufs_ioctl	genfs_enoioctl
-#define	ufs_islocked	genfs_islocked
+int	ufs_islocked(void *);
 #define	ufs_lease_check genfs_lease_check
 int	ufs_link(void *);
-#define ufs_lock	genfs_lock
+int	ufs_lock(void *);
 int	ufs_lookup(void *);
 int	ufs_mkdir(void *);
 int	ufs_mknod(void *);
 #define	ufs_mmap	genfs_mmap
@@ -87,9 +87,9 @@ int	ufs_rmdir(void *);
 #define	ufs_poll	genfs_poll
 int	ufs_setattr(void *);
 int	ufs_strategy(void *);
 int	ufs_symlink(void *);
-#define ufs_unlock	genfs_unlock
+int	ufs_unlock(void *);
 int	ufs_whiteout(void *);
 int	ufsspec_close(void *);
 int	ufsspec_read(void *);
 int	ufsspec_write(void *);
Index: sys/ufs/ufs/ufs_inode.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_inode.c,v
retrieving revision 1.59
diff -p -u -4 -r1.59 ufs_inode.c
--- sys/ufs/ufs/ufs_inode.c	14 May 2006 21:33:39 -0000	1.59
+++ sys/ufs/ufs/ufs_inode.c	30 Jul 2006 16:54:12 -0000
@@ -51,8 +51,9 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,
 #include <sys/mount.h>
 #include <sys/kernel.h>
 #include <sys/namei.h>
 #include <sys/kauth.h>
+#include <sys/fstrans.h>
 
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/ufsmount.h>
@@ -79,16 +80,19 @@ ufs_inactive(void *v)
 		struct lwp *a_l;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
 	struct inode *ip = VTOI(vp);
-	struct mount *mp;
+	struct mount *mp, *transmp;
 	struct lwp *l = ap->a_l;
 	mode_t mode;
 	int error = 0;
 
 	if (prtactive && vp->v_usecount != 0)
 		vprint("ufs_inactive: pushing active", vp);
 
+	transmp = vp->v_mount;
+	if ((error = fstrans_start(transmp, FSTRANS_SHARED)) != 0)
+		return error;
 	/*
 	 * Ignore inodes related to stale file handles.
 	 */
 	if (ip->i_mode == 0)
@@ -141,8 +145,9 @@ out:
 	 */
 
 	if (ip->i_mode == 0)
 		vrecycle(vp, NULL, l);
+	fstrans_done(transmp);
 	return (error);
 }
 
 /*
Index: sys/ufs/ufs/ufs_lookup.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_lookup.c,v
retrieving revision 1.78
diff -p -u -4 -r1.78 ufs_lookup.c
--- sys/ufs/ufs/ufs_lookup.c	23 Jun 2006 14:13:02 -0000	1.78
+++ sys/ufs/ufs/ufs_lookup.c	30 Jul 2006 16:54:12 -0000
@@ -52,8 +52,9 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c
 #include <sys/mount.h>
 #include <sys/vnode.h>
 #include <sys/kernel.h>
 #include <sys/kauth.h>
+#include <sys/fstrans.h>
 
 #include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>
 #ifdef UFS_DIRHASH
@@ -150,17 +151,21 @@ ufs_lookup(void *v)
 	*vpp = NULL;
 	lockparent = flags & LOCKPARENT;
 	wantparent = flags & (LOCKPARENT|WANTPARENT);
 	endsearch = 0; /* silence compiler warning */
+	if ((error = fstrans_start(vdp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
 	/*
 	 * Check accessiblity of directory.
 	 */
 	if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_lwp)) != 0)
-		return (error);
+		goto out;
 
 	if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
-	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
-		return (EROFS);
+	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
+		error = EROFS;
+		goto out;
+	}
 
 	/*
 	 * We now have a segment name to search for, and a directory to search.
 	 *
@@ -168,9 +173,9 @@ ufs_lookup(void *v)
 	 * check the name cache to see if the directory/name pair
 	 * we are looking for is known already.
 	 */
 	if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
-		return (error);
+		goto out;
 
 	/*
 	 * Suppress search for slots unless creating
 	 * file and at end of pathname, in which case
@@ -245,9 +250,9 @@ ufs_lookup(void *v)
 	} else {
 		dp->i_offset = dp->i_diroff;
 		if ((entryoffsetinblock = dp->i_offset & bmask) &&
 		    (error = ufs_blkatoff(vdp, (off_t)dp->i_offset, NULL, &bp)))
-			return (error);
+			goto out;
 		numdirpasses = 2;
 		nchstats.ncs_2passes++;
 	}
 	prevoff = dp->i_offset;
@@ -266,9 +271,9 @@ searchloop:
 				brelse(bp);
 			error = ufs_blkatoff(vdp, (off_t)dp->i_offset, NULL,
 			    &bp);
 			if (error)
-				return (error);
+				goto out;
 			entryoffsetinblock = 0;
 		}
 		/*
 		 * If still looking for a slot, and at a DIRBLKSIZE
@@ -423,9 +428,9 @@ notfound:
 		 * creation of files in the directory.
 		 */
 		error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_lwp);
 		if (error)
-			return (error);
+			goto out;
 		/*
 		 * Return an indication of where the new directory
 		 * entry should be put.  If we didn't find a slot,
 		 * then set dp->i_count to 0 indicating
@@ -471,16 +476,18 @@ notfound:
 		if (!lockparent) {
 			VOP_UNLOCK(vdp, 0);
 			cnp->cn_flags |= PDIRUNLOCK;
 		}
-		return (EJUSTRETURN);
+		error = EJUSTRETURN;
+		goto out;
 	}
 	/*
 	 * Insert name into cache (as non-existent) if appropriate.
 	 */
 	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
 		cache_enter(vdp, *vpp, cnp);
-	return (ENOENT);
+	error = ENOENT;
+	goto out;
 
 found:
 	if (numdirpasses == 2)
 		nchstats.ncs_pass2++;
@@ -516,9 +523,9 @@ found:
 		 * Write access to directory required to delete files.
 		 */
 		error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_lwp);
 		if (error)
-			return (error);
+			goto out;
 		/*
 		 * Return pointer to current entry in dp->i_offset,
 		 * and distance past previous entry (if there
 		 * is a previous entry in this block) in dp->i_count.
@@ -530,17 +537,18 @@ found:
 			dp->i_count = dp->i_offset - prevoff;
 		if (dp->i_number == foundino) {
 			VREF(vdp);
 			*vpp = vdp;
-			return (0);
+			error = 0;
+			goto out;
 		}
 		if (flags & ISDOTDOT)
 			VOP_UNLOCK(vdp, 0); /* race to get the inode */
 		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
 		if (flags & ISDOTDOT)
 			vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
 		if (error)
-			return (error);
+			goto out;
 		/*
 		 * If directory is "sticky", then user must own
 		 * the directory, or the file in it, else she
 		 * may not delete it (unless she's root). This
@@ -550,16 +558,18 @@ found:
 		    kauth_cred_geteuid(cred) != 0 &&
 		    kauth_cred_geteuid(cred) != dp->i_uid &&
 		    VTOI(tdp)->i_uid != kauth_cred_geteuid(cred)) {
 			vput(tdp);
-			return (EPERM);
+			error = EPERM;
+			goto out;
 		}
 		*vpp = tdp;
 		if (!lockparent) {
 			VOP_UNLOCK(vdp, 0);
 			cnp->cn_flags |= PDIRUNLOCK;
 		}
-		return (0);
+		error = 0;
+		goto out;
 	}
 
 	/*
 	 * If rewriting (RENAME), return the inode and the
@@ -569,29 +579,32 @@ found:
 	 */
 	if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
 		error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_lwp);
 		if (error)
-			return (error);
+			goto out;
 		/*
 		 * Careful about locking second inode.
 		 * This can only occur if the target is ".".
 		 */
-		if (dp->i_number == foundino)
-			return (EISDIR);
+		if (dp->i_number == foundino) {
+			error = EISDIR;
+			goto out;
+		}
 		if (flags & ISDOTDOT)
 			VOP_UNLOCK(vdp, 0); /* race to get the inode */
 		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
 		if (flags & ISDOTDOT)
 			vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
 		if (error)
-			return (error);
+			goto out;
 		*vpp = tdp;
 		cnp->cn_flags |= SAVENAME;
 		if (!lockparent) {
 			VOP_UNLOCK(vdp, 0);
 			cnp->cn_flags |= PDIRUNLOCK;
 		}
-		return (0);
+		error = 0;
+		goto out;
 	}
 
 	/*
 	 * Step through the translation in the name.  We do not `vput' the
@@ -619,14 +632,14 @@ found:
 		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
 		if (error) {
 			if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY) == 0)
 				cnp->cn_flags &= ~PDIRUNLOCK;
-			return (error);
+			goto out;
 		}
 		if (lockparent && (flags & ISLASTCN)) {
 			if ((error = vn_lock(pdp, LK_EXCLUSIVE))) {
 				vput(tdp);
-				return (error);
+				goto out;
 			}
 			cnp->cn_flags &= ~PDIRUNLOCK;
 		}
 		*vpp = tdp;
@@ -635,9 +648,9 @@ found:
 		*vpp = vdp;
 	} else {
 		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
 		if (error)
-			return (error);
+			goto out;
 		if (!lockparent || !(flags & ISLASTCN)) {
 			VOP_UNLOCK(pdp, 0);
 			cnp->cn_flags |= PDIRUNLOCK;
 		}
@@ -648,9 +661,13 @@ found:
 	 * Insert name into cache if appropriate.
 	 */
 	if (cnp->cn_flags & MAKEENTRY)
 		cache_enter(vdp, *vpp, cnp);
-	return (0);
+	error = 0;
+
+out:
+	fstrans_done(vdp->v_mount);
+	return error;
 }
 
 void
 ufs_dirbad(struct inode *ip, doff_t offset, const char *how)
Index: sys/ufs/ufs/ufs_readwrite.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_readwrite.c,v
retrieving revision 1.68
diff -p -u -4 -r1.68 ufs_readwrite.c
--- sys/ufs/ufs/ufs_readwrite.c	14 May 2006 21:33:39 -0000	1.68
+++ sys/ufs/ufs/ufs_readwrite.c	30 Jul 2006 16:54:12 -0000
@@ -102,8 +102,12 @@ READ(void *v)
 	if ((u_int64_t)uio->uio_offset > ump->um_maxfilesize)
 		return (EFBIG);
 	if (uio->uio_resid == 0)
 		return (0);
+
+	if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
+
 	if (uio->uio_offset >= ip->i_size)
 		goto out;
 
 #ifdef LFS_READWRITE
@@ -178,8 +182,10 @@ READ(void *v)
 		ip->i_flag |= IN_ACCESS;
 		if ((ap->a_ioflag & IO_SYNC) == IO_SYNC)
 			error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
 	}
+
+	fstrans_done(vp->v_mount);
 	return (error);
 }
 
 /*
@@ -271,8 +277,11 @@ WRITE(void *v)
 	}
 	if (uio->uio_resid == 0)
 		return (0);
 
+	if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
+
 	flags = ioflag & IO_SYNC ? B_SYNC : 0;
 	async = vp->v_mount->mnt_flag & MNT_ASYNC;
 	origoff = uio->uio_offset;
 	resid = uio->uio_resid;
@@ -496,6 +505,9 @@ out:
 		uio->uio_resid = resid;
 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
 		error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
 	KASSERT(vp->v_size == ip->i_size);
+
+	fstrans_done(vp->v_mount);
+
 	return (error);
 }
Index: sys/ufs/ufs/ufs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.141
diff -p -u -4 -r1.141 ufs_vnops.c
--- sys/ufs/ufs/ufs_vnops.c	7 Jun 2006 22:34:44 -0000	1.141
+++ sys/ufs/ufs/ufs_vnops.c	30 Jul 2006 16:54:12 -0000
@@ -59,8 +59,9 @@ __KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,
 #include <sys/malloc.h>
 #include <sys/dirent.h>
 #include <sys/lockf.h>
 #include <sys/kauth.h>
+#include <sys/fstrans.h>
 
 #include <miscfs/specfs/specdev.h>
 #include <miscfs/fifofs/fifo.h>
 
@@ -104,11 +105,14 @@ ufs_create(void *v)
 		struct vattr		*a_vap;
 	} */ *ap = v;
 	int	error;
 
+	if ((error = fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
 	error =
 	    ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
 			  ap->a_dvp, ap->a_vpp, ap->a_cnp);
+	fstrans_done(ap->a_dvp->v_mount);
 	if (error)
 		return (error);
 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
 	return (0);
@@ -135,12 +139,14 @@ ufs_mknod(void *v)
 	ino_t		ino;
 
 	vap = ap->a_vap;
 	vpp = ap->a_vpp;
+	if ((error = fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
 	if ((error =
 	    ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
 	    ap->a_dvp, vpp, ap->a_cnp)) != 0)
-		return (error);
+		goto out;
 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
 	ip = VTOI(*vpp);
 	mp  = (*vpp)->v_mount;
 	ino = ip->i_number;
@@ -166,8 +172,10 @@ ufs_mknod(void *v)
 	vput(*vpp);
 	(*vpp)->v_type = VNON;
 	vgone(*vpp);
 	error = VFS_VGET(mp, ino, vpp);
+out:
+	fstrans_done(ap->a_dvp->v_mount);
 	if (error != 0) {
 		*vpp = NULL;
 		return (error);
 	}
@@ -257,10 +265,15 @@ ufs_access(void *v)
 		case VREG:
 			if (vp->v_mount->mnt_flag & MNT_RDONLY)
 				return (EROFS);
 #ifdef QUOTA
-			if ((error = getinoquota(ip)) != 0)
-				return (error);
+			if ((error =
+			    fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0)
+				return error;
+			error = getinoquota(ip);
+			fstrans_done(vp->v_mount);
+			if (error != 0)
+				return error;
 #endif
 			break;
 		case VBAD:
 		case VBLK:
@@ -383,51 +396,71 @@ ufs_setattr(void *v)
 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
 	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
 		return (EINVAL);
 	}
+
+	if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
+
 	if (vap->va_flags != VNOVAL) {
-		if (vp->v_mount->mnt_flag & MNT_RDONLY)
-			return (EROFS);
+		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
+			error = EROFS;
+			goto out;
+		}
 		if (kauth_cred_geteuid(cred) != ip->i_uid &&
 		    (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
 					       &l->l_proc->p_acflag)))
-			return (error);
+			goto out;
 		if (kauth_cred_geteuid(cred) == 0) {
 			if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&
-			    securelevel > 0)
-				return (EPERM);
+			    securelevel > 0) {
+				error =  EPERM;
+				goto out;
+			}
 			/* Snapshot flag cannot be set or cleared */
 			if ((vap->va_flags & SF_SNAPSHOT) !=
-			    (ip->i_flags & SF_SNAPSHOT))
-				return (EPERM);
+			    (ip->i_flags & SF_SNAPSHOT)) {
+				error = EPERM;
+				goto out;
+			}
 			ip->i_flags = vap->va_flags;
 			DIP_ASSIGN(ip, flags, ip->i_flags);
 		} else {
 			if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) ||
-			    (vap->va_flags & UF_SETTABLE) != vap->va_flags)
-				return (EPERM);
+			    (vap->va_flags & UF_SETTABLE) != vap->va_flags) {
+				error = EPERM;
+				goto out;
+			}
 			if ((ip->i_flags & SF_SETTABLE) !=
-			    (vap->va_flags & SF_SETTABLE))
-				return (EPERM);
+			    (vap->va_flags & SF_SETTABLE)) {
+				error = EPERM;
+				goto out;
+			}
 			ip->i_flags &= SF_SETTABLE;
 			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
 			DIP_ASSIGN(ip, flags, ip->i_flags);
 		}
 		ip->i_flag |= IN_CHANGE;
-		if (vap->va_flags & (IMMUTABLE | APPEND))
-			return (0);
+		if (vap->va_flags & (IMMUTABLE | APPEND)) {
+			error = 0;
+			goto out;
+		}
+	}
+	if (ip->i_flags & (IMMUTABLE | APPEND)) {
+		error = EPERM;
+		goto out;
 	}
-	if (ip->i_flags & (IMMUTABLE | APPEND))
-		return (EPERM);
 	/*
 	 * Go through the fields and update iff not VNOVAL.
 	 */
 	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
-		if (vp->v_mount->mnt_flag & MNT_RDONLY)
-			return (EROFS);
+		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
+			error = EROFS;
+			goto out;
+		}
 		error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, l->l_proc);
 		if (error)
-			return (error);
+			goto out;
 	}
 	if (vap->va_size != VNOVAL) {
 		/*
 		 * Disallow write attempts on read-only file systems;
@@ -435,39 +468,49 @@ ufs_setattr(void *v)
 		 * character device resident on the file system.
 		 */
 		switch (vp->v_type) {
 		case VDIR:
-			return (EISDIR);
+			error = EISDIR;
+			goto out;
 		case VCHR:
 		case VBLK:
 		case VFIFO:
 			break;
 		case VREG:
-			if (vp->v_mount->mnt_flag & MNT_RDONLY)
-				 return (EROFS);
-			if ((ip->i_flags & SF_SNAPSHOT) != 0)
-				return (EPERM);
+			if (vp->v_mount->mnt_flag & MNT_RDONLY) {
+				 error = EROFS;
+				 goto out;
+			}
+			if ((ip->i_flags & SF_SNAPSHOT) != 0) {
+				error = EPERM;
+				goto out;
+			}
 			error = UFS_TRUNCATE(vp, vap->va_size, 0, cred, l);
 			if (error)
-				return (error);
+				goto out;
 			break;
 		default:
-			return (EOPNOTSUPP);
+			error = EOPNOTSUPP;
+			goto out;
 		}
 	}
 	ip = VTOI(vp);
 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
 	    vap->va_birthtime.tv_sec != VNOVAL) {
-		if (vp->v_mount->mnt_flag & MNT_RDONLY)
-			return (EROFS);
-		if ((ip->i_flags & SF_SNAPSHOT) != 0)
-			return (EPERM);
+		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
+			error = EROFS;
+			goto out;
+		}
+		if ((ip->i_flags & SF_SNAPSHOT) != 0) {
+			error = EPERM;
+			goto out;
+		}
 		if (kauth_cred_geteuid(cred) != ip->i_uid &&
 		    (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
 					       &l->l_proc->p_acflag)) &&
 		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
 		    (error = VOP_ACCESS(vp, VWRITE, cred, l))))
-			return (error);
+			goto out;
 		if (vap->va_atime.tv_sec != VNOVAL)
 			if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
 				ip->i_flag |= IN_ACCESS;
 		if (vap->va_mtime.tv_sec != VNOVAL)
@@ -478,21 +521,27 @@ ufs_setattr(void *v)
 			ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec;
 		}
 		error = UFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0);
 		if (error)
-			return (error);
+			goto out;
 	}
 	error = 0;
 	if (vap->va_mode != (mode_t)VNOVAL) {
-		if (vp->v_mount->mnt_flag & MNT_RDONLY)
-			return (EROFS);
+		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
+			error = EROFS;
+			goto out;
+		}
 		if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
 		    (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
-		     S_IXOTH | S_IWOTH)))
-			return (EPERM);
+		     S_IXOTH | S_IWOTH))) {
+			error = EPERM;
+			goto out;
+		}
 		error = ufs_chmod(vp, (int)vap->va_mode, cred, l->l_proc);
 	}
 	VN_KNOTE(vp, NOTE_ATTRIB);
+out:
+	fstrans_done(vp->v_mount);
 	return (error);
 }
 
 /*
@@ -648,8 +697,10 @@ ufs_remove(void *v)
 
 	vp = ap->a_vp;
 	dvp = ap->a_dvp;
 	ip = VTOI(vp);
+	if ((error = fstrans_start(dvp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
 	if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
 	    (VTOI(dvp)->i_flags & APPEND))
 		error = EPERM;
 	else
@@ -660,8 +711,9 @@ ufs_remove(void *v)
 		vrele(vp);
 	else
 		vput(vp);
 	vput(dvp);
+	fstrans_done(dvp->v_mount);
 	return (error);
 }
 
 /*
@@ -687,8 +739,10 @@ ufs_link(void *v)
 #ifdef DIAGNOSTIC
 	if ((cnp->cn_flags & HASBUF) == 0)
 		panic("ufs_link: no name");
 #endif
+	if ((error = fstrans_start(dvp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
 	if (vp->v_type == VDIR) {
 		VOP_ABORTOP(dvp, cnp);
 		error = EPERM;
 		goto out2;
@@ -741,8 +795,9 @@ ufs_link(void *v)
  out2:
 	VN_KNOTE(vp, NOTE_LINK);
 	VN_KNOTE(dvp, NOTE_WRITE);
 	vput(dvp);
+	fstrans_done(dvp->v_mount);
 	return (error);
 }
 
 /*
@@ -762,17 +817,21 @@ ufs_whiteout(void *v)
 	int			error;
 	struct ufsmount		*ump = VFSTOUFS(dvp->v_mount);
 
 	error = 0;
+
 	switch (ap->a_flags) {
 	case LOOKUP:
 		/* 4.4 format directories support whiteout operations */
+		fstrans_done(dvp->v_mount);
 		if (ump->um_maxsymlinklen > 0)
 			return (0);
 		return (EOPNOTSUPP);
 
 	case CREATE:
 		/* create a new directory whiteout */
+		if ((error = fstrans_start(dvp->v_mount, FSTRANS_SHARED)) != 0)
+			return error;
 #ifdef DIAGNOSTIC
 		if ((cnp->cn_flags & SAVENAME) == 0)
 			panic("ufs_whiteout: missing name");
 		if (ump->um_maxsymlinklen <= 0)
@@ -791,8 +850,10 @@ ufs_whiteout(void *v)
 		break;
 
 	case DELETE:
 		/* remove an existing directory whiteout */
+		if ((error = fstrans_start(dvp->v_mount, FSTRANS_SHARED)) != 0)
+			return error;
 #ifdef DIAGNOSTIC
 		if (ump->um_maxsymlinklen <= 0)
 			panic("ufs_whiteout: old format filesystem");
 #endif
@@ -807,8 +868,9 @@ ufs_whiteout(void *v)
 	if (cnp->cn_flags & HASBUF) {
 		PNBUF_PUT(cnp->cn_pnbuf);
 		cnp->cn_flags &= ~HASBUF;
 	}
+	fstrans_done(dvp->v_mount);
 	return (error);
 }
 
 
@@ -849,8 +911,9 @@ ufs_rename(void *v)
 	} */ *ap = v;
 	struct vnode		*tvp, *tdvp, *fvp, *fdvp;
 	struct componentname	*tcnp, *fcnp;
 	struct inode		*ip, *xp, *dp;
+	struct mount		*mp;
 	struct direct		*newdir;
 	int			doingdirectory, oldparent, newparent, error;
 
 	tvp = ap->a_tvp;
@@ -959,8 +1022,12 @@ ufs_rename(void *v)
 	xp = NULL;
 	if (tvp)
 		xp = VTOI(tvp);
 
+	mp = fdvp->v_mount;
+	if ((error = fstrans_start(mp, FSTRANS_SHARED)) != 0)
+		return error;
+
 	/*
 	 * 1) Bump link count while we're moving stuff
 	 *    around.  If we crash somewhere before
 	 *    completing our work, the link count
@@ -1156,9 +1223,9 @@ ufs_rename(void *v)
 	fcnp->cn_flags &= ~(MODMASK | SAVESTART);
 	fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
 	if ((error = relookup(fdvp, &fvp, fcnp))) {
 		vrele(ap->a_fvp);
-		return (error);
+		goto out2;
 	}
 	if (fvp != NULL) {
 		xp = VTOI(fvp);
 		dp = VTOI(fdvp);
@@ -1168,9 +1235,10 @@ ufs_rename(void *v)
 		 */
 		if (doingdirectory)
 			panic("rename: lost dir entry");
 		vrele(ap->a_fvp);
-		return (0);
+		error = 0;
+		goto out2;
 	}
 	/*
 	 * Ensure that the directory entry still exists and has not
 	 * changed while the new name has been entered. If the source is
@@ -1203,9 +1271,9 @@ ufs_rename(void *v)
 		vput(fdvp);
 	if (xp)
 		vput(fvp);
 	vrele(ap->a_fvp);
-	return (error);
+	goto out2;
 
 	/* exit routines from steps 1 & 2 */
  bad:
 	if (xp)
@@ -1225,8 +1293,12 @@ ufs_rename(void *v)
 		vput(fvp);
 	} else
 		vrele(fvp);
 	vrele(fdvp);
+
+	/* exit routines from step 3 */
+ out2:
+	fstrans_done(mp);
 	return (error);
 }
 
 /*
@@ -1251,8 +1323,11 @@ ufs_mkdir(void *v)
 	int			error, dmode, blkoff;
 	struct ufsmount		*ump = dp->i_ump;
 	int			dirblksiz = ump->um_dirblksiz;
 
+	if ((error = fstrans_start(dvp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
+
 #ifdef DIAGNOSTIC
 	if ((cnp->cn_flags & HASBUF) == 0)
 		panic("ufs_mkdir: no name");
 #endif
@@ -1279,8 +1354,9 @@ ufs_mkdir(void *v)
 	if ((error = getinoquota(ip)) ||
 	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
 		PNBUF_PUT(cnp->cn_pnbuf);
 		UFS_VFREE(tvp, ip->i_number, dmode);
+		fstrans_done(dvp->v_mount);
 		vput(tvp);
 		vput(dvp);
 		return (error);
 	}
@@ -1408,8 +1484,9 @@ ufs_mkdir(void *v)
 		vput(tvp);
 	}
  out:
 	PNBUF_PUT(cnp->cn_pnbuf);
+	fstrans_done(dvp->v_mount);
 	vput(dvp);
 	return (error);
 }
 
@@ -1443,8 +1520,12 @@ ufs_rmdir(void *v)
 			VOP_UNLOCK(dvp, 0);
 		vput(vp);
 		return (EINVAL);
 	}
+
+	if ((error = fstrans_start(dvp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
+
 	/*
 	 * Do not remove a directory that is in the process of being renamed.
 	 * Verify that the directory is empty (and valid). (Rmdir ".." won't
 	 * be valid since ".." will contain a reference to the current
@@ -1513,8 +1594,9 @@ ufs_rmdir(void *v)
 		ufsdirhash_free(ip);
 #endif
  out:
 	VN_KNOTE(vp, NOTE_DELETE);
+	fstrans_done(dvp->v_mount);
 	vput(dvp);
 	vput(vp);
 	return (error);
 }
@@ -1536,12 +1618,14 @@ ufs_symlink(void *v)
 	struct inode	*ip;
 	int		len, error;
 
 	vpp = ap->a_vpp;
+	if ((error = fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
 	error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
 			      vpp, ap->a_cnp);
 	if (error)
-		return (error);
+		goto out;
 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
 	vp = *vpp;
 	len = strlen(ap->a_target);
 	ip = VTOI(vp);
@@ -1556,8 +1640,10 @@ ufs_symlink(void *v)
 		    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
 		    NULL);
 	if (error)
 		vput(vp);
+out:
+	fstrans_done(ap->a_dvp->v_mount);
 	return (error);
 }
 
 /*
@@ -2218,4 +2304,71 @@ ufs_gop_markupdate(struct vnode *vp, int
 
 		ip->i_flag |= mask;
 	}
 }
+
+/*
+ * Lock the node.
+ */
+int
+ufs_lock(void *v)
+{
+	struct vop_lock_args /* {
+		struct vnode *a_vp;
+		int a_flags;
+	} */ *ap = v;
+	struct vnode *vp = ap->a_vp;
+	struct mount *mp = vp->v_mount;
+
+	/*
+	 * Fake lock during file system suspension.
+	 */
+	if ((mp->mnt_iflag & (IMNT_SUSPEND|IMNT_SUSPENDED)) == IMNT_SUSPEND &&
+	    (vp->v_type == VREG || vp->v_type == VDIR) &&
+	    fstrans_status(mp, FSTRANS_EXCL)) {
+		if ((ap->a_flags & LK_INTERLOCK) != 0)
+			simple_unlock(&vp->v_interlock);
+		return 0;
+	}
+	return (lockmgr(vp->v_vnlock, ap->a_flags, &vp->v_interlock));
+}
+
+/*
+ * Unlock the node.
+ */
+int
+ufs_unlock(void *v)
+{
+	struct vop_unlock_args /* {
+		struct vnode *a_vp;
+		int a_flags;
+	} */ *ap = v;
+	struct vnode *vp = ap->a_vp;
+	struct mount *mp = vp->v_mount;
+
+	/*
+	 * Fake unlock during file system suspension.
+	 */
+	if ((mp->mnt_iflag & (IMNT_SUSPEND|IMNT_SUSPENDED)) == IMNT_SUSPEND &&
+	    (vp->v_type == VREG || vp->v_type == VDIR) &&
+	    fstrans_status(mp, FSTRANS_EXCL)) {
+		if ((ap->a_flags & LK_INTERLOCK) != 0)
+			simple_unlock(&vp->v_interlock);
+		return 0;
+	}
+	return (lockmgr(vp->v_vnlock, ap->a_flags | LK_RELEASE,
+	    &vp->v_interlock));
+}
+
+/*
+ * Return whether or not the node is locked.
+ */
+int
+ufs_islocked(void *v)
+{
+	struct vop_islocked_args /* {
+		struct vnode *a_vp;
+	} */ *ap = v;
+	struct vnode *vp = ap->a_vp;
+
+	return (lockstatus(vp->v_vnlock));
+}
Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.183
diff -p -u -4 -r1.183 ffs_vfsops.c
--- sys/ufs/ffs/ffs_vfsops.c	13 Jul 2006 12:00:26 -0000	1.183
+++ sys/ufs/ffs/ffs_vfsops.c	30 Jul 2006 16:54:11 -0000
@@ -60,8 +60,9 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c
 #include <sys/lock.h>
 #include <sys/sysctl.h>
 #include <sys/conf.h>
 #include <sys/kauth.h>
+#include <sys/fstrans.h>
 
 #include <miscfs/specfs/specdev.h>
 
 #include <ufs/ufs/quota.h>
@@ -107,8 +108,9 @@ struct vfsops ffs_vfsops = {
 	ffs_done,
 	ffs_mountroot,
 	ffs_snapshot,
 	ffs_extattrctl,
+	ffs_suspendctl,
 	ffs_vnodeopv_descs,
 };
 VFS_ATTACH(ffs_vfsops);
 
@@ -963,8 +965,11 @@ ffs_mountfs(struct vnode *devvp, struct 
 	}
 	mp->mnt_fs_bshift = fs->fs_bshift;
 	mp->mnt_dev_bshift = DEV_BSHIFT;	/* XXX */
 	mp->mnt_flag |= MNT_LOCAL;
+#ifdef NEWVNGATE
+	mp->mnt_iflag |= IMNT_HAS_TRANS;
+#endif
 #ifdef FFS_EI
 	if (needswap)
 		ump->um_flags |= UFS_NEEDSWAP;
 #endif
@@ -1296,15 +1301,19 @@ ffs_sync(struct mount *mp, int waitfor, 
 	struct vnode *vp, *nvp;
 	struct inode *ip;
 	struct ufsmount *ump = VFSTOUFS(mp);
 	struct fs *fs;
-	int error, count, allerror = 0;
+	int error, count, suspend, allerror = 0;
 
 	fs = ump->um_fs;
+	suspend =
+	    (mp->mnt_iflag & (IMNT_SUSPEND | IMNT_SUSPENDED)) == IMNT_SUSPEND;
 	if (fs->fs_fmod != 0 && fs->fs_ronly != 0) {		/* XXX */
 		printf("fs = %s\n", fs->fs_fsmnt);
 		panic("update: rofs mod");
 	}
+	if ((error = fstrans_start(mp, FSTRANS_SHARED)) != 0)
+		return error;
 	/*
 	 * Write back each (modified) inode.
 	 */
 	simple_lock(&mntvnode_slock);
@@ -1327,8 +1336,12 @@ loop:
 		{
 			simple_unlock(&vp->v_interlock);
 			continue;
 		}
+		if (vp->v_type == VBLK && suspend) {
+			simple_unlock(&vp->v_interlock);
+			continue;
+		}
 		simple_unlock(&mntvnode_slock);
 		error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
 		if (error) {
 			simple_lock(&mntvnode_slock);
@@ -1382,8 +1395,9 @@ loop:
 		fs->fs_time = time_second;
 		if ((error = ffs_cgupdate(ump, waitfor)))
 			allerror = error;
 	}
+	fstrans_done(mp);
 	return (allerror);
 }
 
 /*
@@ -1746,4 +1760,36 @@ ffs_extattrctl(struct mount *mp, int cmd
 				       l));
 #endif
 	return (vfs_stdextattrctl(mp, cmd, vp, attrnamespace, attrname, l));
 }
+
+int
+ffs_suspendctl(struct mount *mp, int cmd)
+{
+	int error;
+	struct lwp *l = curlwp;
+
+	switch (cmd) {
+	case SUSPEND_SUSPEND:
+		if ((error = fstrans_start(mp, FSTRANS_EXCL)) != 0)
+			return error;
+		mp->mnt_iflag |= IMNT_SUSPEND;
+		error = ffs_sync(mp, MNT_WAIT, l->l_proc->p_cred, l);
+		if (error != 0) {
+			mp->mnt_iflag &= ~IMNT_SUSPEND;
+			fstrans_done(mp);
+			return error;
+		}
+		mp->mnt_iflag |= IMNT_SUSPENDED;
+		return 0;
+
+	case SUSPEND_RESUME:
+		KASSERT((mp->mnt_iflag & (IMNT_SUSPEND | IMNT_SUSPENDED)) ==
+		    (IMNT_SUSPEND | IMNT_SUSPENDED));
+		mp->mnt_iflag &= ~(IMNT_SUSPEND | IMNT_SUSPENDED);
+		fstrans_done(mp);
+		return 0;
+
+	default:
+		return EINVAL;
+	}
+}
Index: sys/ufs/ffs/ffs_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_extern.h,v
retrieving revision 1.54
diff -p -u -4 -r1.54 ffs_extern.h
--- sys/ufs/ffs/ffs_extern.h	13 Jul 2006 12:00:26 -0000	1.54
+++ sys/ufs/ffs/ffs_extern.h	30 Jul 2006 16:54:09 -0000
@@ -124,8 +124,9 @@ int	ffs_vget(struct mount *, ino_t, stru
 int	ffs_fhtovp(struct mount *, struct fid *, struct vnode **);
 int	ffs_vptofh(struct vnode *, struct fid *, size_t *);
 int	ffs_extattrctl(struct mount *, int, struct vnode *, int,
 		       const char *, struct lwp *);
+int	ffs_suspendctl(struct mount *, int);
 int	ffs_sbupdate(struct ufsmount *, int);
 int	ffs_cgupdate(struct ufsmount *, int);
 
 /* ffs_vnops.c */
Index: sys/ufs/ffs/ffs_snapshot.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_snapshot.c,v
retrieving revision 1.30
diff -p -u -4 -r1.30 ffs_snapshot.c
--- sys/ufs/ffs/ffs_snapshot.c	7 Jun 2006 22:34:19 -0000	1.30
+++ sys/ufs/ffs/ffs_snapshot.c	30 Jul 2006 16:54:09 -0000
@@ -58,8 +58,9 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_snapshot
 #include <sys/resource.h>
 #include <sys/resourcevar.h>
 #include <sys/vnode.h>
 #include <sys/kauth.h>
+#include <sys/fstrans.h>
 
 #include <miscfs/specfs/specdev.h>
 
 #include <ufs/ufs/quota.h>
@@ -284,9 +285,9 @@ ffs_snapshot(struct mount *mp, struct vn
 	 * All allocations are done, so we can now snapshot the system.
 	 *
 	 * Suspend operation on filesystem.
 	 */
-	if ((error = vfs_write_suspend(vp->v_mount, PUSER|PCATCH, 0)) != 0) {
+	if ((error = vfs_suspend(vp->v_mount, 0)) != 0) {
 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
 		goto out;
 	}
 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
@@ -378,25 +379,33 @@ loop:
 			VI_UNLOCK(xvp);
 			MNT_ILOCK(mp);
 			continue;
 		}
+#ifndef NEWVNGATE
 		if (vn_lock(xvp, LK_EXCLUSIVE | LK_INTERLOCK) != 0) {
 			MNT_ILOCK(mp);
 			goto loop;
 		}
+#else /* NEWVNGATE */
+		VI_UNLOCK(xvp);
+#endif /* NEWVNGATE */
 #ifdef DEBUG
 		if (snapdebug)
 			vprint("ffs_snapshot: busy vnode", xvp);
 #endif
 		if (VOP_GETATTR(xvp, &vat, l->l_proc->p_cred, l) == 0 &&
 		    vat.va_nlink > 0) {
+#ifndef NEWVNGATE
 			VOP_UNLOCK(xvp, 0);
+#endif /* NEWVNGATE */
 			MNT_ILOCK(mp);
 			continue;
 		}
 		xp = VTOI(xvp);
 		if (ffs_checkfreefile(copy_fs, vp, xp->i_number)) {
+#ifndef NEWVNGATE
 			VOP_UNLOCK(xvp, 0);
+#endif /* NEWVNGATE */
 			MNT_ILOCK(mp);
 			continue;
 		}
 		/*
@@ -424,9 +433,11 @@ loop:
 			db_assign(xp, loc, blkno);
 		if (!error)
 			error = ffs_freefile(copy_fs, vp, xp->i_number,
 			    xp->i_mode);
+#ifndef NEWVNGATE
 		VOP_UNLOCK(xvp, 0);
+#endif /* NEWVNGATE */
 		if (error) {
 			free(copy_fs->fs_csp, M_UFSMNT);
 			goto out1;
 		}
@@ -507,9 +518,9 @@ loop:
 out1:
 	/*
 	 * Resume operation on filesystem.
 	 */
-	vfs_write_resume(vp->v_mount);
+	vfs_resume(vp->v_mount);
 	/*
 	 * Set the mtime to the time the snapshot has been taken.
 	 */
 	TIMEVAL_TO_TIMESPEC(&starttime, &ts);
Index: sys/ufs/ffs/ffs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vnops.c,v
retrieving revision 1.80
diff -p -u -4 -r1.80 ffs_vnops.c
--- sys/ufs/ffs/ffs_vnops.c	14 May 2006 21:32:45 -0000	1.80
+++ sys/ufs/ffs/ffs_vnops.c	30 Jul 2006 16:54:11 -0000
@@ -47,8 +47,9 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,
 #include <sys/vnode.h>
 #include <sys/pool.h>
 #include <sys/signalvar.h>
 #include <sys/kauth.h>
+#include <sys/fstrans.h>
 
 #include <miscfs/fifofs/fifo.h>
 #include <miscfs/genfs/genfs.h>
 #include <miscfs/specfs/specdev.h>
@@ -250,18 +251,22 @@ ffs_fsync(void *v)
 	int bsize;
 	daddr_t blk_high;
 	struct vnode *vp;
 
+	vp = ap->a_vp;
+
+	if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0)
+		return error;
 	/*
 	 * XXX no easy way to sync a range in a file with softdep.
 	 */
-	if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(ap->a_vp) ||
-			(ap->a_vp->v_type != VREG))
-		return ffs_full_fsync(v);
-
-	vp = ap->a_vp;
+	if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(vp) ||
+	    (vp->v_type != VREG)) {
+		error = ffs_full_fsync(v);
+		goto out;
+	}
 
-	bsize = ap->a_vp->v_mount->mnt_stat.f_iosize;
+	bsize = vp->v_mount->mnt_stat.f_iosize;
 	blk_high = ap->a_offhi / bsize;
 	if (ap->a_offhi % bsize != 0)
 		blk_high++;
 
@@ -273,9 +278,9 @@ ffs_fsync(void *v)
 	error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
 	    round_page(ap->a_offhi), PGO_CLEANIT |
 	    ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0));
 	if (error) {
-		return error;
+		goto out;
 	}
 
 	/*
 	 * Then, flush indirect blocks.
@@ -285,9 +290,9 @@ ffs_fsync(void *v)
 	if (blk_high >= NDADDR) {
 		error = ufs_getlbns(vp, blk_high, ia, &num);
 		if (error) {
 			splx(s);
-			return error;
+			goto out;
 		}
 		for (i = 0; i < num; i++) {
 			bp = incore(vp, ia[i].in_lbn);
 			if (bp != NULL) {
@@ -325,8 +330,10 @@ ffs_fsync(void *v)
 		VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
 			ap->a_l->l_proc->p_cred, ap->a_l);
 	}
 
+out:
+	fstrans_done(vp->v_mount);
 	return error;
 }
 
 /*
@@ -479,13 +486,18 @@ ffs_reclaim(void *v)
 		struct lwp *a_l;
 	} */ *ap = v;
 	struct vnode *vp = ap->a_vp;
 	struct inode *ip = VTOI(vp);
+	struct mount *mp = vp->v_mount;
 	struct ufsmount *ump = ip->i_ump;
 	int error;
 
-	if ((error = ufs_reclaim(vp, ap->a_l)) != 0)
+	if ((error = fstrans_start(mp, FSTRANS_SHARED)) != 0)
+		return error;
+	if ((error = ufs_reclaim(vp, ap->a_l)) != 0) {
+		fstrans_done(mp);
 		return (error);
+	}
 	if (ip->i_din.ffs1_din != NULL) {
 		if (ump->um_fstype == UFS1)
 			pool_put(&ffs_dinode1_pool, ip->i_din.ffs1_din);
 		else
@@ -496,8 +508,9 @@ ffs_reclaim(void *v)
 	 * XXX a separate pool for MFS inodes?
 	 */
 	pool_put(&ffs_inode_pool, vp->v_data);
 	vp->v_data = NULL;
+	fstrans_done(mp);
 	return (0);
 }
 
 int
@@ -606,14 +619,21 @@ ffs_getextattr(void *v)
 		size_t *a_size;
 		kauth_cred_t a_cred;
 		struct proc *a_p;
 	} */ *ap = v;
-	struct inode *ip = VTOI(ap->a_vp);
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
 	struct fs *fs = ip->i_fs;
 
 	if (fs->fs_magic == FS_UFS1_MAGIC) {
 #ifdef UFS_EXTATTR
-		return (ufs_getextattr(ap));
+		int error;
+
+		if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0)
+			return error;
+		error = ufs_getextattr(ap);
+		fstrans_done(vp->v_mount);
+		return error;
 #else
 		return (EOPNOTSUPP);
 #endif
 	}
@@ -632,14 +652,21 @@ ffs_setextattr(void *v)
 		struct uio *a_uio;
 		kauth_cred_t a_cred;
 		struct proc *a_p;
 	} */ *ap = v;
-	struct inode *ip = VTOI(ap->a_vp);
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
 	struct fs *fs = ip->i_fs;
 
 	if (fs->fs_magic == FS_UFS1_MAGIC) {
 #ifdef UFS_EXTATTR
-		return (ufs_setextattr(ap));
+		int error;
+
+		if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0)
+			return error;
+		error = ufs_setextattr(ap);
+		fstrans_done(vp->v_mount);
+		return error;
 #else
 		return (EOPNOTSUPP);
 #endif
 	}
@@ -678,14 +705,21 @@ ffs_deleteextattr(void *v)
 		int a_attrnamespace;
 		kauth_cred_t a_cred;
 		struct proc *a_p;
 	} */ *ap = v;
-	struct inode *ip = VTOI(ap->a_vp);
+	struct vnode *vp = ap->a_vp;
+	struct inode *ip = VTOI(vp);
 	struct fs *fs = ip->i_fs;
 
 	if (fs->fs_magic == FS_UFS1_MAGIC) {
 #ifdef UFS_EXTATTR
-		return (ufs_deleteextattr(ap));
+		int error;
+
+		if ((error = fstrans_start(vp->v_mount, FSTRANS_SHARED)) != 0)
+			return error;
+		error = ufs_deleteextattr(ap);
+		fstrans_done(vp->v_mount);
+		return error;
 #else
 		return (EOPNOTSUPP);
 #endif
 	}
Index: sys/ufs/lfs/lfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_vnops.c,v
retrieving revision 1.183
diff -p -u -4 -r1.183 lfs_vnops.c
--- sys/ufs/lfs/lfs_vnops.c	13 Jul 2006 22:08:00 -0000	1.183
+++ sys/ufs/lfs/lfs_vnops.c	30 Jul 2006 16:54:11 -0000
@@ -87,8 +87,9 @@ __KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,
 #include <sys/pool.h>
 #include <sys/signalvar.h>
 #include <sys/kauth.h>
 #include <sys/syslog.h>
+#include <sys/fstrans.h>
 
 #include <miscfs/fifofs/fifo.h>
 #include <miscfs/genfs/genfs.h>
 #include <miscfs/specfs/specdev.h>
Index: sys/kern/kern_exit.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_exit.c,v
retrieving revision 1.157
diff -p -u -4 -r1.157 kern_exit.c
--- sys/kern/kern_exit.c	19 Jul 2006 21:11:37 -0000	1.157
+++ sys/kern/kern_exit.c	30 Jul 2006 16:54:06 -0000
@@ -113,8 +113,9 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exit.c,
 #include <sys/mount.h>
 #include <sys/syscallargs.h>
 #include <sys/systrace.h>
 #include <sys/kauth.h>
+#include <sys/fstrans.h>
 
 #include <machine/cpu.h>
 
 #include <uvm/uvm_extern.h>
@@ -358,8 +359,9 @@ exit1(struct lwp *l, int rv)
 	 */
 #ifndef __NO_CPU_LWP_FREE
 	cpu_lwp_free(l, 1);
 #endif
+	fstrans_exit(l);
 
 	pmap_deactivate(l);
 
 	/*
Index: sys/kern/tty_ptm.c
===================================================================
RCS file: /cvsroot/src/sys/kern/tty_ptm.c,v
retrieving revision 1.10
diff -p -u -4 -r1.10 tty_ptm.c
--- sys/kern/tty_ptm.c	17 Jul 2006 14:49:16 -0000	1.10
+++ sys/kern/tty_ptm.c	30 Jul 2006 16:54:06 -0000
@@ -48,8 +48,9 @@ __KERNEL_RCSID(0, "$NetBSD: tty_ptm.c,v 
 #include <sys/stat.h>
 #include <sys/file.h>
 #include <sys/uio.h>
 #include <sys/kernel.h>
+#include <sys/mount.h>
 #include <sys/vnode.h>
 #include <sys/namei.h>
 #include <sys/signalvar.h>
 #include <sys/uio.h>
Index: sys/kern/vfs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_subr.c,v
retrieving revision 1.267
diff -p -u -4 -r1.267 vfs_subr.c
--- sys/kern/vfs_subr.c	23 Jun 2006 14:13:02 -0000	1.267
+++ sys/kern/vfs_subr.c	30 Jul 2006 16:54:06 -0000
@@ -358,8 +358,9 @@ vfs_rootmountalloc(const char *fstypenam
 		return (ENODEV);
 	mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
 	memset((char *)mp, 0, (u_long)sizeof(struct mount));
 	lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
+	lockinit(&mp->mnt_trans_lock, PVFS, "suspfs", 0, 0);
 	simple_lock_init(&mp->mnt_slock);
 	(void)vfs_busy(mp, LK_NOWAIT, 0);
 	LIST_INIT(&mp->mnt_vnodelist);
 	mp->mnt_op = vfsp;
@@ -1203,9 +1204,16 @@ vget(struct vnode *vp, int flags)
 	}
 #endif
 	if (flags & LK_TYPE_MASK) {
 		if ((error = vn_lock(vp, flags | LK_INTERLOCK))) {
-			vrele(vp);
+			simple_lock(&vp->v_interlock);
+			if (vp->v_usecount > 1) {
+				vp->v_usecount--;
+				simple_unlock(&vp->v_interlock);
+			} else {
+				simple_unlock(&vp->v_interlock);
+				vrele(vp);
+			}
 		}
 		return (error);
 	}
 	simple_unlock(&vp->v_interlock);
@@ -2434,62 +2442,8 @@ vfs_reinit(void)
 		}
 	}
 }
 
-/*
- * Request a filesystem to suspend write operations.
- */
-int
-vfs_write_suspend(struct mount *mp, int slpflag, int slptimeo)
-{
-	struct lwp *l = curlwp;	/* XXX */
-	int error;
-
-	while ((mp->mnt_iflag & IMNT_SUSPEND)) {
-		if (slptimeo < 0)
-			return EWOULDBLOCK;
-		error = tsleep(&mp->mnt_flag, slpflag, "suspwt1", slptimeo);
-		if (error)
-			return error;
-	}
-	mp->mnt_iflag |= IMNT_SUSPEND;
-
-	simple_lock(&mp->mnt_slock);
-	if (mp->mnt_writeopcountupper > 0)
-		ltsleep(&mp->mnt_writeopcountupper, PUSER - 1, "suspwt",
-			0, &mp->mnt_slock);
-	simple_unlock(&mp->mnt_slock);
-
-	error = VFS_SYNC(mp, MNT_WAIT, l->l_proc->p_cred, l);
-	if (error) {
-		vfs_write_resume(mp);
-		return error;
-	}
-	mp->mnt_iflag |= IMNT_SUSPENDLOW;
-
-	simple_lock(&mp->mnt_slock);
-	if (mp->mnt_writeopcountlower > 0)
-		ltsleep(&mp->mnt_writeopcountlower, PUSER - 1, "suspwt",
-			0, &mp->mnt_slock);
-	mp->mnt_iflag |= IMNT_SUSPENDED;
-	simple_unlock(&mp->mnt_slock);
-
-	return 0;
-}
-
-/*
- * Request a filesystem to resume write operations.
- */
-void
-vfs_write_resume(struct mount *mp)
-{
-
-	if ((mp->mnt_iflag & IMNT_SUSPEND) == 0)
-		return;
-	mp->mnt_iflag &= ~(IMNT_SUSPEND | IMNT_SUSPENDLOW | IMNT_SUSPENDED);
-	wakeup(&mp->mnt_flag);
-}
-
 void
 copy_statvfs_info(struct statvfs *sbp, const struct mount *mp)
 {
 	const struct statvfs *mbp;
Index: sys/kern/vfs_syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.254
diff -p -u -4 -r1.254 vfs_syscalls.c
--- sys/kern/vfs_syscalls.c	19 Jul 2006 12:45:19 -0000	1.254
+++ sys/kern/vfs_syscalls.c	30 Jul 2006 16:54:07 -0000
@@ -324,8 +324,9 @@ sys_mount(struct lwp *l, void *v, regist
 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
 		M_MOUNT, M_WAITOK);
 	memset((char *)mp, 0, (u_long)sizeof(struct mount));
 	lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
+	lockinit(&mp->mnt_trans_lock, PVFS, "suspfs", 0, 0);
 	simple_lock_init(&mp->mnt_slock);
 	(void)vfs_busy(mp, LK_NOWAIT, 0);
 	mp->mnt_op = vfs;
 	vfs->vfs_refcount++;
@@ -650,8 +651,9 @@ dounmount(struct mount *mp, int flags, s
 	if (LIST_FIRST(&mp->mnt_vnodelist) != NULL)
 		panic("unmount: dangling vnode");
 	mp->mnt_iflag |= IMNT_GONE;
 	lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock);
+	lockmgr(&mp->mnt_trans_lock, LK_DRAIN, NULL);
 	if (used_syncer)
 		lockmgr(&syncer_lock, LK_RELEASE, NULL);
 	simple_lock(&mp->mnt_slock);
 	while (mp->mnt_wcnt > 0) {
Index: sys/kern/vfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_vnops.c,v
retrieving revision 1.114
diff -p -u -4 -r1.114 vfs_vnops.c
--- sys/kern/vfs_vnops.c	16 Jul 2006 18:49:29 -0000	1.114
+++ sys/kern/vfs_vnops.c	30 Jul 2006 16:54:07 -0000
@@ -963,8 +963,10 @@ vn_start_write(struct vnode *vp, struct 
 	}
 	if ((mp = *mpp) == NULL)
 		return (0);
 	mp = mp->mnt_leaf;
+	if ((mp->mnt_iflag & IMNT_HAS_TRANS) != 0)
+		return 0;
 	/*
 	 * Check on status of suspension.
 	 */
 	prio = PUSER - 1;
@@ -1004,8 +1006,10 @@ vn_finished_write(struct mount *mp, int 
 {
 	if (mp == NULL)
 		return;
 	mp = mp->mnt_leaf;
+	if ((mp->mnt_iflag & IMNT_HAS_TRANS) != 0)
+		return;
 	simple_lock(&mp->mnt_slock);
 	if ((flags & V_LOWER) == 0) {
 		mp->mnt_writeopcountupper--;
 		if (mp->mnt_writeopcountupper < 0)
Index: sys/uvm/uvm_pdaemon.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_pdaemon.c,v
retrieving revision 1.76
diff -p -u -4 -r1.76 uvm_pdaemon.c
--- sys/uvm/uvm_pdaemon.c	14 Feb 2006 15:06:27 -0000	1.76
+++ sys/uvm/uvm_pdaemon.c	30 Jul 2006 16:54:13 -0000
@@ -82,8 +82,9 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_pdaemon.
 #include <sys/kernel.h>
 #include <sys/pool.h>
 #include <sys/buf.h>
 #include <sys/vnode.h>
+#include <sys/fstrans.h>
 
 #include <uvm/uvm.h>
 
 /*
@@ -174,13 +175,8 @@ uvmpd_tune(void)
 	UVMHIST_FUNC("uvmpd_tune"); UVMHIST_CALLED(pdhist);
 
 	uvmexp.freemin = uvmexp.npages / 20;
 
-	/* between 16k and 256k */
-	/* XXX:  what are these values good for? */
-	uvmexp.freemin = MAX(uvmexp.freemin, (16*1024) >> PAGE_SHIFT);
-	uvmexp.freemin = MIN(uvmexp.freemin, (256*1024) >> PAGE_SHIFT);
-
 	/* Make sure there's always a user page free. */
 	if (uvmexp.freemin < uvmexp.reserve_kernel + 1)
 		uvmexp.freemin = uvmexp.reserve_kernel + 1;
 
@@ -704,12 +700,22 @@ uvmpd_scan_inactive(struct pglist *pglst
 		}
 #endif /* defined(READAHEAD_STATS) */
 
 		if ((p->pqflags & PQ_SWAPBACKED) == 0) {
+			struct vnode *vp = (struct vnode *)uobj;
+
+			if (UVM_OBJ_IS_VNODE(uobj) && fstrans_start(vp->v_mount,
+			    FSTRANS_SHARED | FSTRANS_NOWAIT) != 0) {
+				uvmexp.pdobscan--;
+				simple_unlock(slock);
+				continue;
+			}
 			uvm_unlock_pageq();
 			(void) (uobj->pgops->pgo_put)(uobj, p->offset,
 			    p->offset + PAGE_SIZE, PGO_CLEANIT|PGO_FREE);
 			uvm_lock_pageq();
+			if (UVM_OBJ_IS_VNODE(uobj))
+				fstrans_done(vp->v_mount);
 			if (nextpg &&
 			    (nextpg->pqflags & PQ_INACTIVE) == 0) {
 				nextpg = TAILQ_FIRST(pglst);
 			}
Index: common/lib/libc/gmon/mcount.c
===================================================================
RCS file: /cvsroot/src/common/lib/libc/gmon/mcount.c,v
retrieving revision 1.5
diff -p -u -4 -r1.5 mcount.c
--- common/lib/libc/gmon/mcount.c	8 Jan 2006 07:46:39 -0000	1.5
+++ common/lib/libc/gmon/mcount.c	30 Jul 2006 16:52:50 -0000
@@ -94,9 +94,9 @@ struct gmonparam *_m_gmon_alloc(void);
 #endif
 
 _MCOUNT_DECL __P((u_long, u_long))
 #ifdef _KERNEL
-    __attribute__((__unused__,__no_instrument_function__));	/* see below. */
+    __attribute__((__used__,__no_instrument_function__));	/* see below. */
 #else
 #ifdef __vax__
     __attribute__((__unused__));	/* see below. */
 #else
Index: sys/arch/sparc64/dev/psm.c
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/dev/psm.c,v
retrieving revision 1.2
diff -p -u -4 -r1.2 psm.c
--- sys/arch/sparc64/dev/psm.c	12 Jul 2006 15:03:24 -0000	1.2
+++ sys/arch/sparc64/dev/psm.c	30 Jul 2006 16:54:02 -0000
@@ -127,9 +127,9 @@ STATIC void psm_attach(struct device *, 
 CFATTACH_DECL(psm, sizeof(struct psm_softc),
     psm_match, psm_attach, NULL, NULL);
 
 
-static int
+STATIC int
 psm_match(struct device *parent, struct cfdata *cf, void *aux)
 {
 	struct ebus_attach_args *ea = aux;
 
@@ -137,9 +137,9 @@ psm_match(struct device *parent, struct 
 		return (0);
 	return (1);
 }
 
-static void
+STATIC void
 psm_attach(struct device *parent, struct device *self, void *aux)
 {
 	struct psm_softc	*sc = (struct psm_softc *)self;
 	struct ebus_attach_args	*ea = aux;
Index: sys/arch/xen/i386/autoconf.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/i386/autoconf.c,v
retrieving revision 1.17
diff -p -u -4 -r1.17 autoconf.c
--- sys/arch/xen/i386/autoconf.c	15 May 2006 00:55:57 -0000	1.17
+++ sys/arch/xen/i386/autoconf.c	30 Jul 2006 16:54:03 -0000
@@ -63,8 +63,9 @@ __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v
 #include <sys/reboot.h>
 #endif
 #include <sys/device.h>
 #include <sys/malloc.h>
+#include <sys/mount.h>
 #include <sys/vnode.h>
 #include <sys/fcntl.h>
 #include <sys/dkio.h>
 #include <sys/proc.h>
Index: sys/conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.789
diff -p -u -4 -r1.789 files
--- sys/conf/files	14 Jul 2006 18:41:40 -0000	1.789
+++ sys/conf/files	30 Jul 2006 16:54:03 -0000
@@ -1319,8 +1319,9 @@ file	kern/vfs_init.c
 file	kern/vfs_lockf.c
 file	kern/vfs_lookup.c
 file	kern/vfs_subr.c
 file	kern/vfs_syscalls.c
+file	kern/vfs_trans.c
 file	kern/vfs_vnops.c
 file	kern/vfs_xattr.c
 file	kern/vnode_if.c
 file	miscfs/deadfs/dead_vnops.c
Index: sys/dev/fss.c
===================================================================
RCS file: /cvsroot/src/sys/dev/fss.c,v
retrieving revision 1.26
diff -p -u -4 -r1.26 fss.c
--- sys/dev/fss.c	14 May 2006 21:42:26 -0000	1.26
+++ sys/dev/fss.c	30 Jul 2006 16:54:04 -0000
@@ -64,8 +64,9 @@ __KERNEL_RCSID(0, "$NetBSD: fss.c,v 1.26
 #include <sys/file.h>
 #include <sys/uio.h>
 #include <sys/conf.h>
 #include <sys/kthread.h>
+#include <sys/fstrans.h>
 
 #include <miscfs/specfs/specdev.h>
 
 #include <dev/fssvar.h>
@@ -739,9 +740,9 @@ fss_create_snapshot(struct fss_softc *sc
 	/*
 	 * Activate the snapshot.
 	 */
 
-	if ((error = vfs_write_suspend(sc->sc_mount, PUSER|PCATCH, 0)) != 0)
+	if ((error = vfs_suspend(sc->sc_mount, 0)) != 0)
 		goto bad;
 
 	microtime(&sc->sc_time);
 
@@ -750,9 +751,9 @@ fss_create_snapshot(struct fss_softc *sc
 		    fss_copy_on_write, sc);
 	if (error == 0)
 		sc->sc_flags |= FSS_ACTIVE;
 
-	vfs_write_resume(sc->sc_mount);
+	vfs_resume(sc->sc_mount);
 
 	if (error != 0)
 		goto bad;
 
@@ -1083,9 +1084,11 @@ fss_bs_thread(void *arg)
 			if (error) {
 				bp->b_error = error;
 				bp->b_flags |= B_ERROR;
 				bp->b_resid = bp->b_bcount;
-			}
+			} else
+				bp->b_resid = 0;
+
 			biodone(bp);
 
 			continue;
 		}
Index: sys/fs/sysvbfs/sysvbfs.c
===================================================================
RCS file: /cvsroot/src/sys/fs/sysvbfs/sysvbfs.c,v
retrieving revision 1.2
diff -p -u -4 -r1.2 sysvbfs.c
--- sys/fs/sysvbfs/sysvbfs.c	1 Jul 2006 08:42:39 -0000	1.2
+++ sys/fs/sysvbfs/sysvbfs.c	30 Jul 2006 16:54:05 -0000
@@ -131,7 +131,8 @@ struct vfsops sysvbfs_vfsops = {
 	NULL,			/* vfs_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *))
 	    eopnotsupp,		/* snapshot */
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	sysvbfs_vnodeopv_descs,
 };
 VFS_ATTACH(sysvbfs_vfsops);
Index: sys/ufs/ext2fs/ext2fs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_vfsops.c,v
retrieving revision 1.99
diff -p -u -4 -r1.99 ext2fs_vfsops.c
--- sys/ufs/ext2fs/ext2fs_vfsops.c	13 Jul 2006 12:00:26 -0000	1.99
+++ sys/ufs/ext2fs/ext2fs_vfsops.c	30 Jul 2006 16:54:09 -0000
@@ -138,8 +138,9 @@ struct vfsops ext2fs_vfsops = {
 	ext2fs_done,
 	ext2fs_mountroot,
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	ext2fs_vnodeopv_descs,
 };
 VFS_ATTACH(ext2fs_vfsops);
 
Index: sys/ufs/lfs/lfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/lfs/lfs_vfsops.c,v
retrieving revision 1.216
diff -p -u -4 -r1.216 lfs_vfsops.c
--- sys/ufs/lfs/lfs_vfsops.c	13 Jul 2006 12:00:26 -0000	1.216
+++ sys/ufs/lfs/lfs_vfsops.c	30 Jul 2006 16:54:11 -0000
@@ -155,8 +155,9 @@ struct vfsops lfs_vfsops = {
 	lfs_done,
 	lfs_mountroot,
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	lfs_vnodeopv_descs,
 };
 VFS_ATTACH(lfs_vfsops);
 
Index: sys/ufs/mfs/mfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/mfs/mfs_vfsops.c,v
retrieving revision 1.72
diff -p -u -4 -r1.72 mfs_vfsops.c
--- sys/ufs/mfs/mfs_vfsops.c	15 Apr 2006 01:16:40 -0000	1.72
+++ sys/ufs/mfs/mfs_vfsops.c	30 Jul 2006 16:54:11 -0000
@@ -101,8 +101,9 @@ struct vfsops mfs_vfsops = {
 	mfs_done,
 	NULL,
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	mfs_vnodeopv_descs,
 };
 VFS_ATTACH(mfs_vfsops);
 
Index: sys/coda/coda_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/coda/coda_vfsops.c,v
retrieving revision 1.48
diff -p -u -4 -r1.48 coda_vfsops.c
--- sys/coda/coda_vfsops.c	14 May 2006 21:24:49 -0000	1.48
+++ sys/coda/coda_vfsops.c	30 Jul 2006 16:54:03 -0000
@@ -118,8 +118,9 @@ struct vfsops coda_vfsops = {
     coda_done,
     (int (*)(void)) eopnotsupp,
     (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
     vfs_stdextattrctl,
+    vfs_stdsuspendctl,
     coda_vnodeopv_descs,
     0
 };
 
Index: sys/fs/adosfs/advfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/adosfs/advfsops.c,v
retrieving revision 1.29
diff -p -u -4 -r1.29 advfsops.c
--- sys/fs/adosfs/advfsops.c	13 Jul 2006 12:00:25 -0000	1.29
+++ sys/fs/adosfs/advfsops.c	30 Jul 2006 16:54:05 -0000
@@ -864,7 +864,8 @@ struct vfsops adosfs_vfsops = {
 	adosfs_done,
 	NULL,				/* vfs_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	adosfs_vnodeopv_descs,
 };
 VFS_ATTACH(adosfs_vfsops);
Index: sys/fs/cd9660/cd9660_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/cd9660/cd9660_vfsops.c,v
retrieving revision 1.33
diff -p -u -4 -r1.33 cd9660_vfsops.c
--- sys/fs/cd9660/cd9660_vfsops.c	13 Jul 2006 12:00:25 -0000	1.33
+++ sys/fs/cd9660/cd9660_vfsops.c	30 Jul 2006 16:54:05 -0000
@@ -102,8 +102,9 @@ struct vfsops cd9660_vfsops = {
 	cd9660_done,
 	cd9660_mountroot,
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	cd9660_vnodeopv_descs,
 };
 VFS_ATTACH(cd9660_vfsops);
 
Index: sys/fs/filecorefs/filecore_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/filecorefs/filecore_vfsops.c,v
retrieving revision 1.26
diff -p -u -4 -r1.26 filecore_vfsops.c
--- sys/fs/filecorefs/filecore_vfsops.c	13 Jul 2006 12:00:25 -0000	1.26
+++ sys/fs/filecorefs/filecore_vfsops.c	30 Jul 2006 16:54:05 -0000
@@ -120,8 +120,9 @@ struct vfsops filecore_vfsops = {
 	filecore_done,
 	NULL,				/* filecore_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	filecore_vnodeopv_descs,
 };
 VFS_ATTACH(filecore_vfsops);
 
Index: sys/fs/msdosfs/msdosfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/msdosfs/msdosfs_vfsops.c,v
retrieving revision 1.32
diff -p -u -4 -r1.32 msdosfs_vfsops.c
--- sys/fs/msdosfs/msdosfs_vfsops.c	13 Jul 2006 12:00:25 -0000	1.32
+++ sys/fs/msdosfs/msdosfs_vfsops.c	30 Jul 2006 16:54:05 -0000
@@ -132,8 +132,9 @@ struct vfsops msdosfs_vfsops = {
 	msdosfs_done,
 	msdosfs_mountroot,
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	msdosfs_vnodeopv_descs,
 };
 VFS_ATTACH(msdosfs_vfsops);
 
Index: sys/fs/ntfs/ntfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/ntfs/ntfs_vfsops.c,v
retrieving revision 1.42
diff -p -u -4 -r1.42 ntfs_vfsops.c
--- sys/fs/ntfs/ntfs_vfsops.c	13 Jul 2006 12:00:25 -0000	1.42
+++ sys/fs/ntfs/ntfs_vfsops.c	30 Jul 2006 16:54:05 -0000
@@ -1020,8 +1020,9 @@ struct vfsops ntfs_vfsops = {
 	ntfs_done,
 	ntfs_mountroot,
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	ntfs_vnodeopv_descs,
 };
 VFS_ATTACH(ntfs_vfsops);
 #endif
Index: sys/fs/ptyfs/ptyfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/ptyfs/ptyfs_vfsops.c,v
retrieving revision 1.17
diff -p -u -4 -r1.17 ptyfs_vfsops.c
--- sys/fs/ptyfs/ptyfs_vfsops.c	20 Jun 2006 09:17:14 -0000	1.17
+++ sys/fs/ptyfs/ptyfs_vfsops.c	30 Jul 2006 16:54:05 -0000
@@ -412,7 +412,8 @@ struct vfsops ptyfs_vfsops = {
 	NULL,				/* vfs_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *))eopnotsupp,
 	(int (*)(struct mount *, int, struct vnode *, int, const char *,
 	    struct lwp *))eopnotsupp,
+	vfs_stdsuspendctl,
 	ptyfs_vnodeopv_descs,
 };
 VFS_ATTACH(ptyfs_vfsops);
Index: sys/fs/smbfs/smbfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/smbfs/smbfs_vfsops.c,v
retrieving revision 1.52
diff -p -u -4 -r1.52 smbfs_vfsops.c
--- sys/fs/smbfs/smbfs_vfsops.c	14 May 2006 21:31:52 -0000	1.52
+++ sys/fs/smbfs/smbfs_vfsops.c	30 Jul 2006 16:54:05 -0000
@@ -137,8 +137,9 @@ struct vfsops smbfs_vfsops = {
 	smbfs_done,
 	(int (*) (void)) eopnotsupp, /* mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	smbfs_vnodeopv_descs,
 };
 VFS_ATTACH(smbfs_vfsops);
 
Index: sys/fs/tmpfs/tmpfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_vfsops.c,v
retrieving revision 1.13
diff -p -u -4 -r1.13 tmpfs_vfsops.c
--- sys/fs/tmpfs/tmpfs_vfsops.c	13 Jul 2006 12:00:25 -0000	1.13
+++ sys/fs/tmpfs/tmpfs_vfsops.c	30 Jul 2006 16:54:05 -0000
@@ -466,7 +466,8 @@ struct vfsops tmpfs_vfsops = {
 	tmpfs_done,			/* vfs_done */
 	NULL,				/* vfs_mountroot */
 	tmpfs_snapshot,			/* vfs_snapshot */
 	vfs_stdextattrctl,		/* vfs_extattrctl */
+	vfs_stdsuspendctl,		/* vfs_suspendctl */
 	tmpfs_vnodeopv_descs,
 };
 VFS_ATTACH(tmpfs_vfsops);
Index: sys/fs/udf/udf_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/udf/udf_vfsops.c,v
retrieving revision 1.7
diff -p -u -4 -r1.7 udf_vfsops.c
--- sys/fs/udf/udf_vfsops.c	13 Jul 2006 12:00:25 -0000	1.7
+++ sys/fs/udf/udf_vfsops.c	30 Jul 2006 16:54:06 -0000
@@ -142,8 +142,9 @@ struct vfsops udf_vfsops = {
 	udf_done,
 	udf_mountroot,
 	udf_snapshot,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	udf_vnodeopv_descs,
 	/* int vfs_refcount   */
 	/* LIST_ENTRY(vfsops) */
 };
Index: sys/fs/union/union_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/union/union_vfsops.c,v
retrieving revision 1.35
diff -p -u -4 -r1.35 union_vfsops.c
--- sys/fs/union/union_vfsops.c	14 May 2006 21:31:52 -0000	1.35
+++ sys/fs/union/union_vfsops.c	30 Jul 2006 16:54:06 -0000
@@ -581,7 +581,8 @@ struct vfsops union_vfsops = {
 	union_done,
 	NULL,				/* vfs_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	union_vnodeopv_descs,
 };
 VFS_ATTACH(union_vfsops);
Index: sys/miscfs/fdesc/fdesc_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/fdesc/fdesc_vfsops.c,v
retrieving revision 1.59
diff -p -u -4 -r1.59 fdesc_vfsops.c
--- sys/miscfs/fdesc/fdesc_vfsops.c	14 May 2006 21:31:52 -0000	1.59
+++ sys/miscfs/fdesc/fdesc_vfsops.c	30 Jul 2006 16:54:07 -0000
@@ -316,7 +316,8 @@ struct vfsops fdesc_vfsops = {
 	fdesc_done,
 	NULL,				/* vfs_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	fdesc_vnodeopv_descs,
 };
 VFS_ATTACH(fdesc_vfsops);
Index: sys/miscfs/kernfs/kernfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/kernfs/kernfs_vfsops.c,v
retrieving revision 1.71
diff -p -u -4 -r1.71 kernfs_vfsops.c
--- sys/miscfs/kernfs/kernfs_vfsops.c	14 May 2006 21:31:52 -0000	1.71
+++ sys/miscfs/kernfs/kernfs_vfsops.c	30 Jul 2006 16:54:08 -0000
@@ -318,7 +318,8 @@ struct vfsops kernfs_vfsops = {
 	kernfs_done,
 	NULL,				/* vfs_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	kernfs_vnodeopv_descs,
 };
 VFS_ATTACH(kernfs_vfsops);
Index: sys/miscfs/nullfs/null_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/nullfs/null_vfsops.c,v
retrieving revision 1.58
diff -p -u -4 -r1.58 null_vfsops.c
--- sys/miscfs/nullfs/null_vfsops.c	11 Dec 2005 12:24:51 -0000	1.58
+++ sys/miscfs/nullfs/null_vfsops.c	30 Jul 2006 16:54:08 -0000
@@ -312,7 +312,8 @@ struct vfsops nullfs_vfsops = {
 	layerfs_done,
 	NULL,				/* vfs_mountroot */
 	layerfs_snapshot,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	nullfs_vnodeopv_descs,
 };
 VFS_ATTACH(nullfs_vfsops);
Index: sys/miscfs/overlay/overlay_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/overlay/overlay_vfsops.c,v
retrieving revision 1.33
diff -p -u -4 -r1.33 overlay_vfsops.c
--- sys/miscfs/overlay/overlay_vfsops.c	11 Dec 2005 12:24:51 -0000	1.33
+++ sys/miscfs/overlay/overlay_vfsops.c	30 Jul 2006 16:54:08 -0000
@@ -295,7 +295,8 @@ struct vfsops overlay_vfsops = {
 	layerfs_done,
 	NULL,				/* vfs_mountroot */
 	layerfs_snapshot,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	ov_vnodeopv_descs,
 };
 VFS_ATTACH(overlay_vfsops);
Index: sys/miscfs/portal/portal_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/portal/portal_vfsops.c,v
retrieving revision 1.55
diff -p -u -4 -r1.55 portal_vfsops.c
--- sys/miscfs/portal/portal_vfsops.c	14 May 2006 21:31:53 -0000	1.55
+++ sys/miscfs/portal/portal_vfsops.c	30 Jul 2006 16:54:08 -0000
@@ -349,7 +349,8 @@ struct vfsops portal_vfsops = {
 	portal_done,
 	NULL,				/* vfs_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	portal_vnodeopv_descs,
 };
 VFS_ATTACH(portal_vfsops);
Index: sys/miscfs/procfs/procfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/procfs/procfs_vfsops.c,v
retrieving revision 1.64
diff -p -u -4 -r1.64 procfs_vfsops.c
--- sys/miscfs/procfs/procfs_vfsops.c	14 May 2006 21:31:53 -0000	1.64
+++ sys/miscfs/procfs/procfs_vfsops.c	30 Jul 2006 16:54:08 -0000
@@ -344,7 +344,8 @@ struct vfsops procfs_vfsops = {
 	procfs_done,
 	NULL,				/* vfs_mountroot */
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	procfs_vnodeopv_descs,
 };
 VFS_ATTACH(procfs_vfsops);
Index: sys/miscfs/umapfs/umap_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/umapfs/umap_vfsops.c,v
retrieving revision 1.57
diff -p -u -4 -r1.57 umap_vfsops.c
--- sys/miscfs/umapfs/umap_vfsops.c	14 May 2006 21:32:21 -0000	1.57
+++ sys/miscfs/umapfs/umap_vfsops.c	30 Jul 2006 16:54:08 -0000
@@ -334,7 +334,8 @@ struct vfsops umapfs_vfsops = {
 	layerfs_done,
 	NULL,				/* vfs_mountroot */
 	layerfs_snapshot,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	umapfs_vnodeopv_descs,
 };
 VFS_ATTACH(umapfs_vfsops);
Index: sys/nfs/nfs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/nfs/nfs_vfsops.c,v
retrieving revision 1.158
diff -p -u -4 -r1.158 nfs_vfsops.c
--- sys/nfs/nfs_vfsops.c	13 Jul 2006 12:00:26 -0000	1.158
+++ sys/nfs/nfs_vfsops.c	30 Jul 2006 16:54:08 -0000
@@ -119,8 +119,9 @@ struct vfsops nfs_vfsops = {
 	nfs_vfs_done,
 	nfs_mountroot,
 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
 	vfs_stdextattrctl,
+	vfs_stdsuspendctl,
 	nfs_vnodeopv_descs,
 };
 VFS_ATTACH(nfs_vfsops);
 

--bp/iNruPH9dso1Pn--