* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)vfs_vnops.c 7.8 (Berkeley) %G%
#include "../ufs/inode.h"
#include "../ufs/quota.h"
int vn_read(), vn_write(), vn_ioctl(), vn_select(), vn_close();
{ vn_read
, vn_write
, vn_ioctl
, vn_select
, vn_close
};
* Common code for vnode open operations.
* Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
vn_open(ndp
, fmode
, cmode
)
register struct nameidata
*ndp
;
register struct vnode
*vp
;
struct vattr
*vap
= &vat
;
ndp
->ni_nameiop
= CREATE
| LOCKPARENT
| LOCKLEAF
;
if ((fmode
& FEXCL
) == 0)
ndp
->ni_nameiop
|= FOLLOW
;
if (ndp
->ni_vp
== NULL
) {
if (error
= VOP_CREATE(ndp
, vap
))
ndp
->ni_nameiop
= LOOKUP
| FOLLOW
| LOCKLEAF
;
if (vp
->v_type
== VSOCK
) {
if ((fmode
& FCREAT
) == 0) {
if (error
= VOP_ACCESS(vp
, VREAD
, ndp
->ni_cred
))
if (fmode
& (FWRITE
|FTRUNC
)) {
if (vp
->v_type
== VDIR
) {
if ((error
= vn_writechk(vp
)) ||
(error
= VOP_ACCESS(vp
, VWRITE
, ndp
->ni_cred
)))
if (error
= VOP_SETATTR(vp
, vap
, ndp
->ni_cred
))
if (setjmp(&u
.u_qsave
)) {
error
= VOP_OPEN(vp
, fmode
, ndp
->ni_cred
);
* Check for write permissions on the specified vnode.
* The read-only status of the file system is checked.
* Also, prototype text segments cannot be written.
register struct vnode
*vp
;
* Disallow write attempts on read-only file systems;
* unless the file is a socket or a block or character
* device resident on the file system.
if ((vp
->v_mount
->m_flag
& M_RDONLY
) && vp
->v_type
!= VCHR
&&
vp
->v_type
!= VBLK
&& vp
->v_type
!= VSOCK
)
* If there's shared text associated with
* the vnode, try to free it up once. If
* we fail, we can't allow writing.
* Vnode version of rdwri() for calls on file systems.
vn_rdwr(rw
, vp
, base
, len
, offset
, segflg
, ioflg
, cred
, aresid
)
auio
.uio_offset
= offset
;
auio
.uio_segflg
= segflg
;
error
= VOP_READ(vp
, &auio
, &offset
, ioflg
, cred
);
error
= VOP_WRITE(vp
, &auio
, &offset
, ioflg
, cred
);
*aresid
= auio
.uio_resid
;
if (auio
.uio_resid
&& error
== 0)
return (VOP_READ((struct vnode
*)fp
->f_data
, uio
, &(fp
->f_offset
),
(fp
->f_flag
& FNDELAY
) ? IO_NDELAY
: 0, cred
));
register struct vnode
*vp
= (struct vnode
*)fp
->f_data
;
if (vp
->v_type
== VREG
&& (fp
->f_flag
& FAPPEND
))
if (fp
->f_flag
& FNDELAY
)
return (VOP_WRITE(vp
, uio
, &(fp
->f_offset
), ioflag
, cred
));
* Get stat info for a vnode.
register struct stat
*sb
;
register struct vattr
*vap
;
error
= VOP_GETATTR(vp
, vap
, u
.u_cred
);
sb
->st_dev
= vap
->va_fsid
;
sb
->st_ino
= vap
->va_fileid
;
sb
->st_nlink
= vap
->va_nlink
;
sb
->st_uid
= vap
->va_uid
;
sb
->st_gid
= vap
->va_gid
;
sb
->st_rdev
= vap
->va_rdev
;
sb
->st_size
= vap
->va_size
;
sb
->st_atime
= vap
->va_atime
.tv_sec
;
sb
->st_mtime
= vap
->va_mtime
.tv_sec
;
sb
->st_ctime
= vap
->va_ctime
.tv_sec
;
sb
->st_blksize
= vap
->va_blocksize
;
sb
->st_flags
= vap
->va_flags
;
sb
->st_gen
= vap
->va_gen
;
* XXX THIS IS NOT CORRECT!!, but be sure to change ufs_getattr()
sb
->st_blocks
= vap
->va_bytes
;
register struct vnode
*vp
= ((struct vnode
*)fp
->f_data
);
if (error
= VOP_GETATTR(vp
, &vattr
, u
.u_cred
))
*(off_t
*)data
= vattr
.va_size
- fp
->f_offset
;
if (com
== FIONBIO
|| com
== FIOASYNC
) /* XXX */
if (setjmp(&u
.u_qsave
)) {
if ((u
.u_sigintr
& sigmask(u
.u_procp
->p_cursig
)) != 0)
return (VOP_IOCTL(vp
, com
, data
, fp
->f_flag
, u
.u_cred
));
return(VOP_SELECT(((struct vnode
*)fp
->f_data
), which
, u
.u_cred
));
register struct file
*fp
;
struct vnode
*vp
= ((struct vnode
*)fp
->f_data
);
if (fp
->f_flag
& (FSHLOCK
|FEXLOCK
))
vn_unlock(fp
, FSHLOCK
|FEXLOCK
);
* Must delete vnode reference from this file entry
* before VOP_CLOSE, so that only other references
fp
->f_data
= (caddr_t
) 0;
error
= VOP_CLOSE(vp
, fp
->f_flag
, u
.u_cred
);
* Place an advisory lock on a vnode.
* !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries
register struct file
*fp
;
register int priority
= PLOCK
;
register struct vnode
*vp
= (struct vnode
*)fp
->f_data
;
if ((cmd
& LOCK_EX
) == 0)
if (setjmp(&u
.u_qsave
)) {
if ((u
.u_sigintr
& sigmask(u
.u_procp
->p_cursig
)) != 0)
* If there's a exclusive lock currently applied
* to the file, then we've gotta wait for the
* lock with everyone else.
while (vp
->v_flag
& VEXLOCK
) {
* If we're holding an exclusive
if (fp
->f_flag
& FEXLOCK
) {
sleep((caddr_t
)&vp
->v_exlockc
, priority
);
if ((cmd
& LOCK_EX
) && (vp
->v_flag
& VSHLOCK
)) {
* Must wait for any shared locks to finish
* before we try to apply a exclusive lock.
* If we're holding a shared
if (fp
->f_flag
& FSHLOCK
) {
sleep((caddr_t
)&vp
->v_shlockc
, PLOCK
);
if (fp
->f_flag
& FEXLOCK
)
if ((cmd
& LOCK_SH
) && (fp
->f_flag
& FSHLOCK
) == 0) {
register struct file
*fp
;
register struct vnode
*vp
= (struct vnode
*)fp
->f_data
;
if (vp
== NULL
|| kind
== 0)
if ((flags
& VSHLOCK
) == 0)
panic("vn_unlock: SHLOCK");
if (--vp
->v_shlockc
== 0) {
wakeup((caddr_t
)&vp
->v_shlockc
);
if ((flags
& VEXLOCK
) == 0)
panic("vn_unlock: EXLOCK");
if (--vp
->v_exlockc
== 0) {
vp
->v_flag
&= ~(VEXLOCK
|VLWAIT
);
wakeup((caddr_t
)&vp
->v_exlockc
);
* vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
* - look up fsid in mount list (if not found ret error)
* - get vp by calling VFS_FHTOVP() macro
* - if lockflag lock it with VOP_LOCK()
vn_fhtovp(fhp
, lockflag
, vpp
)
register struct mount
*mp
;
if ((mp
= getvfs(&fhp
->fh_fsid
)) == NULL
)
if (VFS_FHTOVP(mp
, &fhp
->fh_fid
, vpp
))
* Revoke access the current tty by all processes.
* Used only by the super-user in init
* to give ``clean'' terminals at login.
if (u
.u_error
= suser(u
.u_cred
, &u
.u_acflag
))
if ((u
.u_ttyp
->t_state
) & TS_ISOPEN
)
gsignal(u
.u_ttyp
->t_pgid
, SIGHUP
);
register struct file
*fp
;
register struct vnode
*vp
;
for (fp
= file
; fp
< fileNFILE
; fp
++) {
if (fp
->f_type
!= DTYPE_VNODE
)
vp
= (struct vnode
*)fp
->f_data
;
fp
->f_flag
&= ~(FREAD
|FWRITE
);
* Vnode reference, just increment the count
* Vnode release, just decrement the count and call VOP_INACTIVE()
register struct vnode
*vp
;
printf("inode %d, bad ref count %d\n",
VTOI(vp
)->i_number
, vp
->v_count
);
* vput(), just unlock and vrele()
register struct vnode
*vp
;