version 1.16.2.5, 1999/05/30 15:16:01 |
version 1.86.4.10, 2007/08/24 23:28:45 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* 3. Neither the name of the University nor the names of its contributors |
* must display the following acknowledgement: |
|
* This product includes software developed by the University of |
|
* California, Berkeley and its contributors. |
|
* 4. Neither the name of the University nor the names of its contributors |
|
* may be used to endorse or promote products derived from this software |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* without specific prior written permission. |
* |
* |
|
|
* @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 |
* @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 |
*/ |
*/ |
|
|
#if defined(_KERNEL) && !defined(_LKM) |
#include <sys/cdefs.h> |
#include "opt_uvm.h" |
__KERNEL_RCSID(0, "$NetBSD$"); |
#include "opt_uvmhist.h" |
|
#endif |
|
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
|
|
#include <sys/file.h> |
#include <sys/file.h> |
#include <sys/stat.h> |
#include <sys/stat.h> |
#include <sys/buf.h> |
#include <sys/buf.h> |
|
#include <sys/event.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
#include <sys/conf.h> |
|
#include <sys/mount.h> |
#include <sys/mount.h> |
#include <sys/vnode.h> |
#include <sys/vnode.h> |
#include <sys/malloc.h> |
|
#include <sys/pool.h> |
#include <sys/pool.h> |
#include <sys/signalvar.h> |
#include <sys/signalvar.h> |
|
#include <sys/kauth.h> |
#include <vm/vm.h> |
#include <sys/fstrans.h> |
|
|
#if defined(UVM) |
|
#include <uvm/uvm_extern.h> |
|
#endif |
|
|
|
#include <miscfs/fifofs/fifo.h> |
#include <miscfs/fifofs/fifo.h> |
#include <miscfs/genfs/genfs.h> |
#include <miscfs/genfs/genfs.h> |
#include <miscfs/specfs/specdev.h> |
#include <miscfs/specfs/specdev.h> |
|
|
#include <ufs/ufs/quota.h> |
|
#include <ufs/ufs/inode.h> |
#include <ufs/ufs/inode.h> |
#include <ufs/ufs/dir.h> |
#include <ufs/ufs/dir.h> |
#include <ufs/ufs/ufs_extern.h> |
#include <ufs/ufs/ufs_extern.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> |
|
|
|
static int ffs_full_fsync(void *); |
|
|
/* Global vfs data structures for ufs. */ |
/* Global vfs data structures for ufs. */ |
int (**ffs_vnodeop_p) __P((void *)); |
int (**ffs_vnodeop_p)(void *); |
struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { |
const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { |
{ &vop_default_desc, vn_default_error }, |
{ &vop_default_desc, vn_default_error }, |
{ &vop_lookup_desc, ufs_lookup }, /* lookup */ |
{ &vop_lookup_desc, ufs_lookup }, /* lookup */ |
{ &vop_create_desc, ufs_create }, /* create */ |
{ &vop_create_desc, ufs_create }, /* create */ |
Line 91 struct vnodeopv_entry_desc ffs_vnodeop_e |
|
Line 83 struct vnodeopv_entry_desc ffs_vnodeop_e |
|
{ &vop_write_desc, ffs_write }, /* write */ |
{ &vop_write_desc, ffs_write }, /* write */ |
{ &vop_lease_desc, ufs_lease_check }, /* lease */ |
{ &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_poll_desc, ufs_poll }, /* poll */ |
{ &vop_poll_desc, ufs_poll }, /* poll */ |
|
{ &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ |
{ &vop_revoke_desc, ufs_revoke }, /* revoke */ |
{ &vop_revoke_desc, ufs_revoke }, /* revoke */ |
{ &vop_mmap_desc, ufs_mmap }, /* mmap */ |
{ &vop_mmap_desc, ufs_mmap }, /* mmap */ |
{ &vop_fsync_desc, ffs_fsync }, /* fsync */ |
{ &vop_fsync_desc, ffs_fsync }, /* fsync */ |
Line 107 struct vnodeopv_entry_desc ffs_vnodeop_e |
|
Line 101 struct vnodeopv_entry_desc ffs_vnodeop_e |
|
{ &vop_abortop_desc, ufs_abortop }, /* abortop */ |
{ &vop_abortop_desc, ufs_abortop }, /* 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, ffs_lock }, /* lock */ |
{ &vop_unlock_desc, ufs_unlock }, /* unlock */ |
{ &vop_unlock_desc, ffs_unlock }, /* unlock */ |
{ &vop_bmap_desc, ufs_bmap }, /* bmap */ |
{ &vop_bmap_desc, ufs_bmap }, /* bmap */ |
{ &vop_strategy_desc, ufs_strategy }, /* strategy */ |
{ &vop_strategy_desc, ufs_strategy }, /* strategy */ |
{ &vop_print_desc, ufs_print }, /* print */ |
{ &vop_print_desc, ufs_print }, /* print */ |
{ &vop_islocked_desc, ufs_islocked }, /* islocked */ |
{ &vop_islocked_desc, ffs_islocked }, /* islocked */ |
{ &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_blkatoff_desc, ffs_blkatoff }, /* blkatoff */ |
|
{ &vop_valloc_desc, ffs_valloc }, /* valloc */ |
|
{ &vop_reallocblks_desc, ffs_reallocblks }, /* reallocblks */ |
|
{ &vop_vfree_desc, ffs_vfree }, /* vfree */ |
|
{ &vop_truncate_desc, ffs_truncate }, /* truncate */ |
|
{ &vop_update_desc, ffs_update }, /* update */ |
|
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
#ifdef UBC |
{ &vop_getpages_desc, genfs_getpages }, /* getpages */ |
{ &vop_getpages_desc, ffs_getpages }, /* getpages */ |
{ &vop_putpages_desc, genfs_putpages }, /* putpages */ |
{ &vop_putpages_desc, ffs_putpages }, /* putpages */ |
{ &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
#endif |
{ &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
|
{ &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ |
|
{ &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ |
|
{ &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ |
|
{ &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ |
{ NULL, NULL } |
{ NULL, NULL } |
}; |
}; |
struct vnodeopv_desc ffs_vnodeop_opv_desc = |
const struct vnodeopv_desc ffs_vnodeop_opv_desc = |
{ &ffs_vnodeop_p, ffs_vnodeop_entries }; |
{ &ffs_vnodeop_p, ffs_vnodeop_entries }; |
|
|
int (**ffs_specop_p) __P((void *)); |
int (**ffs_specop_p)(void *); |
struct vnodeopv_entry_desc ffs_specop_entries[] = { |
const struct vnodeopv_entry_desc ffs_specop_entries[] = { |
{ &vop_default_desc, vn_default_error }, |
{ &vop_default_desc, vn_default_error }, |
{ &vop_lookup_desc, spec_lookup }, /* lookup */ |
{ &vop_lookup_desc, spec_lookup }, /* lookup */ |
{ &vop_create_desc, spec_create }, /* create */ |
{ &vop_create_desc, spec_create }, /* create */ |
Line 146 struct vnodeopv_entry_desc ffs_specop_en |
|
Line 138 struct vnodeopv_entry_desc ffs_specop_en |
|
{ &vop_write_desc, ufsspec_write }, /* write */ |
{ &vop_write_desc, ufsspec_write }, /* write */ |
{ &vop_lease_desc, spec_lease_check }, /* lease */ |
{ &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_poll_desc, spec_poll }, /* poll */ |
{ &vop_poll_desc, spec_poll }, /* poll */ |
|
{ &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_fsync }, /* fsync */ |
Line 162 struct vnodeopv_entry_desc ffs_specop_en |
|
Line 156 struct vnodeopv_entry_desc ffs_specop_en |
|
{ &vop_abortop_desc, spec_abortop }, /* abortop */ |
{ &vop_abortop_desc, spec_abortop }, /* 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, ffs_lock }, /* lock */ |
{ &vop_unlock_desc, ufs_unlock }, /* unlock */ |
{ &vop_unlock_desc, ffs_unlock }, /* unlock */ |
{ &vop_bmap_desc, spec_bmap }, /* bmap */ |
{ &vop_bmap_desc, spec_bmap }, /* bmap */ |
{ &vop_strategy_desc, spec_strategy }, /* strategy */ |
{ &vop_strategy_desc, spec_strategy }, /* strategy */ |
{ &vop_print_desc, ufs_print }, /* print */ |
{ &vop_print_desc, ufs_print }, /* print */ |
{ &vop_islocked_desc, ufs_islocked }, /* islocked */ |
{ &vop_islocked_desc, ffs_islocked }, /* islocked */ |
{ &vop_pathconf_desc, spec_pathconf }, /* pathconf */ |
{ &vop_pathconf_desc, spec_pathconf }, /* pathconf */ |
{ &vop_advlock_desc, spec_advlock }, /* advlock */ |
{ &vop_advlock_desc, spec_advlock }, /* advlock */ |
{ &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ |
|
{ &vop_valloc_desc, spec_valloc }, /* valloc */ |
|
{ &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */ |
|
{ &vop_vfree_desc, ffs_vfree }, /* vfree */ |
|
{ &vop_truncate_desc, spec_truncate }, /* truncate */ |
|
{ &vop_update_desc, ffs_update }, /* update */ |
|
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL } |
{ &vop_getpages_desc, spec_getpages }, /* getpages */ |
|
{ &vop_putpages_desc, spec_putpages }, /* putpages */ |
|
{ &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
|
{ &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
|
{ &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ |
|
{ &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ |
|
{ &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ |
|
{ &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ |
|
{ NULL, NULL } |
}; |
}; |
struct vnodeopv_desc ffs_specop_opv_desc = |
const struct vnodeopv_desc ffs_specop_opv_desc = |
{ &ffs_specop_p, ffs_specop_entries }; |
{ &ffs_specop_p, ffs_specop_entries }; |
|
|
int (**ffs_fifoop_p) __P((void *)); |
int (**ffs_fifoop_p)(void *); |
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, fifo_lookup }, /* lookup */ |
{ &vop_create_desc, fifo_create }, /* create */ |
{ &vop_create_desc, fifo_create }, /* create */ |
Line 197 struct vnodeopv_entry_desc ffs_fifoop_en |
|
Line 193 struct vnodeopv_entry_desc ffs_fifoop_en |
|
{ &vop_write_desc, ufsfifo_write }, /* write */ |
{ &vop_write_desc, ufsfifo_write }, /* write */ |
{ &vop_lease_desc, fifo_lease_check }, /* lease */ |
{ &vop_lease_desc, fifo_lease_check }, /* lease */ |
{ &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ |
{ &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ |
|
{ &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ |
{ &vop_poll_desc, fifo_poll }, /* poll */ |
{ &vop_poll_desc, fifo_poll }, /* poll */ |
|
{ &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ |
{ &vop_revoke_desc, fifo_revoke }, /* revoke */ |
{ &vop_revoke_desc, fifo_revoke }, /* revoke */ |
{ &vop_mmap_desc, fifo_mmap }, /* mmap */ |
{ &vop_mmap_desc, fifo_mmap }, /* mmap */ |
{ &vop_fsync_desc, ffs_fsync }, /* fsync */ |
{ &vop_fsync_desc, ffs_fsync }, /* fsync */ |
Line 213 struct vnodeopv_entry_desc ffs_fifoop_en |
|
Line 211 struct vnodeopv_entry_desc ffs_fifoop_en |
|
{ &vop_abortop_desc, fifo_abortop }, /* abortop */ |
{ &vop_abortop_desc, fifo_abortop }, /* 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, ffs_lock }, /* lock */ |
{ &vop_unlock_desc, ufs_unlock }, /* unlock */ |
{ &vop_unlock_desc, ffs_unlock }, /* unlock */ |
{ &vop_bmap_desc, fifo_bmap }, /* bmap */ |
{ &vop_bmap_desc, fifo_bmap }, /* bmap */ |
{ &vop_strategy_desc, fifo_strategy }, /* strategy */ |
{ &vop_strategy_desc, fifo_strategy }, /* strategy */ |
{ &vop_print_desc, ufs_print }, /* print */ |
{ &vop_print_desc, ufs_print }, /* print */ |
{ &vop_islocked_desc, ufs_islocked }, /* islocked */ |
{ &vop_islocked_desc, ffs_islocked }, /* islocked */ |
{ &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ |
{ &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ |
{ &vop_advlock_desc, fifo_advlock }, /* advlock */ |
{ &vop_advlock_desc, fifo_advlock }, /* advlock */ |
{ &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ |
|
{ &vop_valloc_desc, fifo_valloc }, /* valloc */ |
|
{ &vop_reallocblks_desc, fifo_reallocblks }, /* reallocblks */ |
|
{ &vop_vfree_desc, ffs_vfree }, /* vfree */ |
|
{ &vop_truncate_desc, fifo_truncate }, /* truncate */ |
|
{ &vop_update_desc, ffs_update }, /* update */ |
|
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL } |
{ &vop_putpages_desc, fifo_putpages }, /* putpages */ |
|
{ &vop_openextattr_desc, ffs_openextattr }, /* openextattr */ |
|
{ &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */ |
|
{ &vop_getextattr_desc, ffs_getextattr }, /* getextattr */ |
|
{ &vop_setextattr_desc, ffs_setextattr }, /* setextattr */ |
|
{ &vop_listextattr_desc, ffs_listextattr }, /* listextattr */ |
|
{ &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */ |
|
{ NULL, NULL } |
}; |
}; |
struct vnodeopv_desc ffs_fifoop_opv_desc = |
const struct vnodeopv_desc ffs_fifoop_opv_desc = |
{ &ffs_fifoop_p, ffs_fifoop_entries }; |
{ &ffs_fifoop_p, ffs_fifoop_entries }; |
|
|
int doclusterread = 0; |
|
int doclusterwrite = 0; |
|
|
|
#include <ufs/ufs/ufs_readwrite.c> |
#include <ufs/ufs/ufs_readwrite.c> |
|
|
|
int |
|
ffs_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; |
|
struct buf *bp; |
|
int num, error, i; |
|
struct indir ia[NIADDR + 1]; |
|
int bsize; |
|
daddr_t blk_high; |
|
struct vnode *vp; |
|
|
|
vp = ap->a_vp; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_LAZY); |
|
/* |
|
* XXX no easy way to sync a range in a file with softdep. |
|
*/ |
|
if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(vp) || |
|
(vp->v_type != VREG)) { |
|
error = ffs_full_fsync(v); |
|
goto out; |
|
} |
|
|
|
bsize = vp->v_mount->mnt_stat.f_iosize; |
|
blk_high = ap->a_offhi / bsize; |
|
if (ap->a_offhi % bsize != 0) |
|
blk_high++; |
|
|
|
/* |
|
* First, flush all pages in range. |
|
*/ |
|
|
|
mutex_enter(&vp->v_interlock); |
|
error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), |
|
round_page(ap->a_offhi), PGO_CLEANIT | |
|
((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0)); |
|
if (error) { |
|
goto out; |
|
} |
|
|
|
/* |
|
* Then, flush indirect blocks. |
|
*/ |
|
|
|
if (blk_high >= NDADDR) { |
|
error = ufs_getlbns(vp, blk_high, ia, &num); |
|
if (error) |
|
goto out; |
|
|
|
mutex_enter(&bufcache_lock); |
|
for (i = 0; i < num; i++) { |
|
if ((bp = incore(vp, ia[i].in_lbn)) == NULL) |
|
continue; |
|
if ((bp->b_cflags & BC_BUSY) != 0 || |
|
(bp->b_oflags & BO_DELWRI) == 0) |
|
continue; |
|
bp->b_cflags |= BC_BUSY | BC_VFLUSH; |
|
mutex_exit(&bufcache_lock); |
|
bawrite(bp); |
|
mutex_enter(&bufcache_lock); |
|
} |
|
mutex_exit(&bufcache_lock); |
|
} |
|
|
|
if (ap->a_flags & FSYNC_WAIT) { |
|
mutex_enter(&vp->v_interlock); |
|
while (vp->v_numoutput > 0) |
|
cv_wait(&vp->v_cv, &vp->v_interlock); |
|
mutex_exit(&vp->v_interlock); |
|
} |
|
|
|
error = ffs_update(vp, NULL, NULL, |
|
((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT) |
|
? UPDATE_WAIT : 0); |
|
|
|
if (error == 0 && ap->a_flags & FSYNC_CACHE) { |
|
int l = 0; |
|
VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE, |
|
ap->a_l->l_cred, ap->a_l); |
|
} |
|
|
|
out: |
|
fstrans_done(vp->v_mount); |
|
return error; |
|
} |
|
|
|
/* |
|
* Synch an open file. |
|
*/ |
|
/* ARGSUSED */ |
|
static int |
|
ffs_full_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; |
|
struct vnode *vp = ap->a_vp; |
|
struct buf *bp, *nbp; |
|
int error, passes, skipmeta, inodedeps_only, waitfor; |
|
|
|
if (vp->v_type == VBLK && |
|
vp->v_specmountpoint != NULL && |
|
(vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP)) |
|
softdep_fsync_mountdev(vp); |
|
|
|
mutex_enter(&vp->v_interlock); |
|
|
|
inodedeps_only = DOINGSOFTDEP(vp) && (ap->a_flags & FSYNC_RECLAIM) |
|
&& UVM_OBJ_IS_CLEAN(&vp->v_uobj) && LIST_EMPTY(&vp->v_dirtyblkhd); |
|
|
|
/* |
|
* Flush all dirty data associated with a vnode. |
|
*/ |
|
|
|
if (vp->v_type == VREG || vp->v_type == VBLK) { |
|
error = VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES | PGO_CLEANIT | |
|
((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0) | |
|
(fstrans_getstate(vp->v_mount) == FSTRANS_SUSPENDING ? |
|
PGO_FREE : 0)); |
|
if (error) { |
|
return error; |
|
} |
|
} else |
|
mutex_exit(&vp->v_interlock); |
|
|
|
passes = NIADDR + 1; |
|
skipmeta = 0; |
|
if (ap->a_flags & FSYNC_WAIT) |
|
skipmeta = 1; |
|
|
|
mutex_enter(&bufcache_lock); |
|
mutex_enter(&vp->v_interlock); |
|
loop: |
|
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; |
|
mutex_exit(&vp->v_interlock); |
|
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 || !(ap->a_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); |
|
mutex_enter(&vp->v_interlock); |
|
nbp = LIST_FIRST(&vp->v_dirtyblkhd); |
|
} |
|
if (skipmeta) { |
|
skipmeta = 0; |
|
goto loop; |
|
} |
|
mutex_exit(&bufcache_lock); |
|
|
|
if (ap->a_flags & FSYNC_WAIT) { |
|
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 ((error = softdep_sync_metadata(ap)) != 0) |
|
return (error); |
|
|
|
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 |
|
} |
|
} else |
|
mutex_exit(&vp->v_interlock); |
|
|
|
if (inodedeps_only) |
|
waitfor = 0; |
|
else |
|
waitfor = (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0; |
|
error = ffs_update(vp, NULL, NULL, waitfor); |
|
|
|
if (error == 0 && ap->a_flags & FSYNC_CACHE) { |
|
int i = 0; |
|
VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, |
|
ap->a_l->l_cred, ap->a_l); |
|
} |
|
|
|
return error; |
|
} |
|
|
/* |
/* |
* Reclaim an inode so that it can be used for other purposes. |
* Reclaim an inode so that it can be used for other purposes. |
*/ |
*/ |
int |
int |
ffs_reclaim(v) |
ffs_reclaim(void *v) |
void *v; |
|
{ |
{ |
struct vop_reclaim_args /* { |
struct vop_reclaim_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
struct proc *a_p; |
struct lwp *a_l; |
} */ *ap = v; |
} */ *ap = v; |
register struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
|
struct inode *ip = VTOI(vp); |
|
struct mount *mp = vp->v_mount; |
|
struct ufsmount *ump = ip->i_ump; |
|
void *data; |
int error; |
int error; |
|
|
if ((error = ufs_reclaim(vp, ap->a_p)) != 0) |
fstrans_start(mp, FSTRANS_LAZY); |
|
if ((error = ufs_reclaim(vp, ap->a_l)) != 0) { |
|
fstrans_done(mp); |
return (error); |
return (error); |
|
} |
|
if (ip->i_din.ffs1_din != NULL) { |
|
if (ump->um_fstype == UFS1) |
|
pool_put(&ffs_dinode1_pool, ip->i_din.ffs1_din); |
|
else |
|
pool_put(&ffs_dinode2_pool, ip->i_din.ffs2_din); |
|
} |
|
/* |
|
* To interlock with ffs_sync(). |
|
*/ |
|
genfs_node_destroy(vp); |
|
mutex_enter(&vp->v_interlock); |
|
data = vp->v_data; |
|
vp->v_data = NULL; |
|
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 |
* XXX a separate pool for MFS inodes? |
* XXX a separate pool for MFS inodes? |
*/ |
*/ |
pool_put(&ffs_inode_pool, vp->v_data); |
pool_put(&ffs_inode_pool, data); |
vp->v_data = NULL; |
fstrans_done(mp); |
return (0); |
return (0); |
} |
} |
|
|
#ifdef UBC |
#if 0 |
#include <uvm/uvm.h> |
|
|
|
int |
int |
ffs_getpages(v) |
ffs_getpages(void *v) |
void *v; |
|
{ |
{ |
struct vop_getpages_args /* { |
struct vop_getpages_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
vaddr_t a_offset; |
voff_t a_offset; |
vm_page_t *a_m; |
struct vm_page **a_m; |
int *a_count; |
int *a_count; |
int a_centeridx; |
int a_centeridx; |
vm_prot_t a_access_type; |
vm_prot_t a_access_type; |
int a_advice; |
int a_advice; |
int a_flags; |
int a_flags; |
} */ *ap = v; |
} */ *ap = v; |
|
|
int error, npages; |
|
struct buf tmpbuf, *bp; |
|
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct uvm_object *uobj = &vp->v_uvm.u_obj; |
|
struct inode *ip = VTOI(vp); |
struct inode *ip = VTOI(vp); |
struct fs *fs = ip->i_fs; |
struct fs *fs = ip->i_fs; |
struct vm_page *pg; |
|
off_t offset; |
|
UVMHIST_FUNC("ffs_getpages"); UVMHIST_CALLED(ubchist); |
|
|
|
#ifdef DIAGNOSTIC |
|
if (ap->a_centeridx < 0 || ap->a_centeridx > *ap->a_count) { |
|
panic("ffs_getpages: centeridx %d out of range", |
|
ap->a_centeridx); |
|
} |
|
#endif |
|
|
|
if (ap->a_flags & PGO_LOCKED) { |
|
uvn_findpages(uobj, ap->a_offset, ap->a_count, ap->a_m, |
|
UFP_NOWAIT|UFP_NOALLOC); |
|
|
|
/* XXX PGO_ALLPAGES? */ |
|
return ap->a_m[ap->a_centeridx] == NULL ? |
|
VM_PAGER_UNLOCK : VM_PAGER_OK; |
|
} |
|
|
|
/* vnode is VOP_LOCKed, uobj is locked */ |
|
|
|
|
|
/* |
|
* XXX do the findpages for our 1 page first, |
|
* change asyncget to take the one page as an arg and |
|
* pretend that its findpages found it. |
|
*/ |
|
|
|
/* |
|
* kick off a big read first to get some readahead, then |
|
* get the one page we wanted. |
|
*/ |
|
|
|
if ((ap->a_flags & PGO_OVERWRITE) == 0 && |
|
(ap->a_offset & (MAXBSIZE - 1)) == 0) { |
|
/* |
|
* XXX pretty sure unlocking here is wrong. |
|
*/ |
|
simple_unlock(&uobj->vmobjlock); |
|
uvm_vnp_asyncget(vp, ap->a_offset, MAXBSIZE, fs->fs_bsize); |
|
simple_lock(&uobj->vmobjlock); |
|
} |
|
|
|
/* |
|
* the desired page isn't resident, we'll have to read it. |
|
*/ |
|
|
|
offset = ap->a_offset + (ap->a_centeridx << PAGE_SHIFT); |
|
npages = 1; |
|
pg = NULL; |
|
uvn_findpages(uobj, offset, &npages, &pg, 0); |
|
simple_unlock(&uobj->vmobjlock); |
|
|
|
/* |
/* |
* if the page is already resident, just return it. |
* don't allow a softdep write to create pages for only part of a block. |
|
* the dependency tracking requires that all pages be in memory for |
|
* a block involved in a dependency. |
*/ |
*/ |
|
|
if (pg && (pg->flags & PG_FAKE) == 0) { |
if (ap->a_flags & PGO_OVERWRITE && |
ap->a_m[ap->a_centeridx] = pg; |
(blkoff(fs, ap->a_offset) != 0 || |
return VM_PAGER_OK; |
blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) && |
|
DOINGSOFTDEP(ap->a_vp)) { |
|
if ((ap->a_flags & PGO_LOCKED) == 0) { |
|
mutex_exit(&vp->v_interlock); |
|
} |
|
return EINVAL; |
} |
} |
|
return genfs_getpages(v); |
|
} |
|
#endif |
|
|
/* |
/* |
* ok, really read the desired page. |
* Return the last logical file offset that should be written for this file |
*/ |
* if we're doing a write that ends at "size". |
|
*/ |
|
|
bp = &tmpbuf; |
void |
bzero(bp, sizeof *bp); |
ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags) |
|
{ |
|
struct inode *ip = VTOI(vp); |
|
struct fs *fs = ip->i_fs; |
|
daddr_t olbn, nlbn; |
|
|
bp->b_lblkno = lblkno(fs, offset); |
olbn = lblkno(fs, ip->i_size); |
error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); |
nlbn = lblkno(fs, size); |
if (error) { |
if (nlbn < NDADDR && olbn <= nlbn) { |
UVMHIST_LOG(ubchist, "VOP_BMAP lbn 0x%x -> %d\n", |
*eobp = fragroundup(fs, size); |
bp->b_lblkno, error,0,0); |
} else { |
goto out; |
*eobp = blkroundup(fs, size); |
} |
} |
if (bp->b_blkno == (daddr_t)-1) { |
} |
|
|
/* |
|
* XXX pre-allocate blocks here someday? |
|
* ... only for write accesses. |
|
* for read accesses we can skip the block allocation |
|
* if we can arrange to be called again |
|
* when a subsequent write access occurs. |
|
* needs support in uvm_fault(). |
|
*/ |
|
|
|
uvm_pagezero(pg); |
int |
UVMHIST_LOG(ubchist, "VOP_BMAP lbn 0x%x -> blkno 0x%x\n", |
ffs_openextattr(void *v) |
bp->b_lblkno, bp->b_blkno,0,0); |
{ |
goto out; |
struct vop_openextattr_args /* { |
} |
struct vnode *a_vp; |
|
kauth_cred_t a_cred; |
|
struct proc *a_p; |
|
} */ *ap = v; |
|
struct inode *ip = VTOI(ap->a_vp); |
|
struct fs *fs = ip->i_fs; |
|
|
/* adjust physical blkno for partial blocks */ |
/* Not supported for UFS1 file systems. */ |
bp->b_blkno += (offset - lblktosize(fs, bp->b_lblkno)) >> DEV_BSHIFT; |
if (fs->fs_magic == FS_UFS1_MAGIC) |
|
return (EOPNOTSUPP); |
|
|
UVMHIST_LOG(ubchist, "vp %p lblkno 0x%x blkno 0x%x", |
/* XXX Not implemented for UFS2 file systems. */ |
vp, bp->b_lblkno, bp->b_blkno, 0); |
return (EOPNOTSUPP); |
|
} |
|
|
/* |
int |
* don't bother reading the pages if we're just going to |
ffs_closeextattr(void *v) |
* overwrite them. |
{ |
*/ |
struct vop_closeextattr_args /* { |
if (ap->a_flags & PGO_OVERWRITE) { |
struct vnode *a_vp; |
|
int a_commit; |
|
kauth_cred_t a_cred; |
|
struct proc *a_p; |
|
} */ *ap = v; |
|
struct inode *ip = VTOI(ap->a_vp); |
|
struct fs *fs = ip->i_fs; |
|
|
UVMHIST_LOG(ubchist, "PGO_OVERWRITE",0,0,0,0); |
/* Not supported for UFS1 file systems. */ |
|
if (fs->fs_magic == FS_UFS1_MAGIC) |
|
return (EOPNOTSUPP); |
|
|
/* XXX for now, zero the page */ |
/* XXX Not implemented for UFS2 file systems. */ |
if (pg->flags & PG_FAKE) { |
return (EOPNOTSUPP); |
uvm_pagezero(pg); |
} |
pg->flags &= ~(PG_FAKE); |
|
uvm_pageactivate(pg); |
|
} |
|
|
|
UVMHIST_LOG(ubchist, "m[%d] <- pg %p", ap->a_centeridx, pg,0,0); |
int |
|
ffs_getextattr(void *v) |
|
{ |
|
struct vop_getextattr_args /* { |
|
struct vnode *a_vp; |
|
int a_attrnamespace; |
|
const char *a_name; |
|
struct uio *a_uio; |
|
size_t *a_size; |
|
kauth_cred_t a_cred; |
|
struct proc *a_p; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
struct inode *ip = VTOI(vp); |
|
struct fs *fs = ip->i_fs; |
|
|
/* XXX what about *ap->a_count > 1 ? */ |
if (fs->fs_magic == FS_UFS1_MAGIC) { |
ap->a_m[ap->a_centeridx] = pg; |
#ifdef UFS_EXTATTR |
return VM_PAGER_OK; |
int error; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
|
error = ufs_getextattr(ap); |
|
fstrans_done(vp->v_mount); |
|
return error; |
|
#else |
|
return (EOPNOTSUPP); |
|
#endif |
} |
} |
|
|
bp->b_bufsize = PAGE_SIZE; |
/* XXX Not implemented for UFS2 file systems. */ |
bp->b_data = (void *)uvm_pagermapin(&pg, 1, NULL, M_WAITOK); |
return (EOPNOTSUPP); |
bp->b_bcount = bp->b_lblkno < 0 ? bp->b_bufsize : |
} |
min(bp->b_bufsize, fragroundup(fs, vp->v_uvm.u_size - offset)); |
|
bp->b_vp = vp; |
|
bp->b_flags = B_BUSY|B_READ; |
|
|
|
UVMHIST_LOG(ubchist, "bp %p vp %p lblkno 0x%x", bp, vp, bp->b_lblkno, 0); |
int |
|
ffs_setextattr(void *v) |
|
{ |
|
struct vop_setextattr_args /* { |
|
struct vnode *a_vp; |
|
int a_attrnamespace; |
|
const char *a_name; |
|
struct uio *a_uio; |
|
kauth_cred_t a_cred; |
|
struct proc *a_p; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
struct inode *ip = VTOI(vp); |
|
struct fs *fs = ip->i_fs; |
|
|
VOP_STRATEGY(bp); |
if (fs->fs_magic == FS_UFS1_MAGIC) { |
error = biowait(bp); |
#ifdef UFS_EXTATTR |
|
int error; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
|
error = ufs_setextattr(ap); |
|
fstrans_done(vp->v_mount); |
|
return error; |
|
#else |
|
return (EOPNOTSUPP); |
|
#endif |
|
} |
|
|
uvm_pagermapout((vaddr_t)bp->b_data, *ap->a_count); |
/* XXX Not implemented for UFS2 file systems. */ |
|
return (EOPNOTSUPP); |
|
} |
|
|
out: |
int |
if (error) { |
ffs_listextattr(void *v) |
simple_lock(&uobj->vmobjlock); |
{ |
if (pg->flags & PG_WANTED) { |
struct vop_listextattr_args /* { |
wakeup(pg); |
struct vnode *a_vp; |
} |
int a_attrnamespace; |
UVM_PAGE_OWN(pg, NULL); |
struct uio *a_uio; |
uvm_lock_pageq(); |
size_t *a_size; |
uvm_pagefree(pg); |
kauth_cred_t a_cred; |
uvm_unlock_pageq(); |
struct proc *a_p; |
simple_unlock(&uobj->vmobjlock); |
} */ *ap = v; |
} else { |
struct inode *ip = VTOI(ap->a_vp); |
pg->flags &= ~(PG_FAKE); |
struct fs *fs = ip->i_fs; |
pmap_clear_modify(PMAP_PGARG(pg)); |
|
pmap_clear_reference(PMAP_PGARG(pg)); |
|
uvm_pageactivate(pg); |
|
ap->a_m[ap->a_centeridx] = pg; |
|
} |
|
|
|
UVMHIST_LOG(ubchist, "returning, error %d", error,0,0,0); |
/* Not supported for UFS1 file systems. */ |
|
if (fs->fs_magic == FS_UFS1_MAGIC) |
|
return (EOPNOTSUPP); |
|
|
return error ? VM_PAGER_ERROR : VM_PAGER_OK; |
/* XXX Not implemented for UFS2 file systems. */ |
|
return (EOPNOTSUPP); |
} |
} |
|
|
/* |
|
* Vnode op for VM putpages. |
|
*/ |
|
int |
int |
ffs_putpages(v) |
ffs_deleteextattr(void *v) |
void *v; |
|
{ |
{ |
struct vop_putpages_args /* { |
struct vop_deleteextattr_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
struct vm_page **a_m; |
int a_attrnamespace; |
int a_count; |
kauth_cred_t a_cred; |
int a_sync; |
struct proc *a_p; |
int *a_rtvals; |
|
} */ *ap = v; |
} */ *ap = v; |
|
|
int s, error; |
|
int bsize; |
|
vaddr_t kva, offset; |
|
struct vm_page *pg; |
|
struct buf tmpbuf, *bp; |
|
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct inode *ip = VTOI(vp); |
struct inode *ip = VTOI(vp); |
struct fs *fs = ip->i_fs; |
struct fs *fs = ip->i_fs; |
struct ucred *cred = curproc->p_ucred; /* XXX curproc */ |
|
UVMHIST_FUNC("ffs_putpages"); UVMHIST_CALLED(ubchist); |
|
|
|
pg = ap->a_m[0]; |
|
|
|
#ifdef DEBUG |
if (fs->fs_magic == FS_UFS1_MAGIC) { |
/* XXX verify that pages given are in fact physically contiguous. */ |
#ifdef UFS_EXTATTR |
|
int error; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
|
error = ufs_deleteextattr(ap); |
|
fstrans_done(vp->v_mount); |
|
return error; |
|
#else |
|
return (EOPNOTSUPP); |
#endif |
#endif |
|
} |
|
|
kva = uvm_pagermapin(ap->a_m, ap->a_count, NULL, M_WAITOK); |
/* XXX Not implemented for UFS2 file systems. */ |
if (kva == 0) { |
return (EOPNOTSUPP); |
return VM_PAGER_AGAIN; |
} |
} |
|
|
/* |
if (ap->a_sync) { |
* Lock the node. |
bp = &tmpbuf; |
*/ |
bzero(bp, sizeof *bp); |
int |
} |
ffs_lock(void *v) |
else { |
{ |
struct uvm_aiobuf *abp = pool_get(uvm_aiobuf_pool, PR_WAITOK); |
struct vop_lock_args /* { |
abp->aio.aiodone = uvm_aio_aiodone; |
struct vnode *a_vp; |
abp->aio.kva = kva; |
int a_flags; |
abp->aio.npages = ap->a_count; |
} */ *ap = v; |
abp->aio.pd_ptr = abp; |
struct vnode *vp = ap->a_vp; |
/* XXX pagedaemon */ |
struct mount *mp = vp->v_mount; |
abp->aio.flags = (curproc == uvm.pagedaemon_proc) ? |
|
UVM_AIO_PAGEDAEMON : 0; |
|
bp = &abp->buf; |
|
bzero(bp, sizeof *bp); |
|
bp->b_flags = B_CALL|B_ASYNC; |
|
bp->b_iodone = uvm_aio_biodone; |
|
} |
|
|
|
offset = pg->offset; |
|
bp->b_bufsize = ap->a_count << PAGE_SHIFT; |
|
bp->b_data = (void *)kva; |
|
bp->b_lblkno = lblkno(fs, offset); |
|
bp->b_bcount = min(bp->b_bufsize, |
|
fragroundup(fs, vp->v_uvm.u_size - offset)); |
|
bp->b_flags |= B_BUSY|B_WRITE; |
|
bp->b_vp = vp; |
|
|
|
/* |
/* |
* if the blkno wasn't set in the page, do a bmap to find it. |
* Fake lock during file system suspension. |
* this should only happen if the block is unallocated. |
|
* we'll always want to set the page's blkno if it's allocated |
|
* to help prevent memory deadlocks. we probably even want to |
|
* allocate blocks in VOP_GETPAGES() for this same reason. |
|
* |
|
* once we switch to doing that, the page should always have a blkno. |
|
* but for now, we'll handle allocating blocks here too. |
|
* |
|
* XXX this doesn't handle blocksizes smaller than PAGE_SIZE. |
|
*/ |
*/ |
|
if ((vp->v_type == VREG || vp->v_type == VDIR) && |
bp->b_blkno = 0; |
fstrans_is_owner(mp) && |
bsize = blksize(fs, ip, lblkno(fs, offset)); |
fstrans_getstate(mp) == FSTRANS_SUSPENDING) { |
error = ffs_balloc(ip, bp->b_lblkno, bsize, cred, NULL, |
if ((ap->a_flags & LK_INTERLOCK) != 0) |
&bp->b_blkno, 0); |
mutex_exit(&vp->v_interlock); |
if (error) { |
return 0; |
UVMHIST_LOG(ubchist, "ffs_balloc -> %d", error, 0,0,0); |
|
goto out; |
|
} |
|
|
|
if (bp->b_blkno == (daddr_t)-1) { |
|
panic("XXX alloc from putpages vp %p", vp); |
|
} |
} |
|
return (lockmgr(vp->v_vnlock, ap->a_flags, &vp->v_interlock)); |
|
} |
|
|
/* adjust physical blkno for partial blocks */ |
/* |
bp->b_blkno += (offset - lblktosize(fs, bp->b_lblkno)) |
* Unlock the node. |
>> DEV_BSHIFT; |
*/ |
|
int |
UVMHIST_LOG(ubchist, "pg %p vp %p lblkno 0x%x blkno 0x%x", |
ffs_unlock(void *v) |
pg, vp, bp->b_lblkno, bp->b_blkno); |
{ |
|
struct vop_unlock_args /* { |
s = splbio(); |
struct vnode *a_vp; |
vp->v_numoutput++; |
int a_flags; |
splx(s); |
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
struct mount *mp = vp->v_mount; |
|
|
VOP_STRATEGY(bp); |
/* |
if (!ap->a_sync) { |
* Fake unlock during file system suspension. |
return VM_PAGER_PEND; |
*/ |
|
if ((vp->v_type == VREG || vp->v_type == VDIR) && |
|
fstrans_is_owner(mp) && |
|
fstrans_getstate(mp) == FSTRANS_SUSPENDING) { |
|
if ((ap->a_flags & LK_INTERLOCK) != 0) |
|
mutex_exit(&vp->v_interlock); |
|
return 0; |
} |
} |
|
return (lockmgr(vp->v_vnlock, ap->a_flags | LK_RELEASE, |
|
&vp->v_interlock)); |
|
} |
|
|
error = biowait(bp); |
/* |
|
* Return whether or not the node is locked. |
out: |
*/ |
UVMHIST_LOG(ubchist, "error %d", error,0,0,0); |
int |
uvm_pagermapout(kva, ap->a_count); |
ffs_islocked(void *v) |
|
{ |
|
struct vop_islocked_args /* { |
|
struct vnode *a_vp; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
|
return error ? VM_PAGER_ERROR : VM_PAGER_OK; |
return (lockstatus(vp->v_vnlock)); |
} |
} |
#endif |
|