version 1.116.2.1, 2011/06/06 09:10:16 |
version 1.117, 2011/04/15 15:54:11 |
Line 175 const struct vnodeopv_entry_desc ffs_spe |
|
Line 175 const struct vnodeopv_entry_desc ffs_spe |
|
{ &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ |
{ &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ |
{ &vop_revoke_desc, spec_revoke }, /* revoke */ |
{ &vop_revoke_desc, spec_revoke }, /* revoke */ |
{ &vop_mmap_desc, spec_mmap }, /* mmap */ |
{ &vop_mmap_desc, spec_mmap }, /* mmap */ |
{ &vop_fsync_desc, ffs_spec_fsync }, /* fsync */ |
{ &vop_fsync_desc, ffs_fsync }, /* fsync */ |
{ &vop_seek_desc, spec_seek }, /* seek */ |
{ &vop_seek_desc, spec_seek }, /* seek */ |
{ &vop_remove_desc, spec_remove }, /* remove */ |
{ &vop_remove_desc, spec_remove }, /* remove */ |
{ &vop_link_desc, spec_link }, /* link */ |
{ &vop_link_desc, spec_link }, /* link */ |
Line 266 const struct vnodeopv_desc ffs_fifoop_op |
|
Line 266 const struct vnodeopv_desc ffs_fifoop_op |
|
#include <ufs/ufs/ufs_readwrite.c> |
#include <ufs/ufs/ufs_readwrite.c> |
|
|
int |
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) |
ffs_fsync(void *v) |
{ |
{ |
struct vop_fsync_args /* { |
struct vop_fsync_args /* { |
|
|
int |
int |
ffs_full_fsync(struct vnode *vp, int flags) |
ffs_full_fsync(struct vnode *vp, int flags) |
{ |
{ |
int error, i, uflags; |
struct buf *bp, *nbp; |
|
int error, passes, skipmeta, waitfor, i; |
struct mount *mp; |
struct mount *mp; |
|
|
KASSERT(vp->v_tag == VT_UFS); |
|
KASSERT(VTOI(vp) != NULL); |
KASSERT(VTOI(vp) != NULL); |
KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); |
KASSERT(vp->v_tag == VT_UFS); |
|
|
error = 0; |
error = 0; |
uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); |
|
|
|
mp = vp->v_mount; |
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. |
* Flush all dirty data associated with the vnode. |
*/ |
*/ |
if (vp->v_type == VREG) { |
if (vp->v_type == VREG || vp->v_type == VBLK) { |
int pflags = PGO_ALLPAGES | PGO_CLEANIT; |
int pflags = PGO_ALLPAGES | PGO_CLEANIT; |
|
|
if ((flags & FSYNC_WAIT)) |
if ((flags & FSYNC_WAIT)) |
pflags |= PGO_SYNCIO; |
pflags |= PGO_SYNCIO; |
if (fstrans_getstate(mp) == FSTRANS_SUSPENDING) |
if (vp->v_type == VREG && |
|
fstrans_getstate(mp) == FSTRANS_SUSPENDING) |
pflags |= PGO_FREE; |
pflags |= PGO_FREE; |
mutex_enter(&vp->v_interlock); |
mutex_enter(&vp->v_interlock); |
error = VOP_PUTPAGES(vp, 0, 0, pflags); |
error = VOP_PUTPAGES(vp, 0, 0, pflags); |
Line 483 ffs_full_fsync(struct vnode *vp, int fla |
|
Line 433 ffs_full_fsync(struct vnode *vp, int fla |
|
} |
} |
|
|
#ifdef WAPBL |
#ifdef WAPBL |
|
mp = wapbl_vptomp(vp); |
if (mp && mp->mnt_wapbl) { |
if (mp && mp->mnt_wapbl) { |
/* |
/* |
* Don't bother writing out metadata if the syncer is |
* Don't bother writing out metadata if the syncer is |
Line 498 ffs_full_fsync(struct vnode *vp, int fla |
|
Line 449 ffs_full_fsync(struct vnode *vp, int fla |
|
error = UFS_WAPBL_BEGIN(mp); |
error = UFS_WAPBL_BEGIN(mp); |
if (error) |
if (error) |
return error; |
return error; |
error = ffs_update(vp, NULL, NULL, uflags); |
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
|
((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); |
UFS_WAPBL_END(mp); |
UFS_WAPBL_END(mp); |
} |
} |
if (error || (flags & FSYNC_NOLOG) != 0) |
if (error || (flags & FSYNC_NOLOG) != 0) |
Line 525 ffs_full_fsync(struct vnode *vp, int fla |
|
Line 477 ffs_full_fsync(struct vnode *vp, int fla |
|
} |
} |
#endif /* WAPBL */ |
#endif /* WAPBL */ |
|
|
error = vflushbuf(vp, (flags & FSYNC_WAIT) != 0); |
/* |
if (error == 0) |
* Write out metadata for non-logging file systems. XXX This block |
error = ffs_update(vp, NULL, NULL, uflags); |
* 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); |
|
|
if (error == 0 && (flags & FSYNC_CACHE) != 0) { |
if (error == 0 && (flags & FSYNC_CACHE) != 0) { |
i = 1; |
|
(void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, |
(void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, |
kauth_cred_get()); |
kauth_cred_get()); |
} |
} |