Cleanup ffs fsync and make devices on wapbl enabled file systems work here:
- Replace the ugly sync loop in ffs_full_fsync() and ffs_vfs_fsync() with vflushbuf(). This loop is a relic of softdeps and not needed anymore. - Add ffs_spec_fsync() for device nodes on ffs file systems that calls spec_fsync() like all other file systems do and then updates the ctime. Discussed on tech-kern. Should fix PRs: PR #41192 wapbl diagnostic panic during cgdconfig PR #41977 kernel diagnostic assertion "rw_lock_held(&wl->wl_rwlock)" failed PR #42149 wapbl locking panic if watching DVD PR #42551 Lockdebug assert in wapbl when running zpool
This commit is contained in:
parent
00d08a9058
commit
bb3ca01e60
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ffs_extern.h,v 1.76 2011/03/06 17:08:38 bouyer Exp $ */
|
||||
/* $NetBSD: ffs_extern.h,v 1.77 2011/04/27 07:24:52 hannken Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993, 1994
|
||||
@ -125,6 +125,7 @@ int ffs_cgupdate(struct ufsmount *, int);
|
||||
int ffs_read(void *);
|
||||
int ffs_write(void *);
|
||||
int ffs_fsync(void *);
|
||||
int ffs_spec_fsync(void *);
|
||||
int ffs_reclaim(void *);
|
||||
int ffs_getpages(void *);
|
||||
void ffs_gop_size(struct vnode *, off_t, off_t *, int);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ffs_vfsops.c,v 1.265 2011/03/27 08:04:50 mlelstv Exp $ */
|
||||
/* $NetBSD: ffs_vfsops.c,v 1.266 2011/04/27 07:24:53 hannken Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
|
||||
@ -61,7 +61,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.265 2011/03/27 08:04:50 mlelstv Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.266 2011/04/27 07:24:53 hannken Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_ffs.h"
|
||||
@ -2071,14 +2071,12 @@ ffs_suspendctl(struct mount *mp, int cmd)
|
||||
}
|
||||
|
||||
/*
|
||||
* Synch vnode for a mounted file system. This is called for foreign
|
||||
* vnodes, i.e. non-ffs.
|
||||
* Synch vnode for a mounted file system.
|
||||
*/
|
||||
static int
|
||||
ffs_vfs_fsync(vnode_t *vp, int flags)
|
||||
{
|
||||
int error, passes, skipmeta, i, pflags;
|
||||
buf_t *bp, *nbp;
|
||||
int error, i, pflags;
|
||||
#ifdef WAPBL
|
||||
struct mount *mp;
|
||||
#endif
|
||||
@ -2130,80 +2128,9 @@ ffs_vfs_fsync(vnode_t *vp, int flags)
|
||||
}
|
||||
#endif /* WAPBL */
|
||||
|
||||
/*
|
||||
* Write out metadata for non-logging file systems. XXX This block
|
||||
* should be simplified now that softdep is gone.
|
||||
*/
|
||||
passes = NIADDR + 1;
|
||||
skipmeta = 0;
|
||||
if (flags & FSYNC_WAIT)
|
||||
skipmeta = 1;
|
||||
|
||||
loop:
|
||||
mutex_enter(&bufcache_lock);
|
||||
LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
|
||||
bp->b_cflags &= ~BC_SCANNED;
|
||||
}
|
||||
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
||||
nbp = LIST_NEXT(bp, b_vnbufs);
|
||||
if (bp->b_cflags & (BC_BUSY | BC_SCANNED))
|
||||
continue;
|
||||
if ((bp->b_oflags & BO_DELWRI) == 0)
|
||||
panic("ffs_fsync: not dirty");
|
||||
if (skipmeta && bp->b_lblkno < 0)
|
||||
continue;
|
||||
bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED;
|
||||
mutex_exit(&bufcache_lock);
|
||||
/*
|
||||
* On our final pass through, do all I/O synchronously
|
||||
* so that we can find out if our flush is failing
|
||||
* because of write errors.
|
||||
*/
|
||||
if (passes > 0 || !(flags & FSYNC_WAIT))
|
||||
(void) bawrite(bp);
|
||||
else if ((error = bwrite(bp)) != 0)
|
||||
return (error);
|
||||
/*
|
||||
* Since we unlocked during the I/O, we need
|
||||
* to start from a known point.
|
||||
*/
|
||||
mutex_enter(&bufcache_lock);
|
||||
nbp = LIST_FIRST(&vp->v_dirtyblkhd);
|
||||
}
|
||||
mutex_exit(&bufcache_lock);
|
||||
if (skipmeta) {
|
||||
skipmeta = 0;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
if ((flags & FSYNC_WAIT) != 0) {
|
||||
mutex_enter(&vp->v_interlock);
|
||||
while (vp->v_numoutput) {
|
||||
cv_wait(&vp->v_cv, &vp->v_interlock);
|
||||
}
|
||||
mutex_exit(&vp->v_interlock);
|
||||
|
||||
if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
|
||||
/*
|
||||
* Block devices associated with filesystems may
|
||||
* have new I/O requests posted for them even if
|
||||
* the vnode is locked, so no amount of trying will
|
||||
* get them clean. Thus we give block devices a
|
||||
* good effort, then just give up. For all other file
|
||||
* types, go around and try again until it is clean.
|
||||
*/
|
||||
if (passes > 0) {
|
||||
passes--;
|
||||
goto loop;
|
||||
}
|
||||
#ifdef DIAGNOSTIC
|
||||
if (vp->v_type != VBLK)
|
||||
vprint("ffs_fsync: dirty", vp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
error = vflushbuf(vp, (flags & FSYNC_WAIT) != 0);
|
||||
if (error == 0 && (flags & FSYNC_CACHE) != 0) {
|
||||
i = 1;
|
||||
(void)VOP_IOCTL(vp, DIOCCACHESYNC, &i, FWRITE,
|
||||
kauth_cred_get());
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ffs_vnops.c,v 1.117 2011/04/15 15:54:11 hannken Exp $ */
|
||||
/* $NetBSD: ffs_vnops.c,v 1.118 2011/04/27 07:24:53 hannken Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
|
||||
@ -61,7 +61,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.117 2011/04/15 15:54:11 hannken Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.118 2011/04/27 07:24:53 hannken Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_ffs.h"
|
||||
@ -175,7 +175,7 @@ const struct vnodeopv_entry_desc ffs_specop_entries[] = {
|
||||
{ &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */
|
||||
{ &vop_revoke_desc, spec_revoke }, /* revoke */
|
||||
{ &vop_mmap_desc, spec_mmap }, /* mmap */
|
||||
{ &vop_fsync_desc, ffs_fsync }, /* fsync */
|
||||
{ &vop_fsync_desc, ffs_spec_fsync }, /* fsync */
|
||||
{ &vop_seek_desc, spec_seek }, /* seek */
|
||||
{ &vop_remove_desc, spec_remove }, /* remove */
|
||||
{ &vop_link_desc, spec_link }, /* link */
|
||||
@ -265,6 +265,61 @@ const struct vnodeopv_desc ffs_fifoop_opv_desc =
|
||||
|
||||
#include <ufs/ufs/ufs_readwrite.c>
|
||||
|
||||
int
|
||||
ffs_spec_fsync(void *v)
|
||||
{
|
||||
struct vop_fsync_args /* {
|
||||
struct vnode *a_vp;
|
||||
kauth_cred_t a_cred;
|
||||
int a_flags;
|
||||
off_t a_offlo;
|
||||
off_t a_offhi;
|
||||
struct lwp *a_l;
|
||||
} */ *ap = v;
|
||||
int error, flags, uflags;
|
||||
struct vnode *vp;
|
||||
struct mount *mp;
|
||||
|
||||
flags = ap->a_flags;
|
||||
uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0);
|
||||
vp = ap->a_vp;
|
||||
mp = vp->v_mount;
|
||||
|
||||
fstrans_start(mp, FSTRANS_LAZY);
|
||||
|
||||
error = spec_fsync(v);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
#ifdef WAPBL
|
||||
if (mp && mp->mnt_wapbl) {
|
||||
/*
|
||||
* Don't bother writing out metadata if the syncer is
|
||||
* making the request. We will let the sync vnode
|
||||
* write it out in a single burst through a call to
|
||||
* VFS_SYNC().
|
||||
*/
|
||||
if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0)
|
||||
goto out;
|
||||
if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE
|
||||
| IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) {
|
||||
error = UFS_WAPBL_BEGIN(mp);
|
||||
if (error != 0)
|
||||
goto out;
|
||||
error = ffs_update(vp, NULL, NULL, uflags);
|
||||
UFS_WAPBL_END(mp);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
#endif /* WAPBL */
|
||||
|
||||
error = ffs_update(vp, NULL, NULL, uflags);
|
||||
|
||||
out:
|
||||
fstrans_done(mp);
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
ffs_fsync(void *v)
|
||||
{
|
||||
@ -399,32 +454,27 @@ out:
|
||||
int
|
||||
ffs_full_fsync(struct vnode *vp, int flags)
|
||||
{
|
||||
struct buf *bp, *nbp;
|
||||
int error, passes, skipmeta, waitfor, i;
|
||||
int error, i, uflags;
|
||||
struct mount *mp;
|
||||
|
||||
KASSERT(VTOI(vp) != NULL);
|
||||
KASSERT(vp->v_tag == VT_UFS);
|
||||
KASSERT(VTOI(vp) != NULL);
|
||||
KASSERT(vp->v_type != VCHR && vp->v_type != VBLK);
|
||||
|
||||
error = 0;
|
||||
uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0);
|
||||
|
||||
mp = vp->v_mount;
|
||||
if (vp->v_type == VBLK && vp->v_specmountpoint != NULL) {
|
||||
mp = vp->v_specmountpoint;
|
||||
} else {
|
||||
mp = vp->v_mount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush all dirty data associated with the vnode.
|
||||
*/
|
||||
if (vp->v_type == VREG || vp->v_type == VBLK) {
|
||||
if (vp->v_type == VREG) {
|
||||
int pflags = PGO_ALLPAGES | PGO_CLEANIT;
|
||||
|
||||
if ((flags & FSYNC_WAIT))
|
||||
pflags |= PGO_SYNCIO;
|
||||
if (vp->v_type == VREG &&
|
||||
fstrans_getstate(mp) == FSTRANS_SUSPENDING)
|
||||
if (fstrans_getstate(mp) == FSTRANS_SUSPENDING)
|
||||
pflags |= PGO_FREE;
|
||||
mutex_enter(&vp->v_interlock);
|
||||
error = VOP_PUTPAGES(vp, 0, 0, pflags);
|
||||
@ -433,7 +483,6 @@ ffs_full_fsync(struct vnode *vp, int flags)
|
||||
}
|
||||
|
||||
#ifdef WAPBL
|
||||
mp = wapbl_vptomp(vp);
|
||||
if (mp && mp->mnt_wapbl) {
|
||||
/*
|
||||
* Don't bother writing out metadata if the syncer is
|
||||
@ -449,8 +498,7 @@ ffs_full_fsync(struct vnode *vp, int flags)
|
||||
error = UFS_WAPBL_BEGIN(mp);
|
||||
if (error)
|
||||
return error;
|
||||
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE |
|
||||
((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0));
|
||||
error = ffs_update(vp, NULL, NULL, uflags);
|
||||
UFS_WAPBL_END(mp);
|
||||
}
|
||||
if (error || (flags & FSYNC_NOLOG) != 0)
|
||||
@ -477,87 +525,11 @@ ffs_full_fsync(struct vnode *vp, int flags)
|
||||
}
|
||||
#endif /* WAPBL */
|
||||
|
||||
/*
|
||||
* Write out metadata for non-logging file systems. XXX This block
|
||||
* should be simplified now that softdep is gone.
|
||||
*/
|
||||
passes = NIADDR + 1;
|
||||
skipmeta = 0;
|
||||
if (flags & FSYNC_WAIT)
|
||||
skipmeta = 1;
|
||||
|
||||
loop:
|
||||
mutex_enter(&bufcache_lock);
|
||||
LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
|
||||
bp->b_cflags &= ~BC_SCANNED;
|
||||
}
|
||||
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
||||
nbp = LIST_NEXT(bp, b_vnbufs);
|
||||
if (bp->b_cflags & (BC_BUSY | BC_SCANNED))
|
||||
continue;
|
||||
if ((bp->b_oflags & BO_DELWRI) == 0)
|
||||
panic("ffs_fsync: not dirty");
|
||||
if (skipmeta && bp->b_lblkno < 0)
|
||||
continue;
|
||||
bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED;
|
||||
mutex_exit(&bufcache_lock);
|
||||
/*
|
||||
* On our final pass through, do all I/O synchronously
|
||||
* so that we can find out if our flush is failing
|
||||
* because of write errors.
|
||||
*/
|
||||
if (passes > 0 || !(flags & FSYNC_WAIT))
|
||||
(void) bawrite(bp);
|
||||
else if ((error = bwrite(bp)) != 0)
|
||||
return (error);
|
||||
/*
|
||||
* Since we unlocked during the I/O, we need
|
||||
* to start from a known point.
|
||||
*/
|
||||
mutex_enter(&bufcache_lock);
|
||||
nbp = LIST_FIRST(&vp->v_dirtyblkhd);
|
||||
}
|
||||
mutex_exit(&bufcache_lock);
|
||||
if (skipmeta) {
|
||||
skipmeta = 0;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
if ((flags & FSYNC_WAIT) != 0) {
|
||||
mutex_enter(&vp->v_interlock);
|
||||
while (vp->v_numoutput) {
|
||||
cv_wait(&vp->v_cv, &vp->v_interlock);
|
||||
}
|
||||
mutex_exit(&vp->v_interlock);
|
||||
|
||||
/*
|
||||
* Ensure that any filesystem metadata associated
|
||||
* with the vnode has been written.
|
||||
*/
|
||||
if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
|
||||
/*
|
||||
* Block devices associated with filesystems may
|
||||
* have new I/O requests posted for them even if
|
||||
* the vnode is locked, so no amount of trying will
|
||||
* get them clean. Thus we give block devices a
|
||||
* good effort, then just give up. For all other file
|
||||
* types, go around and try again until it is clean.
|
||||
*/
|
||||
if (passes > 0) {
|
||||
passes--;
|
||||
goto loop;
|
||||
}
|
||||
#ifdef DIAGNOSTIC
|
||||
if (vp->v_type != VBLK)
|
||||
vprint("ffs_fsync: dirty", vp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
waitfor = (flags & FSYNC_WAIT) ? UPDATE_WAIT : 0;
|
||||
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | waitfor);
|
||||
|
||||
error = vflushbuf(vp, (flags & FSYNC_WAIT) != 0);
|
||||
if (error == 0)
|
||||
error = ffs_update(vp, NULL, NULL, uflags);
|
||||
if (error == 0 && (flags & FSYNC_CACHE) != 0) {
|
||||
i = 1;
|
||||
(void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE,
|
||||
kauth_cred_get());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user