version 1.77.8.3, 2006/05/24 10:59:25 |
version 1.121.2.1, 2013/02/25 00:30:15 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
|
/*- |
|
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. |
|
* All rights reserved. |
|
* |
|
* This code is derived from software contributed to The NetBSD Foundation |
|
* by Wasabi Systems, Inc, and by Andrew Doran. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
* POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
/* |
/* |
* Copyright (c) 1982, 1986, 1989, 1993 |
* Copyright (c) 1982, 1986, 1989, 1993 |
* The Regents of the University of California. All rights reserved. |
* The Regents of the University of California. All rights reserved. |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#if defined(_KERNEL_OPT) |
|
#include "opt_ffs.h" |
|
#include "opt_wapbl.h" |
|
#endif |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/resourcevar.h> |
#include <sys/resourcevar.h> |
Line 48 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 82 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/pool.h> |
#include <sys/pool.h> |
#include <sys/signalvar.h> |
#include <sys/signalvar.h> |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
|
#include <sys/wapbl.h> |
|
#include <sys/fstrans.h> |
|
|
#include <miscfs/fifofs/fifo.h> |
#include <miscfs/fifofs/fifo.h> |
#include <miscfs/genfs/genfs.h> |
#include <miscfs/genfs/genfs.h> |
Line 57 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 93 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <ufs/ufs/dir.h> |
#include <ufs/ufs/dir.h> |
#include <ufs/ufs/ufs_extern.h> |
#include <ufs/ufs/ufs_extern.h> |
#include <ufs/ufs/ufsmount.h> |
#include <ufs/ufs/ufsmount.h> |
|
#include <ufs/ufs/ufs_wapbl.h> |
|
|
#include <ufs/ffs/fs.h> |
#include <ufs/ffs/fs.h> |
#include <ufs/ffs/ffs_extern.h> |
#include <ufs/ffs/ffs_extern.h> |
|
|
#include <uvm/uvm.h> |
#include <uvm/uvm.h> |
|
|
static int ffs_full_fsync(void *); |
|
|
|
/* Global vfs data structures for ufs. */ |
/* Global vfs data structures for ufs. */ |
int (**ffs_vnodeop_p)(void *); |
int (**ffs_vnodeop_p)(void *); |
const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { |
const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { |
Line 80 const struct vnodeopv_entry_desc ffs_vno |
|
Line 115 const struct vnodeopv_entry_desc ffs_vno |
|
{ &vop_setattr_desc, ufs_setattr }, /* setattr */ |
{ &vop_setattr_desc, ufs_setattr }, /* setattr */ |
{ &vop_read_desc, ffs_read }, /* read */ |
{ &vop_read_desc, ffs_read }, /* read */ |
{ &vop_write_desc, ffs_write }, /* write */ |
{ &vop_write_desc, ffs_write }, /* write */ |
{ &vop_lease_desc, ufs_lease_check }, /* lease */ |
|
{ &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ |
{ &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ |
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
{ &vop_poll_desc, ufs_poll }, /* poll */ |
{ &vop_poll_desc, ufs_poll }, /* poll */ |
Line 109 const struct vnodeopv_entry_desc ffs_vno |
|
Line 143 const struct vnodeopv_entry_desc ffs_vno |
|
{ &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ |
{ &vop_pathconf_desc, ufs_pathconf }, /* pathconf */ |
{ &vop_advlock_desc, ufs_advlock }, /* advlock */ |
{ &vop_advlock_desc, ufs_advlock }, /* advlock */ |
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_getpages_desc, ffs_getpages }, /* getpages */ |
{ &vop_getpages_desc, genfs_getpages }, /* getpages */ |
{ &vop_putpages_desc, genfs_putpages }, /* putpages */ |
{ &vop_putpages_desc, genfs_putpages }, /* putpages */ |
{ &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
{ &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
{ &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
{ &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
Line 135 const struct vnodeopv_entry_desc ffs_spe |
|
Line 169 const struct vnodeopv_entry_desc ffs_spe |
|
{ &vop_setattr_desc, ufs_setattr }, /* setattr */ |
{ &vop_setattr_desc, ufs_setattr }, /* setattr */ |
{ &vop_read_desc, ufsspec_read }, /* read */ |
{ &vop_read_desc, ufsspec_read }, /* read */ |
{ &vop_write_desc, ufsspec_write }, /* write */ |
{ &vop_write_desc, ufsspec_write }, /* write */ |
{ &vop_lease_desc, spec_lease_check }, /* lease */ |
|
{ &vop_ioctl_desc, spec_ioctl }, /* ioctl */ |
{ &vop_ioctl_desc, spec_ioctl }, /* ioctl */ |
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
{ &vop_poll_desc, spec_poll }, /* poll */ |
{ &vop_poll_desc, spec_poll }, /* poll */ |
{ &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_fsync }, /* fsync */ |
{ &vop_fsync_desc, ffs_spec_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 180 const struct vnodeopv_desc ffs_specop_op |
|
Line 213 const struct vnodeopv_desc ffs_specop_op |
|
int (**ffs_fifoop_p)(void *); |
int (**ffs_fifoop_p)(void *); |
const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { |
const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { |
{ &vop_default_desc, vn_default_error }, |
{ &vop_default_desc, vn_default_error }, |
{ &vop_lookup_desc, fifo_lookup }, /* lookup */ |
{ &vop_lookup_desc, vn_fifo_bypass }, /* lookup */ |
{ &vop_create_desc, fifo_create }, /* create */ |
{ &vop_create_desc, vn_fifo_bypass }, /* create */ |
{ &vop_mknod_desc, fifo_mknod }, /* mknod */ |
{ &vop_mknod_desc, vn_fifo_bypass }, /* mknod */ |
{ &vop_open_desc, fifo_open }, /* open */ |
{ &vop_open_desc, vn_fifo_bypass }, /* open */ |
{ &vop_close_desc, ufsfifo_close }, /* close */ |
{ &vop_close_desc, ufsfifo_close }, /* close */ |
{ &vop_access_desc, ufs_access }, /* access */ |
{ &vop_access_desc, ufs_access }, /* access */ |
{ &vop_getattr_desc, ufs_getattr }, /* getattr */ |
{ &vop_getattr_desc, ufs_getattr }, /* getattr */ |
{ &vop_setattr_desc, ufs_setattr }, /* setattr */ |
{ &vop_setattr_desc, ufs_setattr }, /* setattr */ |
{ &vop_read_desc, ufsfifo_read }, /* read */ |
{ &vop_read_desc, ufsfifo_read }, /* read */ |
{ &vop_write_desc, ufsfifo_write }, /* write */ |
{ &vop_write_desc, ufsfifo_write }, /* write */ |
{ &vop_lease_desc, fifo_lease_check }, /* lease */ |
{ &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */ |
{ &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ |
|
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
{ &vop_poll_desc, fifo_poll }, /* poll */ |
{ &vop_poll_desc, vn_fifo_bypass }, /* poll */ |
{ &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ |
{ &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */ |
{ &vop_revoke_desc, fifo_revoke }, /* revoke */ |
{ &vop_revoke_desc, vn_fifo_bypass }, /* revoke */ |
{ &vop_mmap_desc, fifo_mmap }, /* mmap */ |
{ &vop_mmap_desc, vn_fifo_bypass }, /* mmap */ |
{ &vop_fsync_desc, ffs_fsync }, /* fsync */ |
{ &vop_fsync_desc, ffs_fsync }, /* fsync */ |
{ &vop_seek_desc, fifo_seek }, /* seek */ |
{ &vop_seek_desc, vn_fifo_bypass }, /* seek */ |
{ &vop_remove_desc, fifo_remove }, /* remove */ |
{ &vop_remove_desc, vn_fifo_bypass }, /* remove */ |
{ &vop_link_desc, fifo_link }, /* link */ |
{ &vop_link_desc, vn_fifo_bypass }, /* link */ |
{ &vop_rename_desc, fifo_rename }, /* rename */ |
{ &vop_rename_desc, vn_fifo_bypass }, /* rename */ |
{ &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ |
{ &vop_mkdir_desc, vn_fifo_bypass }, /* mkdir */ |
{ &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ |
{ &vop_rmdir_desc, vn_fifo_bypass }, /* rmdir */ |
{ &vop_symlink_desc, fifo_symlink }, /* symlink */ |
{ &vop_symlink_desc, vn_fifo_bypass }, /* symlink */ |
{ &vop_readdir_desc, fifo_readdir }, /* readdir */ |
{ &vop_readdir_desc, vn_fifo_bypass }, /* readdir */ |
{ &vop_readlink_desc, fifo_readlink }, /* readlink */ |
{ &vop_readlink_desc, vn_fifo_bypass }, /* readlink */ |
{ &vop_abortop_desc, fifo_abortop }, /* abortop */ |
{ &vop_abortop_desc, vn_fifo_bypass }, /* abortop */ |
{ &vop_inactive_desc, ufs_inactive }, /* inactive */ |
{ &vop_inactive_desc, ufs_inactive }, /* inactive */ |
{ &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ |
{ &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ |
{ &vop_lock_desc, ufs_lock }, /* lock */ |
{ &vop_lock_desc, ufs_lock }, /* lock */ |
{ &vop_unlock_desc, ufs_unlock }, /* unlock */ |
{ &vop_unlock_desc, ufs_unlock }, /* unlock */ |
{ &vop_bmap_desc, fifo_bmap }, /* bmap */ |
{ &vop_bmap_desc, vn_fifo_bypass }, /* bmap */ |
{ &vop_strategy_desc, fifo_strategy }, /* strategy */ |
{ &vop_strategy_desc, vn_fifo_bypass }, /* strategy */ |
{ &vop_print_desc, ufs_print }, /* print */ |
{ &vop_print_desc, ufs_print }, /* print */ |
{ &vop_islocked_desc, ufs_islocked }, /* islocked */ |
{ &vop_islocked_desc, ufs_islocked }, /* islocked */ |
{ &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ |
{ &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */ |
{ &vop_advlock_desc, fifo_advlock }, /* advlock */ |
{ &vop_advlock_desc, vn_fifo_bypass }, /* advlock */ |
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_putpages_desc, fifo_putpages }, /* putpages */ |
{ &vop_putpages_desc, vn_fifo_bypass }, /* putpages */ |
{ &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
{ &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
{ &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
{ &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
{ &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ |
{ &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ |
Line 234 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 245 ffs_fsync(void *v) |
|
Line 332 ffs_fsync(void *v) |
|
struct lwp *a_l; |
struct lwp *a_l; |
} */ *ap = v; |
} */ *ap = v; |
struct buf *bp; |
struct buf *bp; |
int s, num, error, i; |
int num, error, i; |
struct indir ia[NIADDR + 1]; |
struct indir ia[UFS_NIADDR + 1]; |
int bsize; |
int bsize; |
daddr_t blk_high; |
daddr_t blk_high; |
struct vnode *vp; |
struct vnode *vp; |
|
struct mount *mp; |
/* |
|
* XXX no easy way to sync a range in a file with softdep. |
|
*/ |
|
if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(ap->a_vp) || |
|
(ap->a_vp->v_type != VREG)) |
|
return ffs_full_fsync(v); |
|
|
|
vp = ap->a_vp; |
vp = ap->a_vp; |
|
mp = vp->v_mount; |
|
|
|
fstrans_start(mp, FSTRANS_LAZY); |
|
if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) { |
|
error = ffs_full_fsync(vp, ap->a_flags); |
|
goto out; |
|
} |
|
|
bsize = ap->a_vp->v_mount->mnt_stat.f_iosize; |
bsize = mp->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 269 ffs_fsync(void *v) |
|
Line 357 ffs_fsync(void *v) |
|
* First, flush all pages in range. |
* First, flush all pages in range. |
*/ |
*/ |
|
|
simple_lock(&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)); |
if (error) { |
if (error) { |
|
goto out; |
|
} |
|
|
|
#ifdef WAPBL |
|
KASSERT(vp->v_type == VREG); |
|
if (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 ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) { |
|
fstrans_done(mp); |
|
return 0; |
|
} |
|
error = 0; |
|
if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag & |
|
(IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY | |
|
IN_MODIFIED | IN_ACCESSED)) { |
|
error = UFS_WAPBL_BEGIN(mp); |
|
if (error) { |
|
fstrans_done(mp); |
|
return error; |
|
} |
|
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
|
((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); |
|
UFS_WAPBL_END(mp); |
|
} |
|
if (error || (ap->a_flags & FSYNC_NOLOG) != 0) { |
|
fstrans_done(mp); |
|
return error; |
|
} |
|
error = wapbl_flush(mp->mnt_wapbl, 0); |
|
fstrans_done(mp); |
return error; |
return error; |
} |
} |
|
#endif /* WAPBL */ |
|
|
/* |
/* |
* Then, flush indirect blocks. |
* Then, flush indirect blocks. |
*/ |
*/ |
|
|
s = splbio(); |
if (blk_high >= UFS_NDADDR) { |
if (blk_high >= NDADDR) { |
|
error = ufs_getlbns(vp, blk_high, ia, &num); |
error = ufs_getlbns(vp, blk_high, ia, &num); |
if (error) { |
if (error) |
splx(s); |
goto out; |
return error; |
|
} |
mutex_enter(&bufcache_lock); |
for (i = 0; i < num; i++) { |
for (i = 0; i < num; i++) { |
bp = incore(vp, ia[i].in_lbn); |
if ((bp = incore(vp, ia[i].in_lbn)) == NULL) |
if (bp != NULL) { |
continue; |
simple_lock(&bp->b_interlock); |
if ((bp->b_cflags & BC_BUSY) != 0 || |
if (!(bp->b_flags & B_BUSY) && (bp->b_flags & B_DELWRI)) { |
(bp->b_oflags & BO_DELWRI) == 0) |
bp->b_flags |= B_BUSY | B_VFLUSH; |
continue; |
simple_unlock(&bp->b_interlock); |
bp->b_cflags |= BC_BUSY | BC_VFLUSH; |
splx(s); |
mutex_exit(&bufcache_lock); |
bawrite(bp); |
bawrite(bp); |
s = splbio(); |
mutex_enter(&bufcache_lock); |
} else { |
|
simple_unlock(&bp->b_interlock); |
|
} |
|
} |
|
} |
} |
|
mutex_exit(&bufcache_lock); |
} |
} |
|
|
if (ap->a_flags & FSYNC_WAIT) { |
if (ap->a_flags & FSYNC_WAIT) { |
simple_lock(&global_v_numoutput_slock); |
mutex_enter(vp->v_interlock); |
while (vp->v_numoutput > 0) { |
while (vp->v_numoutput > 0) |
vp->v_flag |= VBWAIT; |
cv_wait(&vp->v_cv, vp->v_interlock); |
ltsleep(&vp->v_numoutput, PRIBIO + 1, "fsync_range", 0, |
mutex_exit(vp->v_interlock); |
&global_v_numoutput_slock); |
|
} |
|
simple_unlock(&global_v_numoutput_slock); |
|
} |
} |
splx(s); |
|
|
|
error = ffs_update(vp, NULL, NULL, |
error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | |
((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) |
(((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) |
? UPDATE_WAIT : 0); |
? UPDATE_WAIT : 0)); |
|
|
if (error == 0 && ap->a_flags & FSYNC_CACHE) { |
if (error == 0 && ap->a_flags & FSYNC_CACHE) { |
int l = 0; |
int l = 0; |
VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, |
VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, |
ap->a_l->l_proc->p_cred, ap->a_l); |
curlwp->l_cred); |
} |
} |
|
|
|
out: |
|
fstrans_done(mp); |
return error; |
return error; |
} |
} |
|
|
/* |
/* |
* Synch an open file. |
* Synch an open file. Called for VOP_FSYNC(). |
*/ |
*/ |
/* ARGSUSED */ |
/* ARGSUSED */ |
static int |
int |
ffs_full_fsync(void *v) |
ffs_full_fsync(struct vnode *vp, int flags) |
{ |
{ |
struct vop_fsync_args /* { |
int error, i, uflags; |
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; |
|
struct vnode *vp = ap->a_vp; |
|
struct buf *bp, *nbp; |
|
int s, error, passes, skipmeta, inodedeps_only, waitfor; |
|
|
|
if (vp->v_type == VBLK && |
KASSERT(vp->v_tag == VT_UFS); |
vp->v_specmountpoint != NULL && |
KASSERT(VTOI(vp) != NULL); |
(vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP)) |
KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); |
softdep_fsync_mountdev(vp); |
|
|
|
inodedeps_only = DOINGSOFTDEP(vp) && (ap->a_flags & FSYNC_RECLAIM) |
uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); |
&& vp->v_uobj.uo_npages == 0 && LIST_EMPTY(&vp->v_dirtyblkhd); |
|
|
|
/* |
#ifdef WAPBL |
* Flush all dirty data associated with a vnode. |
struct mount *mp = vp->v_mount; |
*/ |
if (mp && mp->mnt_wapbl) { |
|
|
if (vp->v_type == VREG || vp->v_type == VBLK) { |
|
simple_lock(&vp->v_interlock); |
|
error = VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES | PGO_CLEANIT | |
|
((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); |
|
if (error) { |
|
return error; |
|
} |
|
} |
|
|
|
passes = NIADDR + 1; |
|
skipmeta = 0; |
|
if (ap->a_flags & FSYNC_WAIT) |
|
skipmeta = 1; |
|
s = splbio(); |
|
|
|
loop: |
|
LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) |
|
bp->b_flags &= ~B_SCANNED; |
|
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { |
|
nbp = LIST_NEXT(bp, b_vnbufs); |
|
simple_lock(&bp->b_interlock); |
|
if (bp->b_flags & (B_BUSY | B_SCANNED)) { |
|
simple_unlock(&bp->b_interlock); |
|
continue; |
|
} |
|
if ((bp->b_flags & B_DELWRI) == 0) |
|
panic("ffs_fsync: not dirty"); |
|
if (skipmeta && bp->b_lblkno < 0) { |
|
simple_unlock(&bp->b_interlock); |
|
continue; |
|
} |
|
simple_unlock(&bp->b_interlock); |
|
bp->b_flags |= B_BUSY | B_VFLUSH | B_SCANNED; |
|
splx(s); |
|
/* |
/* |
* On our final pass through, do all I/O synchronously |
* Flush all dirty data associated with the vnode. |
* so that we can find out if our flush is failing |
|
* because of write errors. |
|
*/ |
*/ |
if (passes > 0 || !(ap->a_flags & FSYNC_WAIT)) |
if (vp->v_type == VREG) { |
(void) bawrite(bp); |
int pflags = PGO_ALLPAGES | PGO_CLEANIT; |
else if ((error = bwrite(bp)) != 0) |
|
return (error); |
if ((flags & FSYNC_LAZY)) |
s = splbio(); |
pflags |= PGO_LAZY; |
|
if ((flags & FSYNC_WAIT)) |
|
pflags |= PGO_SYNCIO; |
|
if (fstrans_getstate(mp) == FSTRANS_SUSPENDING) |
|
pflags |= PGO_FREE; |
|
mutex_enter(vp->v_interlock); |
|
error = VOP_PUTPAGES(vp, 0, 0, pflags); |
|
if (error) |
|
return error; |
|
} |
|
|
/* |
/* |
* Since we may have slept during the I/O, we need |
* Don't bother writing out metadata if the syncer is |
* to start from a known point. |
* making the request. We will let the sync vnode |
|
* write it out in a single burst through a call to |
|
* VFS_SYNC(). |
*/ |
*/ |
nbp = LIST_FIRST(&vp->v_dirtyblkhd); |
if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) |
} |
return 0; |
if (skipmeta) { |
|
skipmeta = 0; |
if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE |
goto loop; |
| IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { |
} |
error = UFS_WAPBL_BEGIN(mp); |
if (ap->a_flags & FSYNC_WAIT) { |
if (error) |
simple_lock(&global_v_numoutput_slock); |
return error; |
while (vp->v_numoutput) { |
error = ffs_update(vp, NULL, NULL, uflags); |
vp->v_flag |= VBWAIT; |
UFS_WAPBL_END(mp); |
(void) ltsleep(&vp->v_numoutput, PRIBIO + 1, |
} else { |
"ffsfsync", 0, &global_v_numoutput_slock); |
error = 0; |
} |
} |
simple_unlock(&global_v_numoutput_slock); |
if (error || (flags & FSYNC_NOLOG) != 0) |
splx(s); |
return error; |
|
|
/* |
/* |
* Ensure that any filesystem metadata associated |
* Don't flush the log if the vnode being flushed |
* with the vnode has been written. |
* contains no dirty buffers that could be in the log. |
*/ |
*/ |
if ((error = softdep_sync_metadata(ap)) != 0) |
|
return (error); |
|
|
|
s = splbio(); |
|
if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { |
if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { |
/* |
error = wapbl_flush(mp->mnt_wapbl, 0); |
* Block devices associated with filesystems may |
if (error) |
* have new I/O requests posted for them even if |
return error; |
* 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 |
|
} |
} |
} |
|
splx(s); |
|
|
|
if (inodedeps_only) |
if ((flags & FSYNC_WAIT) != 0) { |
waitfor = 0; |
mutex_enter(vp->v_interlock); |
else |
while (vp->v_numoutput != 0) |
waitfor = (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0; |
cv_wait(&vp->v_cv, vp->v_interlock); |
error = ffs_update(vp, NULL, NULL, waitfor); |
mutex_exit(vp->v_interlock); |
|
} |
|
|
if (error == 0 && ap->a_flags & FSYNC_CACHE) { |
return error; |
int i = 0; |
} |
VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, |
#endif /* WAPBL */ |
ap->a_l->l_proc->p_cred, ap->a_l); |
|
|
error = vflushbuf(vp, flags); |
|
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()); |
} |
} |
|
|
return error; |
return error; |
Line 480 ffs_reclaim(void *v) |
|
Line 551 ffs_reclaim(void *v) |
|
} */ *ap = v; |
} */ *ap = v; |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct inode *ip = VTOI(vp); |
struct inode *ip = VTOI(vp); |
|
struct mount *mp = vp->v_mount; |
struct ufsmount *ump = ip->i_ump; |
struct ufsmount *ump = ip->i_ump; |
|
void *data; |
int error; |
int error; |
|
|
if ((error = ufs_reclaim(vp, ap->a_l)) != 0) |
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) { |
|
fstrans_done(mp); |
return (error); |
return (error); |
|
} |
if (ip->i_din.ffs1_din != NULL) { |
if (ip->i_din.ffs1_din != NULL) { |
if (ump->um_fstype == UFS1) |
if (ump->um_fstype == UFS1) |
pool_put(&ffs_dinode1_pool, ip->i_din.ffs1_din); |
pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); |
else |
else |
pool_put(&ffs_dinode2_pool, ip->i_din.ffs2_din); |
pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); |
} |
} |
/* |
/* |
* XXX MFS ends up here, too, to free an inode. Should we create |
* To interlock with ffs_sync(). |
* XXX a separate pool for MFS inodes? |
|
*/ |
*/ |
pool_put(&ffs_inode_pool, vp->v_data); |
genfs_node_destroy(vp); |
|
mutex_enter(vp->v_interlock); |
|
data = vp->v_data; |
vp->v_data = NULL; |
vp->v_data = NULL; |
return (0); |
mutex_exit(vp->v_interlock); |
} |
|
|
|
int |
|
ffs_getpages(void *v) |
|
{ |
|
struct vop_getpages_args /* { |
|
struct vnode *a_vp; |
|
voff_t a_offset; |
|
struct vm_page **a_m; |
|
int *a_count; |
|
int a_centeridx; |
|
vm_prot_t a_access_type; |
|
int a_advice; |
|
int a_flags; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
struct inode *ip = VTOI(vp); |
|
struct fs *fs = ip->i_fs; |
|
|
|
/* |
/* |
* don't allow a softdep write to create pages for only part of a block. |
* XXX MFS ends up here, too, to free an inode. Should we create |
* the dependency tracking requires that all pages be in memory for |
* XXX a separate pool for MFS inodes? |
* a block involved in a dependency. |
|
*/ |
*/ |
|
pool_cache_put(ffs_inode_cache, data); |
if (ap->a_flags & PGO_OVERWRITE && |
fstrans_done(mp); |
(blkoff(fs, ap->a_offset) != 0 || |
return (0); |
blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) && |
|
DOINGSOFTDEP(ap->a_vp)) { |
|
if ((ap->a_flags & PGO_LOCKED) == 0) { |
|
simple_unlock(&vp->v_interlock); |
|
} |
|
return EINVAL; |
|
} |
|
return genfs_getpages(v); |
|
} |
} |
|
|
/* |
/* |
Line 549 ffs_gop_size(struct vnode *vp, off_t siz |
|
Line 613 ffs_gop_size(struct vnode *vp, off_t siz |
|
|
|
olbn = lblkno(fs, ip->i_size); |
olbn = lblkno(fs, ip->i_size); |
nlbn = lblkno(fs, size); |
nlbn = lblkno(fs, size); |
if (nlbn < NDADDR && olbn <= nlbn) { |
if (nlbn < UFS_NDADDR && olbn <= nlbn) { |
*eobp = fragroundup(fs, size); |
*eobp = fragroundup(fs, size); |
} else { |
} else { |
*eobp = blkroundup(fs, size); |
*eobp = blkroundup(fs, size); |
Line 607 ffs_getextattr(void *v) |
|
Line 671 ffs_getextattr(void *v) |
|
kauth_cred_t a_cred; |
kauth_cred_t a_cred; |
struct proc *a_p; |
struct proc *a_p; |
} */ *ap = v; |
} */ *ap = v; |
struct inode *ip = VTOI(ap->a_vp); |
struct vnode *vp = ap->a_vp; |
|
struct inode *ip = VTOI(vp); |
struct fs *fs = ip->i_fs; |
struct fs *fs = ip->i_fs; |
|
|
if (fs->fs_magic == FS_UFS1_MAGIC) { |
if (fs->fs_magic == FS_UFS1_MAGIC) { |
#ifdef UFS_EXTATTR |
#ifdef UFS_EXTATTR |
return (ufs_getextattr(ap)); |
int error; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
|
error = ufs_getextattr(ap); |
|
fstrans_done(vp->v_mount); |
|
return error; |
#else |
#else |
return (EOPNOTSUPP); |
return (EOPNOTSUPP); |
#endif |
#endif |
Line 633 ffs_setextattr(void *v) |
|
Line 703 ffs_setextattr(void *v) |
|
kauth_cred_t a_cred; |
kauth_cred_t a_cred; |
struct proc *a_p; |
struct proc *a_p; |
} */ *ap = v; |
} */ *ap = v; |
struct inode *ip = VTOI(ap->a_vp); |
struct vnode *vp = ap->a_vp; |
|
struct inode *ip = VTOI(vp); |
struct fs *fs = ip->i_fs; |
struct fs *fs = ip->i_fs; |
|
|
if (fs->fs_magic == FS_UFS1_MAGIC) { |
if (fs->fs_magic == FS_UFS1_MAGIC) { |
#ifdef UFS_EXTATTR |
#ifdef UFS_EXTATTR |
return (ufs_setextattr(ap)); |
int error; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
|
error = ufs_setextattr(ap); |
|
fstrans_done(vp->v_mount); |
|
return error; |
#else |
#else |
return (EOPNOTSUPP); |
return (EOPNOTSUPP); |
#endif |
#endif |
Line 662 ffs_listextattr(void *v) |
|
Line 738 ffs_listextattr(void *v) |
|
struct inode *ip = VTOI(ap->a_vp); |
struct inode *ip = VTOI(ap->a_vp); |
struct fs *fs = ip->i_fs; |
struct fs *fs = ip->i_fs; |
|
|
/* Not supported for UFS1 file systems. */ |
if (fs->fs_magic == FS_UFS1_MAGIC) { |
if (fs->fs_magic == FS_UFS1_MAGIC) |
#ifdef UFS_EXTATTR |
|
struct vnode *vp = ap->a_vp; |
|
int error; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
|
error = ufs_listextattr(ap); |
|
fstrans_done(vp->v_mount); |
|
return error; |
|
#else |
return (EOPNOTSUPP); |
return (EOPNOTSUPP); |
|
#endif |
|
} |
|
|
/* XXX Not implemented for UFS2 file systems. */ |
/* XXX Not implemented for UFS2 file systems. */ |
return (EOPNOTSUPP); |
return (EOPNOTSUPP); |
Line 679 ffs_deleteextattr(void *v) |
|
Line 765 ffs_deleteextattr(void *v) |
|
kauth_cred_t a_cred; |
kauth_cred_t a_cred; |
struct proc *a_p; |
struct proc *a_p; |
} */ *ap = v; |
} */ *ap = v; |
struct inode *ip = VTOI(ap->a_vp); |
struct vnode *vp = ap->a_vp; |
|
struct inode *ip = VTOI(vp); |
struct fs *fs = ip->i_fs; |
struct fs *fs = ip->i_fs; |
|
|
if (fs->fs_magic == FS_UFS1_MAGIC) { |
if (fs->fs_magic == FS_UFS1_MAGIC) { |
#ifdef UFS_EXTATTR |
#ifdef UFS_EXTATTR |
return (ufs_deleteextattr(ap)); |
int error; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
|
error = ufs_deleteextattr(ap); |
|
fstrans_done(vp->v_mount); |
|
return error; |
#else |
#else |
return (EOPNOTSUPP); |
return (EOPNOTSUPP); |
#endif |
#endif |