Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/ufs/ffs/ffs_vnops.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/ufs/ffs/ffs_vnops.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.37.6.4 retrieving revision 1.86.4.9 diff -u -p -r1.37.6.4 -r1.86.4.9 --- src/sys/ufs/ffs/ffs_vnops.c 2002/06/23 17:52:09 1.37.6.4 +++ src/sys/ufs/ffs/ffs_vnops.c 2007/08/20 21:28:25 1.86.4.9 @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_vnops.c,v 1.37.6.4 2002/06/23 17:52:09 jdolecek Exp $ */ +/* $NetBSD: ffs_vnops.c,v 1.86.4.9 2007/08/20 21:28:25 ad Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -12,11 +12,7 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * 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 + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,7 +32,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.37.6.4 2002/06/23 17:52:09 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.86.4.9 2007/08/20 21:28:25 ad Exp $"); #include #include @@ -51,6 +47,8 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c, #include #include #include +#include +#include #include #include @@ -66,10 +64,10 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c, #include -static int ffs_full_fsync __P((void *)); +static int ffs_full_fsync(void *); /* Global vfs data structures for ufs. */ -int (**ffs_vnodeop_p) __P((void *)); +int (**ffs_vnodeop_p)(void *); const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = { { &vop_default_desc, vn_default_error }, { &vop_lookup_desc, ufs_lookup }, /* lookup */ @@ -87,7 +85,7 @@ const struct vnodeopv_entry_desc ffs_vno { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */ { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ { &vop_poll_desc, ufs_poll }, /* poll */ - { &vop_kqfilter_desc, ufs_kqfilter }, /* kqfilter */ + { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ { &vop_revoke_desc, ufs_revoke }, /* revoke */ { &vop_mmap_desc, ufs_mmap }, /* mmap */ { &vop_fsync_desc, ffs_fsync }, /* fsync */ @@ -103,30 +101,29 @@ const struct vnodeopv_entry_desc ffs_vno { &vop_abortop_desc, ufs_abortop }, /* abortop */ { &vop_inactive_desc, ufs_inactive }, /* inactive */ { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ - { &vop_lock_desc, ufs_lock }, /* lock */ - { &vop_unlock_desc, ufs_unlock }, /* unlock */ + { &vop_lock_desc, ffs_lock }, /* lock */ + { &vop_unlock_desc, ffs_unlock }, /* unlock */ { &vop_bmap_desc, ufs_bmap }, /* bmap */ { &vop_strategy_desc, ufs_strategy }, /* strategy */ { &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_advlock_desc, ufs_advlock }, /* advlock */ - { &vop_blkatoff_desc, ffs_blkatoff }, /* blkatoff */ - { &vop_valloc_desc, ffs_valloc }, /* valloc */ - { &vop_balloc_desc, ffs_balloc }, /* balloc */ - { &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_getpages_desc, ffs_getpages }, /* getpages */ - { &vop_putpages_desc, ffs_putpages }, /* putpages */ + { &vop_getpages_desc, genfs_getpages }, /* getpages */ + { &vop_putpages_desc, genfs_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 } }; const struct vnodeopv_desc ffs_vnodeop_opv_desc = { &ffs_vnodeop_p, ffs_vnodeop_entries }; -int (**ffs_specop_p) __P((void *)); +int (**ffs_specop_p)(void *); const struct vnodeopv_entry_desc ffs_specop_entries[] = { { &vop_default_desc, vn_default_error }, { &vop_lookup_desc, spec_lookup }, /* lookup */ @@ -143,6 +140,7 @@ const struct vnodeopv_entry_desc ffs_spe { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ { &vop_poll_desc, spec_poll }, /* poll */ + { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ { &vop_revoke_desc, spec_revoke }, /* revoke */ { &vop_mmap_desc, spec_mmap }, /* mmap */ { &vop_fsync_desc, ffs_fsync }, /* fsync */ @@ -158,29 +156,29 @@ const struct vnodeopv_entry_desc ffs_spe { &vop_abortop_desc, spec_abortop }, /* abortop */ { &vop_inactive_desc, ufs_inactive }, /* inactive */ { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ - { &vop_lock_desc, ufs_lock }, /* lock */ - { &vop_unlock_desc, ufs_unlock }, /* unlock */ + { &vop_lock_desc, ffs_lock }, /* lock */ + { &vop_unlock_desc, ffs_unlock }, /* unlock */ { &vop_bmap_desc, spec_bmap }, /* bmap */ { &vop_strategy_desc, spec_strategy }, /* strategy */ { &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_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_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 } }; const struct vnodeopv_desc ffs_specop_opv_desc = { &ffs_specop_p, ffs_specop_entries }; -int (**ffs_fifoop_p) __P((void *)); +int (**ffs_fifoop_p)(void *); const struct vnodeopv_entry_desc ffs_fifoop_entries[] = { { &vop_default_desc, vn_default_error }, { &vop_lookup_desc, fifo_lookup }, /* lookup */ @@ -197,6 +195,7 @@ const struct vnodeopv_entry_desc ffs_fif { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */ { &vop_poll_desc, fifo_poll }, /* poll */ + { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ { &vop_revoke_desc, fifo_revoke }, /* revoke */ { &vop_mmap_desc, fifo_mmap }, /* mmap */ { &vop_fsync_desc, ffs_fsync }, /* fsync */ @@ -212,60 +211,60 @@ const struct vnodeopv_entry_desc ffs_fif { &vop_abortop_desc, fifo_abortop }, /* abortop */ { &vop_inactive_desc, ufs_inactive }, /* inactive */ { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */ - { &vop_lock_desc, ufs_lock }, /* lock */ - { &vop_unlock_desc, ufs_unlock }, /* unlock */ + { &vop_lock_desc, ffs_lock }, /* lock */ + { &vop_unlock_desc, ffs_unlock }, /* unlock */ { &vop_bmap_desc, fifo_bmap }, /* bmap */ { &vop_strategy_desc, fifo_strategy }, /* strategy */ { &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_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_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 } }; const struct vnodeopv_desc ffs_fifoop_opv_desc = { &ffs_fifoop_p, ffs_fifoop_entries }; -int doclusterread = 1; -int doclusterwrite = 1; - #include int -ffs_fsync(v) - void *v; +ffs_fsync(void *v) { struct vop_fsync_args /* { struct vnode *a_vp; - struct ucred *a_cred; + kauth_cred_t a_cred; int a_flags; off_t a_offlo; off_t a_offhi; - struct proc *a_p; + struct lwp *a_l; } */ *ap = v; struct buf *bp; - int s, num, error, i; + 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(ap->a_vp)) - return ffs_full_fsync(v); - - vp = ap->a_vp; + if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(vp) || + (vp->v_type != VREG)) { + error = ffs_full_fsync(v); + goto out; + } - bsize = ap->a_vp->v_mount->mnt_stat.f_iosize; + bsize = vp->v_mount->mnt_stat.f_iosize; blk_high = ap->a_offhi / bsize; if (ap->a_offhi % bsize != 0) blk_high++; @@ -274,48 +273,61 @@ ffs_fsync(v) * First, flush all pages in range. */ - if (vp->v_type == VREG) { - simple_lock(&vp->v_interlock); - error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), - round_page(ap->a_offhi), PGO_CLEANIT|PGO_SYNCIO); - if (error) { - return error; - } + 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. */ - s = splbio(); - if (!(ap->a_flags & FSYNC_DATAONLY) && blk_high >= NDADDR) { + if (blk_high >= NDADDR) { error = ufs_getlbns(vp, blk_high, ia, &num); - if (error) { - splx(s); - return error; - } + if (error) + goto out; + + mutex_enter(&bqueue_lock); for (i = 0; i < num; i++) { - bp = incore(vp, ia[i].in_lbn); - if (bp != NULL && !(bp->b_flags & B_BUSY) && - (bp->b_flags & B_DELWRI)) { - bp->b_flags |= B_BUSY | B_VFLUSH; - splx(s); - bawrite(bp); - s = splbio(); + if ((bp = incore(vp, ia[i].in_lbn)) == NULL) + continue; + mutex_enter(&bp->b_interlock); + if ((bp->b_flags & (B_BUSY | B_DELWRI)) != B_DELWRI) { + mutex_exit(&bp->b_interlock); + continue; } + bp->b_flags |= B_BUSY | B_VFLUSH; + mutex_exit(&bp->b_interlock); + mutex_exit(&bqueue_lock); + bawrite(bp); + mutex_enter(&bqueue_lock); } + mutex_exit(&bqueue_lock); } if (ap->a_flags & FSYNC_WAIT) { - while (vp->v_numoutput > 0) { - vp->v_flag |= VBWAIT; - tsleep(&vp->v_numoutput, PRIBIO + 1, "fsync_range", 0); - } + mutex_enter(&vp->v_interlock); + while (vp->v_numoutput > 0) + cv_wait(&vp->v_cv, &vp->v_interlock); + mutex_exit(&vp->v_interlock); } - splx(s); - return (VOP_UPDATE(vp, NULL, NULL, - (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); + 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; } /* @@ -323,100 +335,105 @@ ffs_fsync(v) */ /* ARGSUSED */ static int -ffs_full_fsync(v) - void *v; +ffs_full_fsync(void *v) { struct vop_fsync_args /* { struct vnode *a_vp; - struct ucred *a_cred; + kauth_cred_t a_cred; int a_flags; off_t a_offlo; off_t a_offhi; - struct proc *a_p; + struct lwp *a_l; } */ *ap = v; struct vnode *vp = ap->a_vp; struct buf *bp, *nbp; - int s, error, passes, skipmeta, inodedeps_only, waitfor; + 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) - && vp->v_uobj.uo_npages == 0 && LIST_EMPTY(&vp->v_dirtyblkhd); + && 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) { - simple_lock(&vp->v_interlock); + 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)); + ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0) | + (fstrans_getstate(vp->v_mount) == FSTRANS_SUSPENDING ? + PGO_FREE : 0)); if (error) { return error; } + mutex_enter(&vp->v_interlock); } passes = NIADDR + 1; skipmeta = 0; - if (ap->a_flags & (FSYNC_DATAONLY|FSYNC_WAIT)) + if (ap->a_flags & FSYNC_WAIT) skipmeta = 1; - s = splbio(); loop: - LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) + LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) { + mutex_enter(&bp->b_interlock); bp->b_flags &= ~B_SCANNED; + mutex_exit(&bp->b_interlock); + } for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { nbp = LIST_NEXT(bp, b_vnbufs); - if (bp->b_flags & (B_BUSY | B_SCANNED)) + mutex_enter(&bp->b_interlock); + if (bp->b_flags & (B_BUSY | B_SCANNED)) { + mutex_exit(&bp->b_interlock); continue; + } if ((bp->b_flags & B_DELWRI) == 0) panic("ffs_fsync: not dirty"); - if (skipmeta && bp->b_lblkno < 0) + if (skipmeta && bp->b_lblkno < 0) { + mutex_exit(&bp->b_interlock); continue; + } bp->b_flags |= B_BUSY | B_VFLUSH | B_SCANNED; - splx(s); + mutex_exit(&bp->b_interlock); /* * 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. */ + mutex_exit(&vp->v_interlock); if (passes > 0 || !(ap->a_flags & FSYNC_WAIT)) (void) bawrite(bp); else if ((error = bwrite(bp)) != 0) return (error); - s = splbio(); + mutex_enter(&vp->v_interlock); /* * Since we may have slept during the I/O, we need * to start from a known point. */ nbp = LIST_FIRST(&vp->v_dirtyblkhd); } - if (skipmeta && !(ap->a_flags & FSYNC_DATAONLY)) { + if (skipmeta) { skipmeta = 0; goto loop; } if (ap->a_flags & FSYNC_WAIT) { while (vp->v_numoutput) { - vp->v_flag |= VBWAIT; - (void) tsleep(&vp->v_numoutput, PRIBIO + 1, - "ffsfsync", 0); + cv_wait(&vp->v_cv, &vp->v_interlock); } - splx(s); - - if (ap->a_flags & FSYNC_DATAONLY) - return (0); + 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); - s = splbio(); if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { /* * Block devices associated with filesystems may @@ -435,41 +452,71 @@ loop: vprint("ffs_fsync: dirty", vp); #endif } - } - splx(s); + } else + mutex_exit(&vp->v_interlock); if (inodedeps_only) waitfor = 0; else waitfor = (ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0; - return (VOP_UPDATE(vp, NULL, NULL, waitfor)); + 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. */ int -ffs_reclaim(v) - void *v; +ffs_reclaim(void *v) { struct vop_reclaim_args /* { struct vnode *a_vp; - struct proc *a_p; + struct lwp *a_l; } */ *ap = v; 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; - 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); + } + 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 a separate pool for MFS inodes? */ - pool_put(&ffs_inode_pool, vp->v_data); - vp->v_data = NULL; + pool_put(&ffs_inode_pool, data); + fstrans_done(mp); return (0); } +#if 0 int ffs_getpages(void *v) { @@ -498,84 +545,254 @@ ffs_getpages(void *v) blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) && DOINGSOFTDEP(ap->a_vp)) { if ((ap->a_flags & PGO_LOCKED) == 0) { - simple_unlock(&vp->v_interlock); + mutex_exit(&vp->v_interlock); } return EINVAL; } return genfs_getpages(v); } +#endif + +/* + * Return the last logical file offset that should be written for this file + * if we're doing a write that ends at "size". + */ + +void +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; + + olbn = lblkno(fs, ip->i_size); + nlbn = lblkno(fs, size); + if (nlbn < NDADDR && olbn <= nlbn) { + *eobp = fragroundup(fs, size); + } else { + *eobp = blkroundup(fs, size); + } +} int -ffs_putpages(void *v) +ffs_openextattr(void *v) { - struct vop_putpages_args /* { + struct vop_openextattr_args /* { struct vnode *a_vp; - voff_t a_offlo; - voff_t a_offhi; - int a_flags; + kauth_cred_t a_cred; + struct proc *a_p; + } */ *ap = v; + struct inode *ip = VTOI(ap->a_vp); + struct fs *fs = ip->i_fs; + + /* Not supported for UFS1 file systems. */ + if (fs->fs_magic == FS_UFS1_MAGIC) + return (EOPNOTSUPP); + + /* XXX Not implemented for UFS2 file systems. */ + return (EOPNOTSUPP); +} + +int +ffs_closeextattr(void *v) +{ + struct vop_closeextattr_args /* { + 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; + + /* Not supported for UFS1 file systems. */ + if (fs->fs_magic == FS_UFS1_MAGIC) + return (EOPNOTSUPP); + + /* XXX Not implemented for UFS2 file systems. */ + return (EOPNOTSUPP); +} + +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 uvm_object *uobj = &vp->v_uobj; struct inode *ip = VTOI(vp); struct fs *fs = ip->i_fs; - struct vm_page *pg; - off_t off; - ufs_lbn_t lbn; - if (!DOINGSOFTDEP(vp) || (ap->a_flags & PGO_CLEANIT) == 0) { - return genfs_putpages(v); + if (fs->fs_magic == FS_UFS1_MAGIC) { +#ifdef UFS_EXTATTR + int error; + + fstrans_start(vp->v_mount, FSTRANS_SHARED); + error = ufs_getextattr(ap); + fstrans_done(vp->v_mount); + return error; +#else + return (EOPNOTSUPP); +#endif } - /* - * for softdep files, force the pages in a block to be written together. - * if we're the pagedaemon and we would have to wait for other pages, - * just fail the request. the pagedaemon will pick a different page. - */ + /* XXX Not implemented for UFS2 file systems. */ + return (EOPNOTSUPP); +} - ap->a_offlo &= ~fs->fs_qbmask; - lbn = lblkno(fs, ap->a_offhi); - ap->a_offhi = blkroundup(fs, ap->a_offhi); - if (curproc == uvm.pagedaemon_proc) { - for (off = ap->a_offlo; off < ap->a_offhi; off += PAGE_SIZE) { - pg = uvm_pagelookup(uobj, off); +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; - /* - * we only have missing pages here because the - * calculation of offhi above doesn't account for - * fragments. so once we see one missing page, - * the rest should be missing as well, but we'll - * check for the rest just to be paranoid. - */ + if (fs->fs_magic == FS_UFS1_MAGIC) { +#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 + } - if (pg == NULL) { - continue; - } - if (pg->flags & PG_BUSY) { - simple_unlock(&uobj->vmobjlock); - return EBUSY; - } - } + /* XXX Not implemented for UFS2 file systems. */ + return (EOPNOTSUPP); +} + +int +ffs_listextattr(void *v) +{ + struct vop_listextattr_args /* { + struct vnode *a_vp; + int a_attrnamespace; + struct uio *a_uio; + size_t *a_size; + kauth_cred_t a_cred; + struct proc *a_p; + } */ *ap = v; + struct inode *ip = VTOI(ap->a_vp); + struct fs *fs = ip->i_fs; + + /* Not supported for UFS1 file systems. */ + if (fs->fs_magic == FS_UFS1_MAGIC) + return (EOPNOTSUPP); + + /* XXX Not implemented for UFS2 file systems. */ + return (EOPNOTSUPP); +} + +int +ffs_deleteextattr(void *v) +{ + struct vop_deleteextattr_args /* { + struct vnode *a_vp; + int a_attrnamespace; + 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; + + if (fs->fs_magic == FS_UFS1_MAGIC) { +#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 } - return genfs_putpages(v); + + /* XXX Not implemented for UFS2 file systems. */ + return (EOPNOTSUPP); } /* - * Return the last logical file offset that should be written for this file - * if we're doing a write that ends at "size". + * Lock the node. */ +int +ffs_lock(void *v) +{ + struct vop_lock_args /* { + struct vnode *a_vp; + int a_flags; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct mount *mp = vp->v_mount; -void -ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp) + /* + * Fake lock during file system suspension. + */ + 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, &vp->v_interlock)); +} + +/* + * Unlock the node. + */ +int +ffs_unlock(void *v) { - struct inode *ip = VTOI(vp); - struct fs *fs = ip->i_fs; - ufs_lbn_t olbn, nlbn; + struct vop_unlock_args /* { + struct vnode *a_vp; + int a_flags; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct mount *mp = vp->v_mount; - olbn = lblkno(fs, ip->i_ffs_size); - nlbn = lblkno(fs, size); - if (nlbn < NDADDR && olbn <= nlbn) { - *eobp = fragroundup(fs, size); - } else { - *eobp = blkroundup(fs, size); + /* + * Fake unlock during file system suspension. + */ + 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)); +} + +/* + * Return whether or not the node is locked. + */ +int +ffs_islocked(void *v) +{ + struct vop_islocked_args /* { + struct vnode *a_vp; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + + return (lockstatus(vp->v_vnlock)); }