From 6f3d87c0090b53820d5f8ea1a7b2bbb8fd476abb Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 24 Aug 2009 08:16:14 -0700 Subject: [PATCH] fsync - Add sysctl to relax fsync requirements. * sysctl vfs.hammer.fsync_mode (defaults to 0 == full fsync semantics). 0 - full fsync semantics 1 - asynchronous 2 - synchronous fsync on close if fsync called prior to close 3 - asynchronous fsync on close if fsync called prior to close 4 - ignore fsync (30-second system sync takes care of it) * This is likely a temporary measure until HAMMER gets a REDO log. It is mainly to facilitate testing and to reduce the pounding disks take from pkgsrc bulk builds (pkg_add seems to insist on calling fsync() a lot for no reason). --- sys/vfs/hammer/hammer.h | 3 ++ sys/vfs/hammer/hammer_ondisk.c | 2 +- sys/vfs/hammer/hammer_vfsops.c | 3 ++ sys/vfs/hammer/hammer_vnops.c | 63 ++++++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/sys/vfs/hammer/hammer.h b/sys/vfs/hammer/hammer.h index 2e18d70dff..d28e535c98 100644 --- a/sys/vfs/hammer/hammer.h +++ b/sys/vfs/hammer/hammer.h @@ -354,6 +354,8 @@ typedef struct hammer_inode *hammer_inode_t; #define HAMMER_INODE_MTIME 0x00200000 /* in-memory mtime modified */ #define HAMMER_INODE_WOULDBLOCK 0x00400000 /* re-issue to new flush group */ #define HAMMER_INODE_DUMMY 0x00800000 /* dummy inode covering bad file */ +#define HAMMER_INODE_CLOSESYNC 0x01000000 /* synchronously fsync on close */ +#define HAMMER_INODE_CLOSEASYNC 0x02000000 /* asynchronously fsync on close */ #define HAMMER_INODE_MODMASK (HAMMER_INODE_DDIRTY| \ HAMMER_INODE_XDIRTY|HAMMER_INODE_BUFS| \ @@ -865,6 +867,7 @@ extern int hammer_verify_zone; extern int hammer_verify_data; extern int hammer_write_mode; extern int hammer_yield_check; +extern int hammer_fsync_mode; extern int hammer_autoflush; extern int64_t hammer_contention_count; diff --git a/sys/vfs/hammer/hammer_ondisk.c b/sys/vfs/hammer/hammer_ondisk.c index 90ecfcdde4..c0b3391d33 100644 --- a/sys/vfs/hammer/hammer_ondisk.c +++ b/sys/vfs/hammer/hammer_ondisk.c @@ -1588,7 +1588,7 @@ hammer_sync_scan2(struct mount *mp, struct vnode *vp, void *data) RB_EMPTY(&vp->v_rbdirty_tree))) { return(0); } - error = VOP_FSYNC(vp, MNT_NOWAIT); + error = VOP_FSYNC(vp, MNT_NOWAIT, 0); if (error) info->error = error; return(0); diff --git a/sys/vfs/hammer/hammer_vfsops.c b/sys/vfs/hammer/hammer_vfsops.c index 331f43f91a..d8e609fd5d 100644 --- a/sys/vfs/hammer/hammer_vfsops.c +++ b/sys/vfs/hammer/hammer_vfsops.c @@ -102,6 +102,7 @@ int hammer_verify_zone; int hammer_verify_data = 1; int hammer_write_mode; int hammer_yield_check = 16; +int hammer_fsync_mode; int64_t hammer_contention_count; int64_t hammer_zone_limit; @@ -219,6 +220,8 @@ SYSCTL_INT(_vfs_hammer, OID_AUTO, write_mode, CTLFLAG_RW, &hammer_write_mode, 0, ""); SYSCTL_INT(_vfs_hammer, OID_AUTO, yield_check, CTLFLAG_RW, &hammer_yield_check, 0, ""); +SYSCTL_INT(_vfs_hammer, OID_AUTO, fsync_mode, CTLFLAG_RW, + &hammer_fsync_mode, 0, ""); KTR_INFO_MASTER(hammer); diff --git a/sys/vfs/hammer/hammer_vnops.c b/sys/vfs/hammer/hammer_vnops.c index b3f72f7683..a125ba0305 100644 --- a/sys/vfs/hammer/hammer_vnops.c +++ b/sys/vfs/hammer/hammer_vnops.c @@ -188,17 +188,57 @@ hammer_vop_vnoperate(struct vop_generic_args *) * fsync() an inode to disk and wait for it to be completely committed * such that the information would not be undone if a crash occured after * return. + * + * NOTE: HAMMER's fsync()'s are going to remain expensive until we implement + * a REDO log. A sysctl is provided to relax HAMMER's fsync() + * operation. + * + * Ultimately the combination of a REDO log and use of fast storage + * to front-end cluster caches will make fsync fast, but it aint + * here yet. And, in anycase, we need real transactional + * all-or-nothing features which are not restricted to a single file. */ static int hammer_vop_fsync(struct vop_fsync_args *ap) { hammer_inode_t ip = VTOI(ap->a_vp); + int waitfor = ap->a_waitfor; + /* + * Fsync rule relaxation (default disabled) + */ + if (ap->a_flags & VOP_FSYNC_SYSCALL) { + switch(hammer_fsync_mode) { + case 0: + /* full semantics */ + break; + case 1: + /* asynchronous */ + if (waitfor == MNT_WAIT) + waitfor = MNT_NOWAIT; + break; + case 2: + /* synchronous fsync on close */ + ip->flags |= HAMMER_INODE_CLOSESYNC; + return(0); + case 3: + /* asynchronous fsync on close */ + ip->flags |= HAMMER_INODE_CLOSEASYNC; + return(0); + default: + /* ignore the fsync() system call */ + return(0); + } + } + + /* + * Go do it + */ ++hammer_count_fsyncs; - vfsync(ap->a_vp, ap->a_waitfor, 1, NULL, NULL); + vfsync(ap->a_vp, waitfor, 1, NULL, NULL); hammer_flush_inode(ip, HAMMER_FLUSH_SIGNAL); - if (ap->a_waitfor == MNT_WAIT) { + if (waitfor == MNT_WAIT) { vn_unlock(ap->a_vp); hammer_wait_inode(ip); vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY); @@ -693,12 +733,29 @@ hammer_vop_advlock(struct vop_advlock_args *ap) /* * hammer_vop_close { vp, fflag } + * + * We can only sync-on-close for normal closes. */ static int hammer_vop_close(struct vop_close_args *ap) { - /*hammer_inode_t ip = VTOI(ap->a_vp);*/ + struct vnode *vp = ap->a_vp; + hammer_inode_t ip = VTOI(vp); + int waitfor; + + if (ip->flags & (HAMMER_INODE_CLOSESYNC|HAMMER_INODE_CLOSEASYNC)) { + if (vn_islocked(vp) == LK_EXCLUSIVE && + (vp->v_flag & (VINACTIVE|VRECLAIMED)) == 0) { + if (ip->flags & HAMMER_INODE_CLOSESYNC) + waitfor = MNT_WAIT; + else + waitfor = MNT_NOWAIT; + ip->flags &= ~(HAMMER_INODE_CLOSESYNC | + HAMMER_INODE_CLOSEASYNC); + VOP_FSYNC(vp, MNT_NOWAIT, waitfor); + } + } return (vop_stdclose(ap)); } -- 2.41.0