1b5970980Smckusick /*
2309aa356Sbostic * Copyright (c) 1982, 1986, 1989, 1993
3309aa356Sbostic * The Regents of the University of California. All rights reserved.
4342da129Sbostic * (c) UNIX System Laboratories, Inc.
5342da129Sbostic * All or some portions of this file are derived from material licensed
6342da129Sbostic * to the University of California by American Telephone and Telegraph
7342da129Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8342da129Sbostic * the permission of UNIX System Laboratories, Inc.
9b5970980Smckusick *
1073a8e095Sbostic * %sccs.include.redist.c%
11760e73c7Smckusick *
12*4ec9d53dSmckusick * @(#)vfs_vnops.c 8.14 (Berkeley) 06/15/95
13b5970980Smckusick */
1482e77ef7Ssam
156e23d7a0Sbostic #include <sys/param.h>
166e23d7a0Sbostic #include <sys/systm.h>
176e23d7a0Sbostic #include <sys/kernel.h>
186e23d7a0Sbostic #include <sys/file.h>
196e23d7a0Sbostic #include <sys/stat.h>
206e23d7a0Sbostic #include <sys/buf.h>
216e23d7a0Sbostic #include <sys/proc.h>
226e23d7a0Sbostic #include <sys/mount.h>
236e23d7a0Sbostic #include <sys/namei.h>
246e23d7a0Sbostic #include <sys/vnode.h>
256e23d7a0Sbostic #include <sys/ioctl.h>
266e23d7a0Sbostic #include <sys/tty.h>
276e23d7a0Sbostic
282a80cc9eSmckusick #include <vm/vm.h>
291d37f34bSbill
30760e73c7Smckusick struct fileops vnops =
311a59b964Smckusick { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
32ae1aeb7bSmckusick
331d37f34bSbill /*
34760e73c7Smckusick * Common code for vnode open operations.
35760e73c7Smckusick * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
361d37f34bSbill */
vn_open(ndp,fmode,cmode)37b1e88a53Smckusick vn_open(ndp, fmode, cmode)
38760e73c7Smckusick register struct nameidata *ndp;
39760e73c7Smckusick int fmode, cmode;
401d37f34bSbill {
41760e73c7Smckusick register struct vnode *vp;
42b1e88a53Smckusick register struct proc *p = ndp->ni_cnd.cn_proc;
436bd82dc0Smckusick register struct ucred *cred = p->p_ucred;
44760e73c7Smckusick struct vattr vat;
45760e73c7Smckusick struct vattr *vap = &vat;
46760e73c7Smckusick int error;
471d37f34bSbill
48552d28cbSmckusick if (fmode & O_CREAT) {
49b1e88a53Smckusick ndp->ni_cnd.cn_nameiop = CREATE;
50b1e88a53Smckusick ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
51552d28cbSmckusick if ((fmode & O_EXCL) == 0)
52b1e88a53Smckusick ndp->ni_cnd.cn_flags |= FOLLOW;
53b1e88a53Smckusick if (error = namei(ndp))
54760e73c7Smckusick return (error);
55760e73c7Smckusick if (ndp->ni_vp == NULL) {
569a8d5e2aSmckusick VATTR_NULL(vap);
57760e73c7Smckusick vap->va_type = VREG;
58760e73c7Smckusick vap->va_mode = cmode;
599879b7b8Smckusick if (fmode & O_EXCL)
609879b7b8Smckusick vap->va_vaflags |= VA_EXCLUSIVE;
615274606dSmckusick VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
62b1e88a53Smckusick if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
63b1e88a53Smckusick &ndp->ni_cnd, vap))
64760e73c7Smckusick return (error);
65552d28cbSmckusick fmode &= ~O_TRUNC;
66760e73c7Smckusick vp = ndp->ni_vp;
67760e73c7Smckusick } else {
68b1c104dbSheideman VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
6983225eaeSmckusick if (ndp->ni_dvp == ndp->ni_vp)
7083225eaeSmckusick vrele(ndp->ni_dvp);
71e8a20c25Smckusick else
7283225eaeSmckusick vput(ndp->ni_dvp);
7383225eaeSmckusick ndp->ni_dvp = NULL;
74760e73c7Smckusick vp = ndp->ni_vp;
75552d28cbSmckusick if (fmode & O_EXCL) {
76760e73c7Smckusick error = EEXIST;
77760e73c7Smckusick goto bad;
78760e73c7Smckusick }
79552d28cbSmckusick fmode &= ~O_CREAT;
80760e73c7Smckusick }
81760e73c7Smckusick } else {
82b1e88a53Smckusick ndp->ni_cnd.cn_nameiop = LOOKUP;
83b1e88a53Smckusick ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
84b1e88a53Smckusick if (error = namei(ndp))
85760e73c7Smckusick return (error);
86760e73c7Smckusick vp = ndp->ni_vp;
87760e73c7Smckusick }
88760e73c7Smckusick if (vp->v_type == VSOCK) {
89760e73c7Smckusick error = EOPNOTSUPP;
90760e73c7Smckusick goto bad;
91760e73c7Smckusick }
92552d28cbSmckusick if ((fmode & O_CREAT) == 0) {
93760e73c7Smckusick if (fmode & FREAD) {
942d8de7e9Smckusick if (error = VOP_ACCESS(vp, VREAD, cred, p))
95760e73c7Smckusick goto bad;
96760e73c7Smckusick }
97552d28cbSmckusick if (fmode & (FWRITE | O_TRUNC)) {
98760e73c7Smckusick if (vp->v_type == VDIR) {
99760e73c7Smckusick error = EISDIR;
100760e73c7Smckusick goto bad;
101760e73c7Smckusick }
102a597f5e9Smckusick if ((error = vn_writechk(vp)) ||
1032d8de7e9Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p)))
104a597f5e9Smckusick goto bad;
105760e73c7Smckusick }
106760e73c7Smckusick }
107552d28cbSmckusick if (fmode & O_TRUNC) {
10888c3d290Smckusick VOP_UNLOCK(vp, 0, p); /* XXX */
1095274606dSmckusick VOP_LEASE(vp, p, cred, LEASE_WRITE);
11088c3d290Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
1119a8d5e2aSmckusick VATTR_NULL(vap);
112760e73c7Smckusick vap->va_size = 0;
1132d8de7e9Smckusick if (error = VOP_SETATTR(vp, vap, cred, p))
114760e73c7Smckusick goto bad;
115760e73c7Smckusick }
116c121a858Smckusick if (error = VOP_OPEN(vp, fmode, cred, p))
117c121a858Smckusick goto bad;
118c121a858Smckusick if (fmode & FWRITE)
119c121a858Smckusick vp->v_writecount++;
120552d28cbSmckusick return (0);
121760e73c7Smckusick bad:
122760e73c7Smckusick vput(vp);
123760e73c7Smckusick return (error);
124760e73c7Smckusick }
125760e73c7Smckusick
12645db6fc1Ssam /*
127a597f5e9Smckusick * Check for write permissions on the specified vnode.
1282892e00fSmckusick * Prototype text segments cannot be written.
12945db6fc1Ssam */
vn_writechk(vp)130a597f5e9Smckusick vn_writechk(vp)
131760e73c7Smckusick register struct vnode *vp;
132760e73c7Smckusick {
133760e73c7Smckusick
134760e73c7Smckusick /*
13545db6fc1Ssam * If there's shared text associated with
136a597f5e9Smckusick * the vnode, try to free it up once. If
13745db6fc1Ssam * we fail, we can't allow writing.
13845db6fc1Ssam */
1393065037bSmckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
140760e73c7Smckusick return (ETXTBSY);
141a597f5e9Smckusick return (0);
1421d37f34bSbill }
1431d37f34bSbill
1441d37f34bSbill /*
1451a59b964Smckusick * Vnode close call
1461a59b964Smckusick */
vn_close(vp,flags,cred,p)1471a59b964Smckusick vn_close(vp, flags, cred, p)
1481a59b964Smckusick register struct vnode *vp;
1491a59b964Smckusick int flags;
1501a59b964Smckusick struct ucred *cred;
1511a59b964Smckusick struct proc *p;
1521a59b964Smckusick {
1531a59b964Smckusick int error;
1541a59b964Smckusick
1551a59b964Smckusick if (flags & FWRITE)
1561a59b964Smckusick vp->v_writecount--;
1571a59b964Smckusick error = VOP_CLOSE(vp, flags, cred, p);
1581a59b964Smckusick vrele(vp);
1591a59b964Smckusick return (error);
1601a59b964Smckusick }
1611a59b964Smckusick
1621a59b964Smckusick /*
1631a59b964Smckusick * Package up an I/O request on a vnode into a uio and do it.
1641d37f34bSbill */
1652d8de7e9Smckusick vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
166760e73c7Smckusick enum uio_rw rw;
167760e73c7Smckusick struct vnode *vp;
168760e73c7Smckusick caddr_t base;
169760e73c7Smckusick int len;
170760e73c7Smckusick off_t offset;
171760e73c7Smckusick enum uio_seg segflg;
172760e73c7Smckusick int ioflg;
173760e73c7Smckusick struct ucred *cred;
174760e73c7Smckusick int *aresid;
1752d8de7e9Smckusick struct proc *p;
1761d37f34bSbill {
177760e73c7Smckusick struct uio auio;
178760e73c7Smckusick struct iovec aiov;
179760e73c7Smckusick int error;
1801d37f34bSbill
1812a601dc3Smckusick if ((ioflg & IO_NODELOCKED) == 0)
18288c3d290Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
183760e73c7Smckusick auio.uio_iov = &aiov;
184760e73c7Smckusick auio.uio_iovcnt = 1;
185760e73c7Smckusick aiov.iov_base = base;
186760e73c7Smckusick aiov.iov_len = len;
187760e73c7Smckusick auio.uio_resid = len;
188760e73c7Smckusick auio.uio_offset = offset;
189760e73c7Smckusick auio.uio_segflg = segflg;
190760e73c7Smckusick auio.uio_rw = rw;
1912d8de7e9Smckusick auio.uio_procp = p;
192fdc68a99Smckusick if (rw == UIO_READ) {
1932a601dc3Smckusick error = VOP_READ(vp, &auio, ioflg, cred);
194fdc68a99Smckusick } else {
1952a601dc3Smckusick error = VOP_WRITE(vp, &auio, ioflg, cred);
196fdc68a99Smckusick }
197760e73c7Smckusick if (aresid)
198760e73c7Smckusick *aresid = auio.uio_resid;
199760e73c7Smckusick else
200760e73c7Smckusick if (auio.uio_resid && error == 0)
201760e73c7Smckusick error = EIO;
2022a601dc3Smckusick if ((ioflg & IO_NODELOCKED) == 0)
20388c3d290Smckusick VOP_UNLOCK(vp, 0, p);
204760e73c7Smckusick return (error);
2052510f0cdSmckusick }
2061d37f34bSbill
2071a59b964Smckusick /*
2081a59b964Smckusick * File table vnode read routine.
2091a59b964Smckusick */
210760e73c7Smckusick vn_read(fp, uio, cred)
211760e73c7Smckusick struct file *fp;
212760e73c7Smckusick struct uio *uio;
213760e73c7Smckusick struct ucred *cred;
2141d37f34bSbill {
21588c3d290Smckusick struct vnode *vp = (struct vnode *)fp->f_data;
21688c3d290Smckusick struct proc *p = uio->uio_procp;
2172a601dc3Smckusick int count, error;
2181d37f34bSbill
21988c3d290Smckusick VOP_LEASE(vp, p, cred, LEASE_READ);
22088c3d290Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2212a601dc3Smckusick uio->uio_offset = fp->f_offset;
2222a601dc3Smckusick count = uio->uio_resid;
223552d28cbSmckusick error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
224552d28cbSmckusick cred);
2252a601dc3Smckusick fp->f_offset += count - uio->uio_resid;
22688c3d290Smckusick VOP_UNLOCK(vp, 0, p);
2272a601dc3Smckusick return (error);
228760e73c7Smckusick }
229760e73c7Smckusick
2301a59b964Smckusick /*
2311a59b964Smckusick * File table vnode write routine.
2321a59b964Smckusick */
233760e73c7Smckusick vn_write(fp, uio, cred)
234760e73c7Smckusick struct file *fp;
235760e73c7Smckusick struct uio *uio;
236760e73c7Smckusick struct ucred *cred;
237760e73c7Smckusick {
23888c3d290Smckusick struct vnode *vp = (struct vnode *)fp->f_data;
23988c3d290Smckusick struct proc *p = uio->uio_procp;
24019849eecSmckusick int count, error, ioflag = IO_UNIT;
241760e73c7Smckusick
242552d28cbSmckusick if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
243760e73c7Smckusick ioflag |= IO_APPEND;
244552d28cbSmckusick if (fp->f_flag & FNONBLOCK)
245760e73c7Smckusick ioflag |= IO_NDELAY;
246*4ec9d53dSmckusick if ((fp->f_flag & O_FSYNC) ||
247*4ec9d53dSmckusick (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
2481821a922Smckusick ioflag |= IO_SYNC;
24988c3d290Smckusick VOP_LEASE(vp, p, cred, LEASE_WRITE);
25088c3d290Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2512a601dc3Smckusick uio->uio_offset = fp->f_offset;
2522a601dc3Smckusick count = uio->uio_resid;
2532a601dc3Smckusick error = VOP_WRITE(vp, uio, ioflag, cred);
2542a601dc3Smckusick if (ioflag & IO_APPEND)
2552a601dc3Smckusick fp->f_offset = uio->uio_offset;
2562a601dc3Smckusick else
2572a601dc3Smckusick fp->f_offset += count - uio->uio_resid;
25888c3d290Smckusick VOP_UNLOCK(vp, 0, p);
2592a601dc3Smckusick return (error);
260760e73c7Smckusick }
261760e73c7Smckusick
262760e73c7Smckusick /*
2631a59b964Smckusick * File table vnode stat routine.
264760e73c7Smckusick */
2652d8de7e9Smckusick vn_stat(vp, sb, p)
266760e73c7Smckusick struct vnode *vp;
267760e73c7Smckusick register struct stat *sb;
2682d8de7e9Smckusick struct proc *p;
269760e73c7Smckusick {
270760e73c7Smckusick struct vattr vattr;
271760e73c7Smckusick register struct vattr *vap;
272760e73c7Smckusick int error;
273760e73c7Smckusick u_short mode;
274760e73c7Smckusick
275760e73c7Smckusick vap = &vattr;
2762d8de7e9Smckusick error = VOP_GETATTR(vp, vap, p->p_ucred, p);
277760e73c7Smckusick if (error)
278760e73c7Smckusick return (error);
279760e73c7Smckusick /*
280760e73c7Smckusick * Copy from vattr table
281760e73c7Smckusick */
282760e73c7Smckusick sb->st_dev = vap->va_fsid;
283760e73c7Smckusick sb->st_ino = vap->va_fileid;
284760e73c7Smckusick mode = vap->va_mode;
285760e73c7Smckusick switch (vp->v_type) {
286760e73c7Smckusick case VREG:
2876357f7baSmckusick mode |= S_IFREG;
288760e73c7Smckusick break;
289760e73c7Smckusick case VDIR:
2906357f7baSmckusick mode |= S_IFDIR;
291760e73c7Smckusick break;
292760e73c7Smckusick case VBLK:
2936357f7baSmckusick mode |= S_IFBLK;
294760e73c7Smckusick break;
295760e73c7Smckusick case VCHR:
2966357f7baSmckusick mode |= S_IFCHR;
297760e73c7Smckusick break;
298760e73c7Smckusick case VLNK:
2996357f7baSmckusick mode |= S_IFLNK;
300760e73c7Smckusick break;
301760e73c7Smckusick case VSOCK:
3026357f7baSmckusick mode |= S_IFSOCK;
303760e73c7Smckusick break;
304920ab10fSmckusick case VFIFO:
305920ab10fSmckusick mode |= S_IFIFO;
306920ab10fSmckusick break;
307760e73c7Smckusick default:
308760e73c7Smckusick return (EBADF);
309760e73c7Smckusick };
310760e73c7Smckusick sb->st_mode = mode;
311760e73c7Smckusick sb->st_nlink = vap->va_nlink;
312760e73c7Smckusick sb->st_uid = vap->va_uid;
313760e73c7Smckusick sb->st_gid = vap->va_gid;
314760e73c7Smckusick sb->st_rdev = vap->va_rdev;
315760e73c7Smckusick sb->st_size = vap->va_size;
3161c5a6ce1Smckusick sb->st_atimespec = vap->va_atime;
3171c5a6ce1Smckusick sb->st_mtimespec = vap->va_mtime;
3181c5a6ce1Smckusick sb->st_ctimespec = vap->va_ctime;
319760e73c7Smckusick sb->st_blksize = vap->va_blocksize;
32018b27549Smckusick sb->st_flags = vap->va_flags;
32118b27549Smckusick sb->st_gen = vap->va_gen;
322aa6f7503Smckusick sb->st_blocks = vap->va_bytes / S_BLKSIZE;
3231d37f34bSbill return (0);
3241d37f34bSbill }
325760e73c7Smckusick
326760e73c7Smckusick /*
3271a59b964Smckusick * File table vnode ioctl routine.
328760e73c7Smckusick */
3292d8de7e9Smckusick vn_ioctl(fp, com, data, p)
330760e73c7Smckusick struct file *fp;
331d1a6a392Scgd u_long com;
332760e73c7Smckusick caddr_t data;
3332d8de7e9Smckusick struct proc *p;
334760e73c7Smckusick {
335760e73c7Smckusick register struct vnode *vp = ((struct vnode *)fp->f_data);
336760e73c7Smckusick struct vattr vattr;
337760e73c7Smckusick int error;
338760e73c7Smckusick
339760e73c7Smckusick switch (vp->v_type) {
340760e73c7Smckusick
341760e73c7Smckusick case VREG:
342760e73c7Smckusick case VDIR:
343760e73c7Smckusick if (com == FIONREAD) {
3442d8de7e9Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
345760e73c7Smckusick return (error);
346f0ba414aStorek *(int *)data = vattr.va_size - fp->f_offset;
347760e73c7Smckusick return (0);
348760e73c7Smckusick }
349760e73c7Smckusick if (com == FIONBIO || com == FIOASYNC) /* XXX */
350760e73c7Smckusick return (0); /* XXX */
351760e73c7Smckusick /* fall into ... */
352760e73c7Smckusick
353760e73c7Smckusick default:
354760e73c7Smckusick return (ENOTTY);
355760e73c7Smckusick
356920ab10fSmckusick case VFIFO:
357760e73c7Smckusick case VCHR:
358760e73c7Smckusick case VBLK:
3592d8de7e9Smckusick error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
360e79e4887Smarc if (error == 0 && com == TIOCSCTTY) {
3613dc20f1fSmckusick if (p->p_session->s_ttyvp)
3623dc20f1fSmckusick vrele(p->p_session->s_ttyvp);
3630b0833e3Skarels p->p_session->s_ttyvp = vp;
364e79e4887Smarc VREF(vp);
365e79e4887Smarc }
366e79e4887Smarc return (error);
367760e73c7Smckusick }
368760e73c7Smckusick }
369760e73c7Smckusick
370760e73c7Smckusick /*
3711a59b964Smckusick * File table vnode select routine.
372760e73c7Smckusick */
3732d8de7e9Smckusick vn_select(fp, which, p)
374760e73c7Smckusick struct file *fp;
375760e73c7Smckusick int which;
3762d8de7e9Smckusick struct proc *p;
377760e73c7Smckusick {
3780b0833e3Skarels
379920ab10fSmckusick return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
3801a59b964Smckusick fp->f_cred, p));
381760e73c7Smckusick }
382760e73c7Smckusick
383760e73c7Smckusick /*
38488c3d290Smckusick * Check that the vnode is still valid, and if so
38588c3d290Smckusick * acquire requested lock.
38688c3d290Smckusick */
38788c3d290Smckusick int
vn_lock(vp,flags,p)38888c3d290Smckusick vn_lock(vp, flags, p)
38988c3d290Smckusick struct vnode *vp;
39088c3d290Smckusick int flags;
39188c3d290Smckusick struct proc *p;
39288c3d290Smckusick {
39388c3d290Smckusick int error;
39488c3d290Smckusick
39588c3d290Smckusick do {
39688c3d290Smckusick if ((flags & LK_INTERLOCK) == 0)
39788c3d290Smckusick simple_lock(&vp->v_interlock);
39888c3d290Smckusick if (vp->v_flag & VXLOCK) {
39988c3d290Smckusick vp->v_flag |= VXWANT;
40088c3d290Smckusick simple_unlock(&vp->v_interlock);
40188c3d290Smckusick tsleep((caddr_t)vp, PINOD, "vn_lock", 0);
40288c3d290Smckusick error = ENOENT;
40388c3d290Smckusick } else {
40488c3d290Smckusick error = VOP_LOCK(vp, flags | LK_INTERLOCK, p);
40588c3d290Smckusick if (error == 0)
40688c3d290Smckusick return (error);
40788c3d290Smckusick }
40888c3d290Smckusick flags &= ~LK_INTERLOCK;
40988c3d290Smckusick } while (flags & LK_RETRY);
41088c3d290Smckusick return (error);
41188c3d290Smckusick }
41288c3d290Smckusick
41388c3d290Smckusick /*
4141a59b964Smckusick * File table vnode close routine.
415760e73c7Smckusick */
4161a59b964Smckusick vn_closefile(fp, p)
4171a59b964Smckusick struct file *fp;
4182d8de7e9Smckusick struct proc *p;
419760e73c7Smckusick {
420760e73c7Smckusick
4211a59b964Smckusick return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
4221a59b964Smckusick fp->f_cred, p));
423760e73c7Smckusick }
424