version 1.113.4.5, 2011/05/31 03:05:13 |
version 1.114, 2010/03/29 13:11:33 |
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 /* { |
Line 337 ffs_fsync(void *v) |
|
Line 282 ffs_fsync(void *v) |
|
int bsize; |
int bsize; |
daddr_t blk_high; |
daddr_t blk_high; |
struct vnode *vp; |
struct vnode *vp; |
|
#ifdef WAPBL |
struct mount *mp; |
struct mount *mp; |
|
#endif |
|
|
vp = ap->a_vp; |
vp = ap->a_vp; |
mp = vp->v_mount; |
|
|
|
fstrans_start(mp, FSTRANS_LAZY); |
fstrans_start(vp->v_mount, FSTRANS_LAZY); |
if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { |
if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { |
error = ffs_full_fsync(vp, ap->a_flags); |
error = ffs_full_fsync(vp, ap->a_flags); |
goto out; |
goto out; |
} |
} |
|
|
bsize = mp->mnt_stat.f_iosize; |
bsize = vp->v_mount->mnt_stat.f_iosize; |
blk_high = ap->a_offhi / bsize; |
blk_high = ap->a_offhi / bsize; |
if (ap->a_offhi % bsize != 0) |
if (ap->a_offhi % bsize != 0) |
blk_high++; |
blk_high++; |
Line 357 ffs_fsync(void *v) |
|
Line 303 ffs_fsync(void *v) |
|
* First, flush all pages in range. |
* First, flush all pages in range. |
*/ |
*/ |
|
|
mutex_enter(vp->v_interlock); |
mutex_enter(&vp->v_interlock); |
error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), |
error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), |
round_page(ap->a_offhi), PGO_CLEANIT | |
round_page(ap->a_offhi), PGO_CLEANIT | |
((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); |
((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); |
Line 366 ffs_fsync(void *v) |
|
Line 312 ffs_fsync(void *v) |
|
} |
} |
|
|
#ifdef WAPBL |
#ifdef WAPBL |
KASSERT(vp->v_type == VREG); |
mp = wapbl_vptomp(vp); |
if (mp->mnt_wapbl) { |
if (mp->mnt_wapbl) { |
/* |
/* |
* Don't bother writing out metadata if the syncer is |
* Don't bother writing out metadata if the syncer is |
Line 375 ffs_fsync(void *v) |
|
Line 321 ffs_fsync(void *v) |
|
* VFS_SYNC(). |
* VFS_SYNC(). |
*/ |
*/ |
if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { |
if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { |
fstrans_done(mp); |
fstrans_done(vp->v_mount); |
return 0; |
return 0; |
} |
} |
error = 0; |
error = 0; |
Line 384 ffs_fsync(void *v) |
|
Line 330 ffs_fsync(void *v) |
|
IN_MODIFIED | IN_ACCESSED)) { |
IN_MODIFIED | IN_ACCESSED)) { |
error = UFS_WAPBL_BEGIN(mp); |
error = UFS_WAPBL_BEGIN(mp); |
if (error) { |
if (error) { |
fstrans_done(mp); |
fstrans_done(vp->v_mount); |
return error; |
return error; |
} |
} |
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
Line 392 ffs_fsync(void *v) |
|
Line 338 ffs_fsync(void *v) |
|
UFS_WAPBL_END(mp); |
UFS_WAPBL_END(mp); |
} |
} |
if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { |
if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { |
fstrans_done(mp); |
fstrans_done(vp->v_mount); |
return error; |
return error; |
} |
} |
error = wapbl_flush(mp->mnt_wapbl, 0); |
error = wapbl_flush(mp->mnt_wapbl, 0); |
fstrans_done(mp); |
fstrans_done(vp->v_mount); |
return error; |
return error; |
} |
} |
#endif /* WAPBL */ |
#endif /* WAPBL */ |
Line 426 ffs_fsync(void *v) |
|
Line 372 ffs_fsync(void *v) |
|
} |
} |
|
|
if (ap->a_flags & FSYNC_WAIT) { |
if (ap->a_flags & FSYNC_WAIT) { |
mutex_enter(vp->v_interlock); |
mutex_enter(&vp->v_interlock); |
while (vp->v_numoutput > 0) |
while (vp->v_numoutput > 0) |
cv_wait(&vp->v_cv, vp->v_interlock); |
cv_wait(&vp->v_cv, &vp->v_interlock); |
mutex_exit(vp->v_interlock); |
mutex_exit(&vp->v_interlock); |
} |
} |
|
|
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
Line 443 ffs_fsync(void *v) |
|
Line 389 ffs_fsync(void *v) |
|
} |
} |
|
|
out: |
out: |
fstrans_done(mp); |
fstrans_done(vp->v_mount); |
return error; |
return error; |
} |
} |
|
|
|
|
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); |
if (error) |
if (error) |
return error; |
return error; |
} |
} |
|
|
#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 450 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 515 ffs_full_fsync(struct vnode *vp, int fla |
|
Line 468 ffs_full_fsync(struct vnode *vp, int fla |
|
} |
} |
|
|
if ((flags & FSYNC_WAIT) != 0) { |
if ((flags & FSYNC_WAIT) != 0) { |
mutex_enter(vp->v_interlock); |
mutex_enter(&vp->v_interlock); |
while (vp->v_numoutput != 0) |
while (vp->v_numoutput != 0) |
cv_wait(&vp->v_cv, vp->v_interlock); |
cv_wait(&vp->v_cv, &vp->v_interlock); |
mutex_exit(vp->v_interlock); |
mutex_exit(&vp->v_interlock); |
} |
} |
|
|
return error; |
return error; |
} |
} |
#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()); |
} |
} |
Line 555 ffs_reclaim(void *v) |
|
Line 584 ffs_reclaim(void *v) |
|
int error; |
int error; |
|
|
fstrans_start(mp, FSTRANS_LAZY); |
fstrans_start(mp, FSTRANS_LAZY); |
/* |
|
* The inode must be freed and updated before being removed |
|
* from its hash chain. Other threads trying to gain a hold |
|
* on the inode will be stalled because it is locked (VI_XLOCK). |
|
*/ |
|
error = UFS_WAPBL_BEGIN(mp); |
|
if (error) { |
|
fstrans_done(mp); |
|
return error; |
|
} |
|
if (ip->i_nlink <= 0 && ip->i_omode != 0 && |
|
(vp->v_mount->mnt_flag & MNT_RDONLY) == 0) |
|
ffs_vfree(vp, ip->i_number, ip->i_omode); |
|
UFS_WAPBL_END(mp); |
|
if ((error = ufs_reclaim(vp)) != 0) { |
if ((error = ufs_reclaim(vp)) != 0) { |
fstrans_done(mp); |
fstrans_done(mp); |
return (error); |
return (error); |
Line 583 ffs_reclaim(void *v) |
|
Line 598 ffs_reclaim(void *v) |
|
* To interlock with ffs_sync(). |
* To interlock with ffs_sync(). |
*/ |
*/ |
genfs_node_destroy(vp); |
genfs_node_destroy(vp); |
mutex_enter(vp->v_interlock); |
mutex_enter(&vp->v_interlock); |
data = vp->v_data; |
data = vp->v_data; |
vp->v_data = NULL; |
vp->v_data = NULL; |
mutex_exit(vp->v_interlock); |
mutex_exit(&vp->v_interlock); |
|
|
/* |
/* |
* XXX MFS ends up here, too, to free an inode. Should we create |
* XXX MFS ends up here, too, to free an inode. Should we create |