add definition for ability to produce a backtrace
[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 *
ec5d3354 12 * @(#)vfs_vnops.c 8.12 (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;
b9476051
KM
59 if (fmode & O_EXCL)
60 vap->va_vaflags |= VA_EXCLUSIVE;
4c5d3e43 61 VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
35dccb0f
KM
62 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
63 &ndp->ni_cnd, vap))
eb668bc6 64 return (error);
63992c37 65 fmode &= ~O_TRUNC;
eb668bc6
KM
66 vp = ndp->ni_vp;
67 } else {
cfef4373 68 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
3f530a7b
KM
69 if (ndp->ni_dvp == ndp->ni_vp)
70 vrele(ndp->ni_dvp);
7341981c 71 else
3f530a7b
KM
72 vput(ndp->ni_dvp);
73 ndp->ni_dvp = NULL;
eb668bc6 74 vp = ndp->ni_vp;
63992c37 75 if (fmode & O_EXCL) {
eb668bc6
KM
76 error = EEXIST;
77 goto bad;
78 }
63992c37 79 fmode &= ~O_CREAT;
eb668bc6
KM
80 }
81 } else {
35dccb0f
KM
82 ndp->ni_cnd.cn_nameiop = LOOKUP;
83 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
84 if (error = namei(ndp))
eb668bc6
KM
85 return (error);
86 vp = ndp->ni_vp;
87 }
88 if (vp->v_type == VSOCK) {
89 error = EOPNOTSUPP;
90 goto bad;
91 }
63992c37 92 if ((fmode & O_CREAT) == 0) {
eb668bc6 93 if (fmode & FREAD) {
a9194d51 94 if (error = VOP_ACCESS(vp, VREAD, cred, p))
eb668bc6
KM
95 goto bad;
96 }
63992c37 97 if (fmode & (FWRITE | O_TRUNC)) {
eb668bc6
KM
98 if (vp->v_type == VDIR) {
99 error = EISDIR;
100 goto bad;
101 }
cd811e9a 102 if ((error = vn_writechk(vp)) ||
a9194d51 103 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
cd811e9a 104 goto bad;
eb668bc6
KM
105 }
106 }
63992c37 107 if (fmode & O_TRUNC) {
b521daef 108 VOP_UNLOCK(vp, 0, p); /* XXX */
4c5d3e43 109 VOP_LEASE(vp, p, cred, LEASE_WRITE);
b521daef 110 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
3ee1461b 111 VATTR_NULL(vap);
eb668bc6 112 vap->va_size = 0;
a9194d51 113 if (error = VOP_SETATTR(vp, vap, cred, p))
eb668bc6
KM
114 goto bad;
115 }
cb3e538f
KM
116 if (error = VOP_OPEN(vp, fmode, cred, p))
117 goto bad;
118 if (fmode & FWRITE)
119 vp->v_writecount++;
120 return (0);
eb668bc6
KM
121bad:
122 vput(vp);
ccee3c59 123 return (error);
eb668bc6
KM
124}
125
126/*
cd811e9a
KM
127 * Check for write permissions on the specified vnode.
128 * The read-only status of the file system is checked.
129 * Also, prototype text segments cannot be written.
eb668bc6 130 */
cd811e9a 131vn_writechk(vp)
eb668bc6 132 register struct vnode *vp;
fc96c615 133{
fc96c615 134
cd811e9a
KM
135 /*
136 * Disallow write attempts on read-only file systems;
137 * unless the file is a socket or a block or character
138 * device resident on the file system.
139 */
5216fbe4
KM
140 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
141 switch (vp->v_type) {
142 case VREG: case VDIR: case VLNK:
143 return (EROFS);
144 }
145 }
cd811e9a
KM
146 /*
147 * If there's shared text associated with
148 * the vnode, try to free it up once. If
149 * we fail, we can't allow writing.
150 */
9db58063 151 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
cd811e9a
KM
152 return (ETXTBSY);
153 return (0);
eb668bc6
KM
154}
155
156/*
97f761d2
KM
157 * Vnode close call
158 */
159vn_close(vp, flags, cred, p)
160 register struct vnode *vp;
161 int flags;
162 struct ucred *cred;
163 struct proc *p;
164{
165 int error;
166
167 if (flags & FWRITE)
168 vp->v_writecount--;
169 error = VOP_CLOSE(vp, flags, cred, p);
170 vrele(vp);
171 return (error);
172}
173
174/*
175 * Package up an I/O request on a vnode into a uio and do it.
eb668bc6 176 */
a9194d51 177vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
eb668bc6
KM
178 enum uio_rw rw;
179 struct vnode *vp;
180 caddr_t base;
181 int len;
182 off_t offset;
183 enum uio_seg segflg;
184 int ioflg;
185 struct ucred *cred;
186 int *aresid;
a9194d51 187 struct proc *p;
eb668bc6
KM
188{
189 struct uio auio;
190 struct iovec aiov;
191 int error;
192
cde34f67 193 if ((ioflg & IO_NODELOCKED) == 0)
b521daef 194 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
eb668bc6
KM
195 auio.uio_iov = &aiov;
196 auio.uio_iovcnt = 1;
197 aiov.iov_base = base;
198 aiov.iov_len = len;
199 auio.uio_resid = len;
200 auio.uio_offset = offset;
201 auio.uio_segflg = segflg;
202 auio.uio_rw = rw;
a9194d51 203 auio.uio_procp = p;
73019d79 204 if (rw == UIO_READ) {
cde34f67 205 error = VOP_READ(vp, &auio, ioflg, cred);
73019d79 206 } else {
cde34f67 207 error = VOP_WRITE(vp, &auio, ioflg, cred);
73019d79 208 }
eb668bc6
KM
209 if (aresid)
210 *aresid = auio.uio_resid;
211 else
212 if (auio.uio_resid && error == 0)
213 error = EIO;
cde34f67 214 if ((ioflg & IO_NODELOCKED) == 0)
b521daef 215 VOP_UNLOCK(vp, 0, p);
eb668bc6
KM
216 return (error);
217}
218
97f761d2
KM
219/*
220 * File table vnode read routine.
221 */
eb668bc6
KM
222vn_read(fp, uio, cred)
223 struct file *fp;
224 struct uio *uio;
225 struct ucred *cred;
226{
b521daef
KM
227 struct vnode *vp = (struct vnode *)fp->f_data;
228 struct proc *p = uio->uio_procp;
cde34f67 229 int count, error;
eb668bc6 230
b521daef
KM
231 VOP_LEASE(vp, p, cred, LEASE_READ);
232 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
cde34f67
KM
233 uio->uio_offset = fp->f_offset;
234 count = uio->uio_resid;
63992c37
KM
235 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
236 cred);
cde34f67 237 fp->f_offset += count - uio->uio_resid;
b521daef 238 VOP_UNLOCK(vp, 0, p);
cde34f67 239 return (error);
eb668bc6
KM
240}
241
97f761d2
KM
242/*
243 * File table vnode write routine.
244 */
eb668bc6
KM
245vn_write(fp, uio, cred)
246 struct file *fp;
247 struct uio *uio;
248 struct ucred *cred;
249{
b521daef
KM
250 struct vnode *vp = (struct vnode *)fp->f_data;
251 struct proc *p = uio->uio_procp;
372eeccf 252 int count, error, ioflag = IO_UNIT;
eb668bc6 253
63992c37 254 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
eb668bc6 255 ioflag |= IO_APPEND;
63992c37 256 if (fp->f_flag & FNONBLOCK)
eb668bc6 257 ioflag |= IO_NDELAY;
1b684215 258 if ((fp->f_flag & O_FSYNC) || (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))
02693858 259 ioflag |= IO_SYNC;
b521daef
KM
260 VOP_LEASE(vp, p, cred, LEASE_WRITE);
261 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
cde34f67
KM
262 uio->uio_offset = fp->f_offset;
263 count = uio->uio_resid;
264 error = VOP_WRITE(vp, uio, ioflag, cred);
265 if (ioflag & IO_APPEND)
266 fp->f_offset = uio->uio_offset;
267 else
268 fp->f_offset += count - uio->uio_resid;
b521daef 269 VOP_UNLOCK(vp, 0, p);
cde34f67 270 return (error);
eb668bc6
KM
271}
272
273/*
97f761d2 274 * File table vnode stat routine.
eb668bc6 275 */
a9194d51 276vn_stat(vp, sb, p)
eb668bc6
KM
277 struct vnode *vp;
278 register struct stat *sb;
a9194d51 279 struct proc *p;
eb668bc6
KM
280{
281 struct vattr vattr;
282 register struct vattr *vap;
283 int error;
284 u_short mode;
285
286 vap = &vattr;
a9194d51 287 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
eb668bc6
KM
288 if (error)
289 return (error);
290 /*
291 * Copy from vattr table
292 */
293 sb->st_dev = vap->va_fsid;
294 sb->st_ino = vap->va_fileid;
295 mode = vap->va_mode;
296 switch (vp->v_type) {
297 case VREG:
2e3baa4b 298 mode |= S_IFREG;
eb668bc6
KM
299 break;
300 case VDIR:
2e3baa4b 301 mode |= S_IFDIR;
eb668bc6
KM
302 break;
303 case VBLK:
2e3baa4b 304 mode |= S_IFBLK;
eb668bc6
KM
305 break;
306 case VCHR:
2e3baa4b 307 mode |= S_IFCHR;
eb668bc6
KM
308 break;
309 case VLNK:
2e3baa4b 310 mode |= S_IFLNK;
eb668bc6
KM
311 break;
312 case VSOCK:
2e3baa4b 313 mode |= S_IFSOCK;
eb668bc6 314 break;
0099f400
KM
315 case VFIFO:
316 mode |= S_IFIFO;
317 break;
eb668bc6
KM
318 default:
319 return (EBADF);
320 };
321 sb->st_mode = mode;
322 sb->st_nlink = vap->va_nlink;
323 sb->st_uid = vap->va_uid;
324 sb->st_gid = vap->va_gid;
325 sb->st_rdev = vap->va_rdev;
326 sb->st_size = vap->va_size;
7e11a0c9 327 sb->st_atimespec = vap->va_atime;
e3460a8d 328 sb->st_mtimespec = vap->va_mtime;
7e11a0c9 329 sb->st_ctimespec = vap->va_ctime;
eb668bc6 330 sb->st_blksize = vap->va_blocksize;
2ff0b8da
KM
331 sb->st_flags = vap->va_flags;
332 sb->st_gen = vap->va_gen;
366f2ef0 333 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
eb668bc6
KM
334 return (0);
335}
336
337/*
97f761d2 338 * File table vnode ioctl routine.
eb668bc6 339 */
a9194d51 340vn_ioctl(fp, com, data, p)
eb668bc6 341 struct file *fp;
5d263ebe 342 u_long com;
eb668bc6 343 caddr_t data;
a9194d51 344 struct proc *p;
eb668bc6
KM
345{
346 register struct vnode *vp = ((struct vnode *)fp->f_data);
347 struct vattr vattr;
348 int error;
349
350 switch (vp->v_type) {
351
352 case VREG:
353 case VDIR:
354 if (com == FIONREAD) {
a9194d51 355 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
eb668bc6 356 return (error);
a85f307a 357 *(int *)data = vattr.va_size - fp->f_offset;
eb668bc6
KM
358 return (0);
359 }
360 if (com == FIONBIO || com == FIOASYNC) /* XXX */
361 return (0); /* XXX */
362 /* fall into ... */
363
364 default:
365 return (ENOTTY);
366
0099f400 367 case VFIFO:
eb668bc6
KM
368 case VCHR:
369 case VBLK:
a9194d51 370 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
1665da5a 371 if (error == 0 && com == TIOCSCTTY) {
ec8640fc
KM
372 if (p->p_session->s_ttyvp)
373 vrele(p->p_session->s_ttyvp);
8429d022 374 p->p_session->s_ttyvp = vp;
1665da5a
MT
375 VREF(vp);
376 }
377 return (error);
fc96c615 378 }
eb668bc6
KM
379}
380
381/*
97f761d2 382 * File table vnode select routine.
eb668bc6 383 */
a9194d51 384vn_select(fp, which, p)
eb668bc6
KM
385 struct file *fp;
386 int which;
a9194d51 387 struct proc *p;
eb668bc6 388{
8429d022 389
ccee3c59 390 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
97f761d2 391 fp->f_cred, p));
eb668bc6
KM
392}
393
b521daef
KM
394/*
395 * Check that the vnode is still valid, and if so
396 * acquire requested lock.
397 */
398int
399vn_lock(vp, flags, p)
400 struct vnode *vp;
401 int flags;
402 struct proc *p;
403{
404 int error;
405
406 do {
407 if ((flags & LK_INTERLOCK) == 0)
408 simple_lock(&vp->v_interlock);
409 if (vp->v_flag & VXLOCK) {
410 vp->v_flag |= VXWANT;
411 simple_unlock(&vp->v_interlock);
412 tsleep((caddr_t)vp, PINOD, "vn_lock", 0);
413 error = ENOENT;
414 } else {
415 error = VOP_LOCK(vp, flags | LK_INTERLOCK, p);
416 if (error == 0)
417 return (error);
b521daef
KM
418 }
419 flags &= ~LK_INTERLOCK;
420 } while (flags & LK_RETRY);
421 return (error);
422}
423
eb668bc6 424/*
97f761d2 425 * File table vnode close routine.
eb668bc6 426 */
97f761d2
KM
427vn_closefile(fp, p)
428 struct file *fp;
a9194d51 429 struct proc *p;
eb668bc6 430{
eb668bc6 431
97f761d2
KM
432 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
433 fp->f_cred, p));
eb668bc6 434}