* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* %sccs.include.redist.c%
* @(#)ffs_vnops.c 7.79 (Berkeley) %G%
#include <sys/resourcevar.h>
#include <ufs/ufs/lockf.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#include <ufs/ufs/ufs_extern.h>
#include <ufs/ffs/ffs_extern.h>
/* Global vfs data structures for ufs. */
struct vnodeopv_entry_desc ffs_vnodeop_entries
[] = {
{ &vop_default_desc
, vn_default_error
},
{ &vop_lookup_desc
, ufs_lookup
}, /* lookup */
{ &vop_create_desc
, ufs_create
}, /* create */
{ &vop_mknod_desc
, ufs_mknod
}, /* mknod */
{ &vop_open_desc
, ufs_open
}, /* open */
{ &vop_close_desc
, ufs_close
}, /* close */
{ &vop_access_desc
, ufs_access
}, /* access */
{ &vop_getattr_desc
, ufs_getattr
}, /* getattr */
{ &vop_setattr_desc
, ufs_setattr
}, /* setattr */
{ &vop_read_desc
, ffs_read
}, /* read */
{ &vop_write_desc
, ffs_write
}, /* write */
{ &vop_ioctl_desc
, ufs_ioctl
}, /* ioctl */
{ &vop_select_desc
, ufs_select
}, /* select */
{ &vop_mmap_desc
, ufs_mmap
}, /* mmap */
{ &vop_fsync_desc
, ffs_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
, ffs_inactive
}, /* inactive */
{ &vop_reclaim_desc
, ufs_reclaim
}, /* reclaim */
{ &vop_lock_desc
, ufs_lock
}, /* lock */
{ &vop_unlock_desc
, ufs_unlock
}, /* unlock */
{ &vop_bmap_desc
, ffs_bmap
}, /* bmap */
{ &vop_strategy_desc
, ufs_strategy
}, /* strategy */
{ &vop_print_desc
, ufs_print
}, /* print */
{ &vop_islocked_desc
, ufs_islocked
}, /* islocked */
{ &vop_advlock_desc
, ufs_advlock
}, /* advlock */
{ &vop_blkatoff_desc
, ffs_blkatoff
}, /* blkatoff */
{ &vop_vget_desc
, ffs_vget
}, /* vget */
{ &vop_valloc_desc
, ffs_valloc
}, /* valloc */
{ &vop_vfree_desc
, ffs_vfree
}, /* vfree */
{ &vop_truncate_desc
, ffs_truncate
}, /* truncate */
{ &vop_update_desc
, ffs_update
}, /* update */
{ &vop_bwrite_desc
, vn_bwrite
},
{ (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
struct vnodeopv_desc ffs_vnodeop_opv_desc
=
{ &ffs_vnodeop_p
, ffs_vnodeop_entries
};
struct vnodeopv_entry_desc ffs_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
, ufs_getattr
}, /* getattr */
{ &vop_setattr_desc
, ufs_setattr
}, /* setattr */
{ &vop_read_desc
, ufsspec_read
}, /* read */
{ &vop_write_desc
, ufsspec_write
}, /* write */
{ &vop_ioctl_desc
, spec_ioctl
}, /* ioctl */
{ &vop_select_desc
, spec_select
}, /* select */
{ &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
, ffs_inactive
}, /* inactive */
{ &vop_reclaim_desc
, ufs_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_advlock_desc
, spec_advlock
}, /* advlock */
{ &vop_blkatoff_desc
, spec_blkatoff
}, /* blkatoff */
{ &vop_vget_desc
, spec_vget
}, /* vget */
{ &vop_valloc_desc
, spec_valloc
}, /* valloc */
{ &vop_vfree_desc
, spec_vfree
}, /* vfree */
{ &vop_truncate_desc
, spec_truncate
}, /* truncate */
{ &vop_update_desc
, ffs_update
}, /* update */
{ &vop_bwrite_desc
, vn_bwrite
},
{ (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
struct vnodeopv_desc ffs_specop_opv_desc
=
{ &ffs_specop_p
, ffs_specop_entries
};
struct vnodeopv_entry_desc ffs_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
, ufs_getattr
}, /* getattr */
{ &vop_setattr_desc
, ufs_setattr
}, /* setattr */
{ &vop_read_desc
, ufsfifo_read
}, /* read */
{ &vop_write_desc
, ufsfifo_write
}, /* write */
{ &vop_ioctl_desc
, fifo_ioctl
}, /* ioctl */
{ &vop_select_desc
, fifo_select
}, /* select */
{ &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
, ffs_inactive
}, /* inactive */
{ &vop_reclaim_desc
, ufs_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_advlock_desc
, fifo_advlock
}, /* advlock */
{ &vop_blkatoff_desc
, fifo_blkatoff
}, /* blkatoff */
{ &vop_vget_desc
, fifo_vget
}, /* vget */
{ &vop_valloc_desc
, fifo_valloc
}, /* valloc */
{ &vop_vfree_desc
, fifo_vfree
}, /* vfree */
{ &vop_truncate_desc
, fifo_truncate
}, /* truncate */
{ &vop_update_desc
, ffs_update
}, /* update */
{ &vop_bwrite_desc
, vn_bwrite
},
{ (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
struct vnodeopv_desc ffs_fifoop_opv_desc
=
{ &ffs_fifoop_p
, ffs_fifoop_entries
};
struct vop_read_args
*ap
;
register struct inode
*ip
= VTOI(ap
->a_vp
);
daddr_t lbn
, bn
, rablock
;
if (ap
->a_uio
->uio_rw
!= UIO_READ
)
type
= ip
->i_mode
& IFMT
;
if (type
!= IFDIR
&& type
!= IFREG
&& type
!= IFLNK
)
if (ap
->a_uio
->uio_resid
== 0)
if (ap
->a_uio
->uio_offset
< 0)
lbn
= lblkno(fs
, ap
->a_uio
->uio_offset
);
on
= blkoff(fs
, ap
->a_uio
->uio_offset
);
n
= MIN((unsigned)(fs
->fs_bsize
- on
), ap
->a_uio
->uio_resid
);
diff
= ip
->i_size
- ap
->a_uio
->uio_offset
;
size
= blksize(fs
, ip
, lbn
);
if (ap
->a_vp
->v_lastr
+ 1 == lbn
&&
lblktosize(fs
, rablock
) < ip
->i_size
) {
rasize
= blksize(fs
, ip
, rablock
);
error
= breadn(ap
->a_vp
, lbn
, size
, &rablock
,
&rasize
, 1, NOCRED
, &bp
);
error
= bread(ap
->a_vp
, lbn
, size
, NOCRED
, &bp
);
n
= MIN(n
, size
- bp
->b_resid
);
error
= uiomove(bp
->b_un
.b_addr
+ on
, (int)n
, ap
->a_uio
);
if (n
+ on
== fs
->fs_bsize
|| ap
->a_uio
->uio_offset
== ip
->i_size
)
} while (error
== 0 && ap
->a_uio
->uio_resid
> 0 && n
!= 0);
struct vop_write_args
*ap
;
register struct vnode
*vp
= ap
->a_vp
;
struct proc
*p
= ap
->a_uio
->uio_procp
;
register struct inode
*ip
= VTOI(vp
);
int size
, resid
, error
= 0;
if (ap
->a_uio
->uio_rw
!= UIO_WRITE
)
if (ap
->a_ioflag
& IO_APPEND
)
ap
->a_uio
->uio_offset
= ip
->i_size
;
if ((ap
->a_ioflag
& IO_SYNC
) == 0)
panic("ffs_write nonsync dir write");
if (ap
->a_uio
->uio_offset
< 0)
if (ap
->a_uio
->uio_resid
== 0)
* Maybe this should be above the vnode op call, but so long as
* file servers have no limits, i don't think it matters
if (vp
->v_type
== VREG
&& p
&&
ap
->a_uio
->uio_offset
+ ap
->a_uio
->uio_resid
>
p
->p_rlimit
[RLIMIT_FSIZE
].rlim_cur
) {
resid
= ap
->a_uio
->uio_resid
;
if (ap
->a_ioflag
& IO_SYNC
)
lbn
= lblkno(fs
, ap
->a_uio
->uio_offset
);
on
= blkoff(fs
, ap
->a_uio
->uio_offset
);
n
= MIN((unsigned)(fs
->fs_bsize
- on
), ap
->a_uio
->uio_resid
);
if (error
= ffs_balloc(ip
, lbn
, on
+ n
, ap
->a_cred
, &bp
, flags
))
if (ap
->a_uio
->uio_offset
+ n
> ip
->i_size
) {
ip
->i_size
= ap
->a_uio
->uio_offset
+ n
;
vnode_pager_setsize(vp
, (u_long
)ip
->i_size
);
size
= blksize(fs
, ip
, lbn
);
(void) vnode_pager_uncache(vp
);
n
= MIN(n
, size
- bp
->b_resid
);
error
= uiomove(bp
->b_un
.b_addr
+ on
, n
, ap
->a_uio
);
if (ap
->a_ioflag
& IO_SYNC
)
else if (n
+ on
== fs
->fs_bsize
) {
if (ap
->a_cred
->cr_uid
!= 0)
ip
->i_mode
&= ~(ISUID
|ISGID
);
} while (error
== 0 && ap
->a_uio
->uio_resid
> 0 && n
!= 0);
if (error
&& (ap
->a_ioflag
& IO_UNIT
)) {
(void)VOP_TRUNCATE(vp
, osize
, ap
->a_ioflag
& IO_SYNC
, ap
->a_cred
);
ap
->a_uio
->uio_offset
-= resid
- ap
->a_uio
->uio_resid
;
ap
->a_uio
->uio_resid
= resid
;
if (!error
&& (ap
->a_ioflag
& IO_SYNC
))
error
= VOP_UPDATE(vp
, &time
, &time
, 1);
struct vop_fsync_args
*ap
;
struct inode
*ip
= VTOI(ap
->a_vp
);
if (ap
->a_fflags
& FWRITE
)
vflushbuf(ap
->a_vp
, ap
->a_waitfor
== MNT_WAIT
? B_SYNC
: 0);
return (VOP_UPDATE(ap
->a_vp
, &time
, &time
, ap
->a_waitfor
== MNT_WAIT
));
* Last reference to an inode, write the inode out and if necessary,
* truncate and deallocate the file.
struct vop_inactive_args
*ap
;
register struct inode
*ip
;
if (prtactive
&& ap
->a_vp
->v_usecount
!= 0)
vprint("ffs_inactive: pushing active", ap
->a_vp
);
/* Get rid of inodes related to stale file handles. */
if ((ap
->a_vp
->v_flag
& VXLOCK
) == 0)
if (ip
->i_nlink
<= 0 && (ap
->a_vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0) {
(void)chkiq(ip
, -1, NOCRED
, 0);
error
= VOP_TRUNCATE(ap
->a_vp
, (off_t
)0, 0, NOCRED
);
VOP_VFREE(ap
->a_vp
, ip
->i_number
, mode
);
if (ip
->i_flag
&(IUPD
|IACC
|ICHG
|IMOD
))
VOP_UPDATE(ap
->a_vp
, &time
, &time
, 0);
* If we are done with the inode, reclaim it
* so that it can be reused immediately.
if (ap
->a_vp
->v_usecount
== 0 && ip
->i_mode
== 0)