* Copyright (c) 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
* @(#)lfs_vnops.c 8.11 (Berkeley) %G%
#include <sys/resourcevar.h>
#include <miscfs/specfs/specdev.h>
#include <miscfs/fifofs/fifo.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/lfs/lfs_extern.h>
/* Global vfs data structures for lfs. */
struct vnodeopv_entry_desc lfs_vnodeop_entries
[] = {
{ &vop_default_desc
, vn_default_error
},
{ &vop_lookup_desc
, ufs_lookup
}, /* lookup */
{ &vop_create_desc
, ufs_create
}, /* create */
{ &vop_whiteout_desc
, ufs_whiteout
}, /* whiteout */
{ &vop_mknod_desc
, ufs_mknod
}, /* mknod */
{ &vop_open_desc
, ufs_open
}, /* open */
{ &vop_close_desc
, lfs_close
}, /* close */
{ &vop_access_desc
, ufs_access
}, /* access */
{ &vop_getattr_desc
, lfs_getattr
}, /* getattr */
{ &vop_setattr_desc
, ufs_setattr
}, /* setattr */
{ &vop_read_desc
, lfs_read
}, /* read */
{ &vop_write_desc
, lfs_write
}, /* write */
{ &vop_lease_desc
, ufs_lease_check
}, /* lease */
{ &vop_ioctl_desc
, ufs_ioctl
}, /* ioctl */
{ &vop_select_desc
, ufs_select
}, /* select */
{ &vop_revoke_desc
, ufs_revoke
}, /* revoke */
{ &vop_mmap_desc
, ufs_mmap
}, /* mmap */
{ &vop_fsync_desc
, lfs_fsync
}, /* fsync */
{ &vop_seek_desc
, ufs_seek
}, /* seek */
{ &vop_remove_desc
, ufs_remove
}, /* remove */
{ &vop_link_desc
, ufs_link
}, /* link */
{ &vop_rename_desc
, ufs_rename
}, /* rename */
{ &vop_mkdir_desc
, ufs_mkdir
}, /* mkdir */
{ &vop_rmdir_desc
, ufs_rmdir
}, /* rmdir */
{ &vop_symlink_desc
, ufs_symlink
}, /* symlink */
{ &vop_readdir_desc
, ufs_readdir
}, /* readdir */
{ &vop_readlink_desc
, ufs_readlink
}, /* readlink */
{ &vop_abortop_desc
, ufs_abortop
}, /* abortop */
{ &vop_inactive_desc
, lfs_inactive
}, /* inactive */
{ &vop_reclaim_desc
, lfs_reclaim
}, /* reclaim */
{ &vop_lock_desc
, ufs_lock
}, /* lock */
{ &vop_unlock_desc
, ufs_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_pathconf_desc
, ufs_pathconf
}, /* pathconf */
{ &vop_advlock_desc
, ufs_advlock
}, /* advlock */
{ &vop_blkatoff_desc
, lfs_blkatoff
}, /* blkatoff */
{ &vop_valloc_desc
, lfs_valloc
}, /* valloc */
{ &vop_vfree_desc
, lfs_vfree
}, /* vfree */
{ &vop_truncate_desc
, lfs_truncate
}, /* truncate */
{ &vop_update_desc
, lfs_update
}, /* update */
{ &vop_bwrite_desc
, lfs_bwrite
}, /* bwrite */
{ (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
struct vnodeopv_desc lfs_vnodeop_opv_desc
=
{ &lfs_vnodeop_p
, lfs_vnodeop_entries
};
struct vnodeopv_entry_desc lfs_specop_entries
[] = {
{ &vop_default_desc
, vn_default_error
},
{ &vop_lookup_desc
, spec_lookup
}, /* lookup */
{ &vop_create_desc
, spec_create
}, /* create */
{ &vop_mknod_desc
, spec_mknod
}, /* mknod */
{ &vop_open_desc
, spec_open
}, /* open */
{ &vop_close_desc
, ufsspec_close
}, /* close */
{ &vop_access_desc
, ufs_access
}, /* access */
{ &vop_getattr_desc
, lfs_getattr
}, /* getattr */
{ &vop_setattr_desc
, ufs_setattr
}, /* setattr */
{ &vop_read_desc
, ufsspec_read
}, /* read */
{ &vop_write_desc
, ufsspec_write
}, /* write */
{ &vop_lease_desc
, spec_lease_check
}, /* lease */
{ &vop_ioctl_desc
, spec_ioctl
}, /* ioctl */
{ &vop_select_desc
, spec_select
}, /* select */
{ &vop_revoke_desc
, spec_revoke
}, /* revoke */
{ &vop_mmap_desc
, spec_mmap
}, /* mmap */
{ &vop_fsync_desc
, spec_fsync
}, /* fsync */
{ &vop_seek_desc
, spec_seek
}, /* seek */
{ &vop_remove_desc
, spec_remove
}, /* remove */
{ &vop_link_desc
, spec_link
}, /* link */
{ &vop_rename_desc
, spec_rename
}, /* rename */
{ &vop_mkdir_desc
, spec_mkdir
}, /* mkdir */
{ &vop_rmdir_desc
, spec_rmdir
}, /* rmdir */
{ &vop_symlink_desc
, spec_symlink
}, /* symlink */
{ &vop_readdir_desc
, spec_readdir
}, /* readdir */
{ &vop_readlink_desc
, spec_readlink
}, /* readlink */
{ &vop_abortop_desc
, spec_abortop
}, /* abortop */
{ &vop_inactive_desc
, lfs_inactive
}, /* inactive */
{ &vop_reclaim_desc
, lfs_reclaim
}, /* reclaim */
{ &vop_lock_desc
, ufs_lock
}, /* lock */
{ &vop_unlock_desc
, ufs_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_pathconf_desc
, spec_pathconf
}, /* pathconf */
{ &vop_advlock_desc
, spec_advlock
}, /* advlock */
{ &vop_blkatoff_desc
, spec_blkatoff
}, /* blkatoff */
{ &vop_valloc_desc
, spec_valloc
}, /* valloc */
{ &vop_vfree_desc
, lfs_vfree
}, /* vfree */
{ &vop_truncate_desc
, spec_truncate
}, /* truncate */
{ &vop_update_desc
, lfs_update
}, /* update */
{ &vop_bwrite_desc
, lfs_bwrite
}, /* bwrite */
{ (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
struct vnodeopv_desc lfs_specop_opv_desc
=
{ &lfs_specop_p
, lfs_specop_entries
};
struct vnodeopv_entry_desc lfs_fifoop_entries
[] = {
{ &vop_default_desc
, vn_default_error
},
{ &vop_lookup_desc
, fifo_lookup
}, /* lookup */
{ &vop_create_desc
, fifo_create
}, /* create */
{ &vop_mknod_desc
, fifo_mknod
}, /* mknod */
{ &vop_open_desc
, fifo_open
}, /* open */
{ &vop_close_desc
, ufsfifo_close
}, /* close */
{ &vop_access_desc
, ufs_access
}, /* access */
{ &vop_getattr_desc
, lfs_getattr
}, /* getattr */
{ &vop_setattr_desc
, ufs_setattr
}, /* setattr */
{ &vop_read_desc
, ufsfifo_read
}, /* read */
{ &vop_write_desc
, ufsfifo_write
}, /* write */
{ &vop_lease_desc
, fifo_lease_check
}, /* lease */
{ &vop_ioctl_desc
, fifo_ioctl
}, /* ioctl */
{ &vop_select_desc
, fifo_select
}, /* select */
{ &vop_revoke_desc
, fifo_revoke
}, /* revoke */
{ &vop_mmap_desc
, fifo_mmap
}, /* mmap */
{ &vop_fsync_desc
, fifo_fsync
}, /* fsync */
{ &vop_seek_desc
, fifo_seek
}, /* seek */
{ &vop_remove_desc
, fifo_remove
}, /* remove */
{ &vop_link_desc
, fifo_link
}, /* link */
{ &vop_rename_desc
, fifo_rename
}, /* rename */
{ &vop_mkdir_desc
, fifo_mkdir
}, /* mkdir */
{ &vop_rmdir_desc
, fifo_rmdir
}, /* rmdir */
{ &vop_symlink_desc
, fifo_symlink
}, /* symlink */
{ &vop_readdir_desc
, fifo_readdir
}, /* readdir */
{ &vop_readlink_desc
, fifo_readlink
}, /* readlink */
{ &vop_abortop_desc
, fifo_abortop
}, /* abortop */
{ &vop_inactive_desc
, lfs_inactive
}, /* inactive */
{ &vop_reclaim_desc
, lfs_reclaim
}, /* reclaim */
{ &vop_lock_desc
, ufs_lock
}, /* lock */
{ &vop_unlock_desc
, ufs_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_pathconf_desc
, fifo_pathconf
}, /* pathconf */
{ &vop_advlock_desc
, fifo_advlock
}, /* advlock */
{ &vop_blkatoff_desc
, fifo_blkatoff
}, /* blkatoff */
{ &vop_valloc_desc
, fifo_valloc
}, /* valloc */
{ &vop_vfree_desc
, lfs_vfree
}, /* vfree */
{ &vop_truncate_desc
, fifo_truncate
}, /* truncate */
{ &vop_update_desc
, lfs_update
}, /* update */
{ &vop_bwrite_desc
, lfs_bwrite
}, /* bwrite */
{ (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
struct vnodeopv_desc lfs_fifoop_opv_desc
=
{ &lfs_fifoop_p
, lfs_fifoop_entries
};
#include <ufs/ufs/ufs_readwrite.c>
struct vop_fsync_args
/* {
return (VOP_UPDATE(ap
->a_vp
, &tv
, &tv
,
ap
->a_waitfor
== MNT_WAIT
? LFS_SYNC
: 0));
* These macros are used to bracket UFS directory ops, so that we can
* identify all the pages touched during directory ops which need to
* be ordered and flushed atomically, so that they may be recovered.
#define SET_DIROP(fs) { \
tsleep(&(fs)->lfs_dirops, PRIBIO + 1, "lfs_dirop", 0); \
#define SET_ENDOP(fs) { \
wakeup(&(fs)->lfs_writer); \
#define MARK_VNODE(dvp) (dvp)->v_flag |= VDIROP
struct vop_symlink_args
/* {
struct componentname *a_cnp;
SET_DIROP(VTOI(ap
->a_dvp
)->i_lfs
);
SET_ENDOP(VTOI(ap
->a_dvp
)->i_lfs
);
struct vop_mknod_args
/* {
struct componentname *a_cnp;
SET_DIROP(VTOI(ap
->a_dvp
)->i_lfs
);
SET_ENDOP(VTOI(ap
->a_dvp
)->i_lfs
);
struct vop_create_args
/* {
struct componentname *a_cnp;
SET_DIROP(VTOI(ap
->a_dvp
)->i_lfs
);
SET_ENDOP(VTOI(ap
->a_dvp
)->i_lfs
);
struct vop_mkdir_args
/* {
struct componentname *a_cnp;
SET_DIROP(VTOI(ap
->a_dvp
)->i_lfs
);
SET_ENDOP(VTOI(ap
->a_dvp
)->i_lfs
);
struct vop_remove_args
/* {
struct componentname *a_cnp;
SET_DIROP(VTOI(ap
->a_dvp
)->i_lfs
);
SET_ENDOP(VTOI(ap
->a_dvp
)->i_lfs
);
struct vop_rmdir_args
/* {
struct vnodeop_desc *a_desc;
struct componentname *a_cnp;
SET_DIROP(VTOI(ap
->a_dvp
)->i_lfs
);
SET_ENDOP(VTOI(ap
->a_dvp
)->i_lfs
);
struct vop_link_args
/* {
struct componentname *a_cnp;
SET_DIROP(VTOI(ap
->a_tdvp
)->i_lfs
);
SET_ENDOP(VTOI(ap
->a_tdvp
)->i_lfs
);
struct vop_rename_args
/* {
struct componentname *a_fcnp;
struct componentname *a_tcnp;
SET_DIROP(VTOI(ap
->a_fdvp
)->i_lfs
);
SET_ENDOP(VTOI(ap
->a_fdvp
)->i_lfs
);
/* XXX hack to avoid calling ITIMES in getattr */
struct vop_getattr_args
/* {
register struct vnode
*vp
= ap
->a_vp
;
register struct inode
*ip
= VTOI(vp
);
register struct vattr
*vap
= ap
->a_vap
;
vap
->va_fsid
= ip
->i_dev
;
vap
->va_fileid
= ip
->i_number
;
vap
->va_mode
= ip
->i_mode
& ~IFMT
;
vap
->va_nlink
= ip
->i_nlink
;
vap
->va_rdev
= (dev_t
)ip
->i_rdev
;
vap
->va_size
= ip
->i_din
.di_size
;
vap
->va_atime
.ts_sec
= ip
->i_atime
;
vap
->va_atime
.ts_nsec
= ip
->i_atimensec
;
vap
->va_mtime
.ts_sec
= ip
->i_mtime
;
vap
->va_mtime
.ts_nsec
= ip
->i_mtimensec
;
vap
->va_ctime
.ts_sec
= ip
->i_ctime
;
vap
->va_ctime
.ts_nsec
= ip
->i_ctimensec
;
vap
->va_flags
= ip
->i_flags
;
/* this doesn't belong here */
vap
->va_blocksize
= BLKDEV_IOSIZE
;
else if (vp
->v_type
== VCHR
)
vap
->va_blocksize
= MAXBSIZE
;
vap
->va_blocksize
= vp
->v_mount
->mnt_stat
.f_iosize
;
vap
->va_bytes
= dbtob(ip
->i_blocks
);
vap
->va_type
= vp
->v_type
;
vap
->va_filerev
= ip
->i_modrev
;
* XXX -- we were using ufs_close, but since it updates the
* times on the inode, we might need to bump the uinodes
struct vop_close_args
/* {
register struct vnode
*vp
= ap
->a_vp
;
register struct inode
*ip
= VTOI(vp
);
if (vp
->v_usecount
> 1 && !(ip
->i_flag
& IN_LOCKED
)) {
mod
= ip
->i_flag
& IN_MODIFIED
;
ITIMES(ip
, &time
, &time
);
if (!mod
&& ip
->i_flag
& IN_MODIFIED
)
ip
->i_lfs
->lfs_uinodes
++;
* Stub inactive routine that avoid calling ufs_inactive in some cases.
struct vop_inactive_args
/* {
return (ufs_inactive(ap
));
* Reclaim an inode so that it can be used for other purposes.
struct vop_reclaim_args
/* {
register struct vnode
*vp
= ap
->a_vp
;
if (error
= ufs_reclaim(vp
))
FREE(vp
->v_data
, M_LFSNODE
);