From 19b97e0175b44e6cf2523a5e741a03803f94a1ad Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sun, 18 May 2008 21:47:06 +0000 Subject: [PATCH] HAMMER 46B/Many: Stabilization pass * Add a feature to vmntvnodescan() to only do one pass on the vnode list. Have HAMMER use it. * Fix a buffer cache leak. Buffers could wind up disassociated from their HAMMER structures while in a B_LOCKED state, preventing the kernel from reusing them. --- sys/kern/vfs_mount.c | 23 ++++++++++++++++++++--- sys/sys/vnode.h | 7 ++++--- sys/vfs/hammer/hammer.h | 3 +-- sys/vfs/hammer/hammer_io.c | 30 ++++++++++++++++-------------- sys/vfs/hammer/hammer_ondisk.c | 6 +++--- 5 files changed, 44 insertions(+), 25 deletions(-) diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 42376874f4..a1d08ad5ad 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -67,7 +67,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/kern/vfs_mount.c,v 1.33 2008/05/18 05:54:25 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_mount.c,v 1.34 2008/05/18 21:47:02 dillon Exp $ */ /* @@ -911,10 +911,19 @@ vmntvnodescan( struct vnode *vp; int r = 0; int maxcount = 1000000; + int stopcount = 0; int count = 0; lwkt_gettoken(&ilock, &mntvnode_token); + /* + * If asked to do one pass stop after iterating available vnodes. + * Under heavy loads new vnodes can be added while we are scanning, + * so this isn't perfect. Create a slop factor of 2x. + */ + if (flags & VMSC_ONEPASS) + stopcount = mp->mnt_nvnodelistsize * 2; + info.vp = TAILQ_FIRST(&mp->mnt_nvnodelist); TAILQ_INSERT_TAIL(&mntvnodescan_list, &info, entry); while ((vp = info.vp) != NULL) { @@ -948,7 +957,7 @@ vmntvnodescan( if (slowfunc) { int error; - switch(flags) { + switch(flags & (VMSC_GETVP|VMSC_GETVX|VMSC_NOWAIT)) { case VMSC_GETVP: error = vget(vp, LK_EXCLUSIVE); break; @@ -976,7 +985,7 @@ vmntvnodescan( /* * Cleanup */ - switch(flags) { + switch(flags & (VMSC_GETVP|VMSC_GETVX|VMSC_NOWAIT)) { case VMSC_GETVP: case VMSC_GETVP|VMSC_NOWAIT: vput(vp); @@ -1005,6 +1014,14 @@ next: count = 0; } + /* + * If doing one pass this decrements to zero. If it starts + * at zero it is effectively unlimited for the purposes of + * this loop. + */ + if (--stopcount == 0) + break; + /* * Iterate. If the vnode was ripped out from under us * info.vp will already point to the next vnode, otherwise diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 474044bf16..2de42418d4 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -32,7 +32,7 @@ * * @(#)vnode.h 8.7 (Berkeley) 2/4/94 * $FreeBSD: src/sys/sys/vnode.h,v 1.111.2.19 2002/12/29 18:19:53 dillon Exp $ - * $DragonFly: src/sys/sys/vnode.h,v 1.79 2008/05/18 05:54:30 dillon Exp $ + * $DragonFly: src/sys/sys/vnode.h,v 1.80 2008/05/18 21:47:05 dillon Exp $ */ #ifndef _SYS_VNODE_H_ @@ -287,9 +287,10 @@ struct vnode { /* * vmntvnodescan() flags */ -#define VMSC_GETVP 1 -#define VMSC_GETVX 2 +#define VMSC_GETVP 0x01 +#define VMSC_GETVX 0x02 #define VMSC_NOWAIT 0x10 +#define VMSC_ONEPASS 0x20 /* * Flags for ioflag. (high 16 bits used to ask for read-ahead and diff --git a/sys/vfs/hammer/hammer.h b/sys/vfs/hammer/hammer.h index dcdb28c2b0..5b1ede7ea1 100644 --- a/sys/vfs/hammer/hammer.h +++ b/sys/vfs/hammer/hammer.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer.h,v 1.69 2008/05/18 01:48:50 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer.h,v 1.70 2008/05/18 21:47:06 dillon Exp $ */ /* * This header file contains structures used internally by the HAMMERFS @@ -843,7 +843,6 @@ int hammer_io_read(struct vnode *devvp, struct hammer_io *io, int hammer_io_new(struct vnode *devvp, struct hammer_io *io); void hammer_io_release(struct hammer_io *io, int flush); void hammer_io_flush(struct hammer_io *io); -int hammer_io_checkflush(hammer_io_t io); void hammer_io_clear_modify(struct hammer_io *io); void hammer_io_waitdep(struct hammer_io *io); diff --git a/sys/vfs/hammer/hammer_io.c b/sys/vfs/hammer/hammer_io.c index 24a201e5da..8058698711 100644 --- a/sys/vfs/hammer/hammer_io.c +++ b/sys/vfs/hammer/hammer_io.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.32 2008/05/18 01:48:50 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.33 2008/05/18 21:47:06 dillon Exp $ */ /* * IO Primitives and buffer cache management @@ -332,8 +332,23 @@ hammer_io_release(struct hammer_io *io, int flush) * structure and use bioops to disconnect it later on * if the kernel wants to discard the buffer. */ + bp->b_flags &= ~B_LOCKED; io->released = 1; bqrelse(bp); + } else { + /* + * A released buffer may have been locked when the kernel + * tried to deallocate it while HAMMER still had references + * on the hammer_buffer. We must unlock the buffer or + * it will just rot. + */ + crit_enter(); + if (io->running == 0 && (bp->b_flags & B_LOCKED)) { + regetblk(bp); + bp->b_flags &= ~B_LOCKED; + bqrelse(bp); + } + crit_exit(); } } @@ -747,19 +762,6 @@ hammer_io_checkwrite(struct buf *bp) return(0); } -/* - * Return non-zero if the caller should flush the structure associated - * with this io sub-structure. - */ -int -hammer_io_checkflush(struct hammer_io *io) -{ - if (io->bp == NULL || (io->bp->b_flags & B_LOCKED)) { - return(1); - } - return(0); -} - /* * Return non-zero if we wish to delay the kernel's attempt to flush * this buffer to disk. diff --git a/sys/vfs/hammer/hammer_ondisk.c b/sys/vfs/hammer/hammer_ondisk.c index 5865213c5a..bb33eab048 100644 --- a/sys/vfs/hammer/hammer_ondisk.c +++ b/sys/vfs/hammer/hammer_ondisk.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_ondisk.c,v 1.46 2008/05/18 01:48:50 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_ondisk.c,v 1.47 2008/05/18 21:47:06 dillon Exp $ */ /* * Manage HAMMER's on-disk structures. These routines are primarily @@ -1402,10 +1402,10 @@ hammer_queue_inodes_flusher(hammer_mount_t hmp, int waitfor) info.error = 0; info.waitfor = waitfor; if (waitfor == MNT_WAIT) { - vmntvnodescan(hmp->mp, VMSC_GETVP, + vmntvnodescan(hmp->mp, VMSC_GETVP|VMSC_ONEPASS, hammer_sync_scan1, hammer_sync_scan2, &info); } else { - vmntvnodescan(hmp->mp, VMSC_GETVP|VMSC_NOWAIT, + vmntvnodescan(hmp->mp, VMSC_GETVP|VMSC_ONEPASS|VMSC_NOWAIT, hammer_sync_scan1, hammer_sync_scan2, &info); } return(info.error); -- 2.41.0