have to protect acct_process from acctwatch closing the vnode
[unix-history] / usr / src / sys / kern / vfs_vnops.c
CommitLineData
da7c5cc6 1/*
ec54f0cc
KB
2 * Copyright (c) 1982, 1986, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
adb35f79
KB
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
da7c5cc6 9 *
dbf0c423 10 * %sccs.include.redist.c%
eb668bc6 11 *
ec8640fc 12 * @(#)vfs_vnops.c 8.4 (Berkeley) %G%
da7c5cc6 13 */
961945a8 14
38a01dbe
KB
15#include <sys/param.h>
16#include <sys/systm.h>
17#include <sys/kernel.h>
18#include <sys/file.h>
19#include <sys/stat.h>
20#include <sys/buf.h>
21#include <sys/proc.h>
22#include <sys/mount.h>
23#include <sys/namei.h>
24#include <sys/vnode.h>
25#include <sys/ioctl.h>
26#include <sys/tty.h>
27
8b4f20bf 28#include <vm/vm.h>
fc96c615 29
eb668bc6 30struct fileops vnops =
97f761d2 31 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
d301d150 32
fc96c615 33/*
eb668bc6
KM
34 * Common code for vnode open operations.
35 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
fc96c615 36 */
35dccb0f 37vn_open(ndp, fmode, cmode)
eb668bc6
KM
38 register struct nameidata *ndp;
39 int fmode, cmode;
40{
41 register struct vnode *vp;
35dccb0f 42 register struct proc *p = ndp->ni_cnd.cn_proc;
9b808fbd 43 register struct ucred *cred = p->p_ucred;
eb668bc6
KM
44 struct vattr vat;
45 struct vattr *vap = &vat;
46 int error;
47
63992c37 48 if (fmode & O_CREAT) {
35dccb0f
KM
49 ndp->ni_cnd.cn_nameiop = CREATE;
50 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
63992c37 51 if ((fmode & O_EXCL) == 0)
35dccb0f
KM
52 ndp->ni_cnd.cn_flags |= FOLLOW;
53 if (error = namei(ndp))
eb668bc6
KM
54 return (error);
55 if (ndp->ni_vp == NULL) {
3ee1461b 56 VATTR_NULL(vap);
eb668bc6
KM
57 vap->va_type = VREG;
58 vap->va_mode = cmode;
4c5d3e43 59 VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
35dccb0f
KM
60 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
61 &ndp->ni_cnd, vap))
eb668bc6 62 return (error);
63992c37 63 fmode &= ~O_TRUNC;
eb668bc6
KM
64 vp = ndp->ni_vp;
65 } else {
cfef4373 66 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
3f530a7b
KM
67 if (ndp->ni_dvp == ndp->ni_vp)
68 vrele(ndp->ni_dvp);
7341981c 69 else
3f530a7b
KM
70 vput(ndp->ni_dvp);
71 ndp->ni_dvp = NULL;
eb668bc6 72 vp = ndp->ni_vp;
63992c37 73 if (fmode & O_EXCL) {
eb668bc6
KM
74 error = EEXIST;
75 goto bad;
76 }
63992c37 77 fmode &= ~O_CREAT;
eb668bc6
KM
78 }
79 } else {
35dccb0f
KM
80 ndp->ni_cnd.cn_nameiop = LOOKUP;
81 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
82 if (error = namei(ndp))
eb668bc6
KM
83 return (error);
84 vp = ndp->ni_vp;
85 }
86 if (vp->v_type == VSOCK) {
87 error = EOPNOTSUPP;
88 goto bad;
89 }
63992c37 90 if ((fmode & O_CREAT) == 0) {
eb668bc6 91 if (fmode & FREAD) {
a9194d51 92 if (error = VOP_ACCESS(vp, VREAD, cred, p))
eb668bc6
KM
93 goto bad;
94 }
63992c37 95 if (fmode & (FWRITE | O_TRUNC)) {
eb668bc6
KM
96 if (vp->v_type == VDIR) {
97 error = EISDIR;
98 goto bad;
99 }
cd811e9a 100 if ((error = vn_writechk(vp)) ||
a9194d51 101 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
cd811e9a 102 goto bad;
eb668bc6
KM
103 }
104 }
63992c37 105 if (fmode & O_TRUNC) {
dbcf7de6 106 VOP_UNLOCK(vp); /* XXX */
4c5d3e43 107 VOP_LEASE(vp, p, cred, LEASE_WRITE);
dbcf7de6 108 VOP_LOCK(vp); /* XXX */
3ee1461b 109 VATTR_NULL(vap);
eb668bc6 110 vap->va_size = 0;
a9194d51 111 if (error = VOP_SETATTR(vp, vap, cred, p))
eb668bc6
KM
112 goto bad;
113 }
cb3e538f
KM
114 if (error = VOP_OPEN(vp, fmode, cred, p))
115 goto bad;
116 if (fmode & FWRITE)
117 vp->v_writecount++;
118 return (0);
eb668bc6
KM
119bad:
120 vput(vp);
ccee3c59 121 return (error);
eb668bc6
KM
122}
123
124/*
cd811e9a
KM
125 * Check for write permissions on the specified vnode.
126 * The read-only status of the file system is checked.
127 * Also, prototype text segments cannot be written.
eb668bc6 128 */
cd811e9a 129vn_writechk(vp)
eb668bc6 130 register struct vnode *vp;
fc96c615 131{
fc96c615 132
cd811e9a
KM
133 /*
134 * Disallow write attempts on read-only file systems;
135 * unless the file is a socket or a block or character
136 * device resident on the file system.
137 */
5216fbe4
KM
138 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
139 switch (vp->v_type) {
140 case VREG: case VDIR: case VLNK:
141 return (EROFS);
142 }
143 }
cd811e9a
KM
144 /*
145 * If there's shared text associated with
146 * the vnode, try to free it up once. If
147 * we fail, we can't allow writing.
148 */
9db58063 149 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
cd811e9a
KM
150 return (ETXTBSY);
151 return (0);
eb668bc6
KM
152}
153
154/*
97f761d2
KM
155 * Vnode close call
156 */
157vn_close(vp, flags, cred, p)
158 register struct vnode *vp;
159 int flags;
160 struct ucred *cred;
161 struct proc *p;
162{
163 int error;
164
165 if (flags & FWRITE)
166 vp->v_writecount--;
167 error = VOP_CLOSE(vp, flags, cred, p);
168 vrele(vp);
169 return (error);
170}
171
172/*
173 * Package up an I/O request on a vnode into a uio and do it.
eb668bc6 174 */
a9194d51 175vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
eb668bc6
KM
176 enum uio_rw rw;
177 struct vnode *vp;
178 caddr_t base;
179 int len;
180 off_t offset;
181 enum uio_seg segflg;
182 int ioflg;
183 struct ucred *cred;
184 int *aresid;
a9194d51 185 struct proc *p;
eb668bc6
KM
186{
187 struct uio auio;
188 struct iovec aiov;
189 int error;
190
cde34f67
KM
191 if ((ioflg & IO_NODELOCKED) == 0)
192 VOP_LOCK(vp);
eb668bc6
KM
193 auio.uio_iov = &aiov;
194 auio.uio_iovcnt = 1;
195 aiov.iov_base = base;
196 aiov.iov_len = len;
197 auio.uio_resid = len;
198 auio.uio_offset = offset;
199 auio.uio_segflg = segflg;
200 auio.uio_rw = rw;
a9194d51 201 auio.uio_procp = p;
73019d79 202 if (rw == UIO_READ) {
cde34f67 203 error = VOP_READ(vp, &auio, ioflg, cred);
73019d79 204 } else {
cde34f67 205 error = VOP_WRITE(vp, &auio, ioflg, cred);
73019d79 206 }
eb668bc6
KM
207 if (aresid)
208 *aresid = auio.uio_resid;
209 else
210 if (auio.uio_resid && error == 0)
211 error = EIO;
cde34f67
KM
212 if ((ioflg & IO_NODELOCKED) == 0)
213 VOP_UNLOCK(vp);
eb668bc6
KM
214 return (error);
215}
216
97f761d2
KM
217/*
218 * File table vnode read routine.
219 */
eb668bc6
KM
220vn_read(fp, uio, cred)
221 struct file *fp;
222 struct uio *uio;
223 struct ucred *cred;
224{
cde34f67
KM
225 register struct vnode *vp = (struct vnode *)fp->f_data;
226 int count, error;
eb668bc6 227
4c5d3e43 228 VOP_LEASE(vp, uio->uio_procp, cred, LEASE_READ);
cde34f67
KM
229 VOP_LOCK(vp);
230 uio->uio_offset = fp->f_offset;
231 count = uio->uio_resid;
63992c37
KM
232 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
233 cred);
cde34f67
KM
234 fp->f_offset += count - uio->uio_resid;
235 VOP_UNLOCK(vp);
236 return (error);
eb668bc6
KM
237}
238
97f761d2
KM
239/*
240 * File table vnode write routine.
241 */
eb668bc6
KM
242vn_write(fp, uio, cred)
243 struct file *fp;
244 struct uio *uio;
245 struct ucred *cred;
246{
247 register struct vnode *vp = (struct vnode *)fp->f_data;
cde34f67 248 int count, error, ioflag = 0;
eb668bc6 249
63992c37 250 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
eb668bc6 251 ioflag |= IO_APPEND;
63992c37 252 if (fp->f_flag & FNONBLOCK)
eb668bc6 253 ioflag |= IO_NDELAY;
4c5d3e43 254 VOP_LEASE(vp, uio->uio_procp, cred, LEASE_WRITE);
cde34f67
KM
255 VOP_LOCK(vp);
256 uio->uio_offset = fp->f_offset;
257 count = uio->uio_resid;
258 error = VOP_WRITE(vp, uio, ioflag, cred);
259 if (ioflag & IO_APPEND)
260 fp->f_offset = uio->uio_offset;
261 else
262 fp->f_offset += count - uio->uio_resid;
263 VOP_UNLOCK(vp);
264 return (error);
eb668bc6
KM
265}
266
267/*
97f761d2 268 * File table vnode stat routine.
eb668bc6 269 */
a9194d51 270vn_stat(vp, sb, p)
eb668bc6
KM
271 struct vnode *vp;
272 register struct stat *sb;
a9194d51 273 struct proc *p;
eb668bc6
KM
274{
275 struct vattr vattr;
276 register struct vattr *vap;
277 int error;
278 u_short mode;
279
280 vap = &vattr;
a9194d51 281 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
eb668bc6
KM
282 if (error)
283 return (error);
284 /*
285 * Copy from vattr table
286 */
287 sb->st_dev = vap->va_fsid;
288 sb->st_ino = vap->va_fileid;
289 mode = vap->va_mode;
290 switch (vp->v_type) {
291 case VREG:
2e3baa4b 292 mode |= S_IFREG;
eb668bc6
KM
293 break;
294 case VDIR:
2e3baa4b 295 mode |= S_IFDIR;
eb668bc6
KM
296 break;
297 case VBLK:
2e3baa4b 298 mode |= S_IFBLK;
eb668bc6
KM
299 break;
300 case VCHR:
2e3baa4b 301 mode |= S_IFCHR;
eb668bc6
KM
302 break;
303 case VLNK:
2e3baa4b 304 mode |= S_IFLNK;
eb668bc6
KM
305 break;
306 case VSOCK:
2e3baa4b 307 mode |= S_IFSOCK;
eb668bc6 308 break;
0099f400
KM
309 case VFIFO:
310 mode |= S_IFIFO;
311 break;
eb668bc6
KM
312 default:
313 return (EBADF);
314 };
315 sb->st_mode = mode;
316 sb->st_nlink = vap->va_nlink;
317 sb->st_uid = vap->va_uid;
318 sb->st_gid = vap->va_gid;
319 sb->st_rdev = vap->va_rdev;
320 sb->st_size = vap->va_size;
7e11a0c9
KM
321 sb->st_atimespec = vap->va_atime;
322 sb->st_mtimespec= vap->va_mtime;
323 sb->st_ctimespec = vap->va_ctime;
eb668bc6 324 sb->st_blksize = vap->va_blocksize;
2ff0b8da
KM
325 sb->st_flags = vap->va_flags;
326 sb->st_gen = vap->va_gen;
366f2ef0 327 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
eb668bc6
KM
328 return (0);
329}
330
331/*
97f761d2 332 * File table vnode ioctl routine.
eb668bc6 333 */
a9194d51 334vn_ioctl(fp, com, data, p)
eb668bc6
KM
335 struct file *fp;
336 int com;
337 caddr_t data;
a9194d51 338 struct proc *p;
eb668bc6
KM
339{
340 register struct vnode *vp = ((struct vnode *)fp->f_data);
341 struct vattr vattr;
342 int error;
343
344 switch (vp->v_type) {
345
346 case VREG:
347 case VDIR:
348 if (com == FIONREAD) {
a9194d51 349 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
eb668bc6 350 return (error);
a85f307a 351 *(int *)data = vattr.va_size - fp->f_offset;
eb668bc6
KM
352 return (0);
353 }
354 if (com == FIONBIO || com == FIOASYNC) /* XXX */
355 return (0); /* XXX */
356 /* fall into ... */
357
358 default:
359 return (ENOTTY);
360
0099f400 361 case VFIFO:
eb668bc6
KM
362 case VCHR:
363 case VBLK:
a9194d51 364 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
1665da5a 365 if (error == 0 && com == TIOCSCTTY) {
ec8640fc
KM
366 if (p->p_session->s_ttyvp)
367 vrele(p->p_session->s_ttyvp);
8429d022 368 p->p_session->s_ttyvp = vp;
1665da5a
MT
369 VREF(vp);
370 }
371 return (error);
fc96c615 372 }
eb668bc6
KM
373}
374
375/*
97f761d2 376 * File table vnode select routine.
eb668bc6 377 */
a9194d51 378vn_select(fp, which, p)
eb668bc6
KM
379 struct file *fp;
380 int which;
a9194d51 381 struct proc *p;
eb668bc6 382{
8429d022 383
ccee3c59 384 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
97f761d2 385 fp->f_cred, p));
eb668bc6
KM
386}
387
388/*
97f761d2 389 * File table vnode close routine.
eb668bc6 390 */
97f761d2
KM
391vn_closefile(fp, p)
392 struct file *fp;
a9194d51 393 struct proc *p;
eb668bc6 394{
eb668bc6 395
97f761d2
KM
396 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
397 fp->f_cred, p));
eb668bc6 398}