routing messages do not come with attached addresses
[unix-history] / usr / src / sys / kern / vfs_vnops.c
CommitLineData
da7c5cc6 1/*
eb668bc6
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
eb668bc6
KM
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
7deb2fe9 17 * @(#)vfs_vnops.c 7.22 (Berkeley) %G%
da7c5cc6 18 */
961945a8 19
94368568
JB
20#include "param.h"
21#include "systm.h"
94368568 22#include "user.h"
eb668bc6 23#include "kernel.h"
94368568 24#include "file.h"
eb668bc6
KM
25#include "stat.h"
26#include "buf.h"
27#include "proc.h"
28#include "uio.h"
94368568
JB
29#include "socket.h"
30#include "socketvar.h"
eb668bc6
KM
31#include "mount.h"
32#include "vnode.h"
eb668bc6
KM
33#include "ioctl.h"
34#include "tty.h"
fc96c615 35
eb668bc6
KM
36int vn_read(), vn_write(), vn_ioctl(), vn_select(), vn_close();
37struct fileops vnops =
38 { vn_read, vn_write, vn_ioctl, vn_select, vn_close };
d301d150 39
fc96c615 40/*
eb668bc6
KM
41 * Common code for vnode open operations.
42 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
fc96c615 43 */
eb668bc6
KM
44vn_open(ndp, fmode, cmode)
45 register struct nameidata *ndp;
46 int fmode, cmode;
47{
48 register struct vnode *vp;
49 struct vattr vat;
50 struct vattr *vap = &vat;
51 int error;
52
53 if (fmode & FCREAT) {
54 ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
55 if ((fmode & FEXCL) == 0)
56 ndp->ni_nameiop |= FOLLOW;
57 if (error = namei(ndp))
58 return (error);
59 if (ndp->ni_vp == NULL) {
3ee1461b 60 VATTR_NULL(vap);
eb668bc6
KM
61 vap->va_type = VREG;
62 vap->va_mode = cmode;
63 if (error = VOP_CREATE(ndp, vap))
64 return (error);
65 fmode &= ~FTRUNC;
66 vp = ndp->ni_vp;
67 } else {
3f530a7b
KM
68 if (ndp->ni_dvp == ndp->ni_vp)
69 vrele(ndp->ni_dvp);
7341981c 70 else
3f530a7b
KM
71 vput(ndp->ni_dvp);
72 ndp->ni_dvp = NULL;
eb668bc6 73 vp = ndp->ni_vp;
eb668bc6
KM
74 if (fmode & FEXCL) {
75 error = EEXIST;
76 goto bad;
77 }
78 fmode &= ~FCREAT;
79 }
80 } else {
81 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
82 if (error = namei(ndp))
83 return (error);
84 vp = ndp->ni_vp;
85 }
86 if (vp->v_type == VSOCK) {
87 error = EOPNOTSUPP;
88 goto bad;
89 }
90 if ((fmode & FCREAT) == 0) {
91 if (fmode & FREAD) {
cd811e9a 92 if (error = VOP_ACCESS(vp, VREAD, ndp->ni_cred))
eb668bc6
KM
93 goto bad;
94 }
95 if (fmode & (FWRITE|FTRUNC)) {
eb668bc6
KM
96 if (vp->v_type == VDIR) {
97 error = EISDIR;
98 goto bad;
99 }
cd811e9a
KM
100 if ((error = vn_writechk(vp)) ||
101 (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
102 goto bad;
eb668bc6
KM
103 }
104 }
105 if (fmode & FTRUNC) {
3ee1461b 106 VATTR_NULL(vap);
eb668bc6
KM
107 vap->va_size = 0;
108 if (error = VOP_SETATTR(vp, vap, ndp->ni_cred))
109 goto bad;
110 }
111 VOP_UNLOCK(vp);
d099f49b
KM
112 error = VOP_OPEN(vp, fmode, ndp->ni_cred);
113 if (error)
114 vrele(vp);
115 return (error);
eb668bc6
KM
116
117bad:
118 vput(vp);
ccee3c59 119 return (error);
eb668bc6
KM
120}
121
122/*
cd811e9a
KM
123 * Check for write permissions on the specified vnode.
124 * The read-only status of the file system is checked.
125 * Also, prototype text segments cannot be written.
eb668bc6 126 */
cd811e9a 127vn_writechk(vp)
eb668bc6 128 register struct vnode *vp;
fc96c615 129{
fc96c615 130
cd811e9a
KM
131 /*
132 * Disallow write attempts on read-only file systems;
133 * unless the file is a socket or a block or character
134 * device resident on the file system.
135 */
54fb9dc2 136 if ((vp->v_mount->mnt_flag & MNT_RDONLY) && vp->v_type != VCHR &&
cd811e9a
KM
137 vp->v_type != VBLK && vp->v_type != VSOCK)
138 return (EROFS);
139 /*
140 * If there's shared text associated with
141 * the vnode, try to free it up once. If
142 * we fail, we can't allow writing.
143 */
144 if (vp->v_flag & VTEXT)
145 xrele(vp);
146 if (vp->v_flag & VTEXT)
147 return (ETXTBSY);
148 return (0);
eb668bc6
KM
149}
150
151/*
152 * Vnode version of rdwri() for calls on file systems.
153 */
154vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid)
155 enum uio_rw rw;
156 struct vnode *vp;
157 caddr_t base;
158 int len;
159 off_t offset;
160 enum uio_seg segflg;
161 int ioflg;
162 struct ucred *cred;
163 int *aresid;
164{
165 struct uio auio;
166 struct iovec aiov;
167 int error;
168
cde34f67
KM
169 if ((ioflg & IO_NODELOCKED) == 0)
170 VOP_LOCK(vp);
eb668bc6
KM
171 auio.uio_iov = &aiov;
172 auio.uio_iovcnt = 1;
173 aiov.iov_base = base;
174 aiov.iov_len = len;
175 auio.uio_resid = len;
176 auio.uio_offset = offset;
177 auio.uio_segflg = segflg;
178 auio.uio_rw = rw;
179 if (rw == UIO_READ)
cde34f67 180 error = VOP_READ(vp, &auio, ioflg, cred);
eb668bc6 181 else
cde34f67 182 error = VOP_WRITE(vp, &auio, ioflg, cred);
eb668bc6
KM
183 if (aresid)
184 *aresid = auio.uio_resid;
185 else
186 if (auio.uio_resid && error == 0)
187 error = EIO;
cde34f67
KM
188 if ((ioflg & IO_NODELOCKED) == 0)
189 VOP_UNLOCK(vp);
eb668bc6
KM
190 return (error);
191}
192
193vn_read(fp, uio, cred)
194 struct file *fp;
195 struct uio *uio;
196 struct ucred *cred;
197{
cde34f67
KM
198 register struct vnode *vp = (struct vnode *)fp->f_data;
199 int count, error;
eb668bc6 200
cde34f67
KM
201 VOP_LOCK(vp);
202 uio->uio_offset = fp->f_offset;
203 count = uio->uio_resid;
204 error = VOP_READ(vp, uio, (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred);
205 fp->f_offset += count - uio->uio_resid;
206 VOP_UNLOCK(vp);
207 return (error);
eb668bc6
KM
208}
209
210vn_write(fp, uio, cred)
211 struct file *fp;
212 struct uio *uio;
213 struct ucred *cred;
214{
215 register struct vnode *vp = (struct vnode *)fp->f_data;
cde34f67 216 int count, error, ioflag = 0;
eb668bc6
KM
217
218 if (vp->v_type == VREG && (fp->f_flag & FAPPEND))
219 ioflag |= IO_APPEND;
220 if (fp->f_flag & FNDELAY)
221 ioflag |= IO_NDELAY;
cde34f67
KM
222 VOP_LOCK(vp);
223 uio->uio_offset = fp->f_offset;
224 count = uio->uio_resid;
225 error = VOP_WRITE(vp, uio, ioflag, cred);
226 if (ioflag & IO_APPEND)
227 fp->f_offset = uio->uio_offset;
228 else
229 fp->f_offset += count - uio->uio_resid;
230 VOP_UNLOCK(vp);
231 return (error);
eb668bc6
KM
232}
233
234/*
235 * Get stat info for a vnode.
236 */
237vn_stat(vp, sb)
238 struct vnode *vp;
239 register struct stat *sb;
240{
241 struct vattr vattr;
242 register struct vattr *vap;
243 int error;
244 u_short mode;
245
246 vap = &vattr;
247 error = VOP_GETATTR(vp, vap, u.u_cred);
248 if (error)
249 return (error);
250 /*
251 * Copy from vattr table
252 */
253 sb->st_dev = vap->va_fsid;
254 sb->st_ino = vap->va_fileid;
255 mode = vap->va_mode;
256 switch (vp->v_type) {
257 case VREG:
2e3baa4b 258 mode |= S_IFREG;
eb668bc6
KM
259 break;
260 case VDIR:
2e3baa4b 261 mode |= S_IFDIR;
eb668bc6
KM
262 break;
263 case VBLK:
2e3baa4b 264 mode |= S_IFBLK;
eb668bc6
KM
265 break;
266 case VCHR:
2e3baa4b 267 mode |= S_IFCHR;
eb668bc6
KM
268 break;
269 case VLNK:
2e3baa4b 270 mode |= S_IFLNK;
eb668bc6
KM
271 break;
272 case VSOCK:
2e3baa4b 273 mode |= S_IFSOCK;
eb668bc6 274 break;
0099f400
KM
275 case VFIFO:
276 mode |= S_IFIFO;
277 break;
eb668bc6
KM
278 default:
279 return (EBADF);
280 };
281 sb->st_mode = mode;
282 sb->st_nlink = vap->va_nlink;
283 sb->st_uid = vap->va_uid;
284 sb->st_gid = vap->va_gid;
285 sb->st_rdev = vap->va_rdev;
286 sb->st_size = vap->va_size;
287 sb->st_atime = vap->va_atime.tv_sec;
288 sb->st_spare1 = 0;
289 sb->st_mtime = vap->va_mtime.tv_sec;
290 sb->st_spare2 = 0;
291 sb->st_ctime = vap->va_ctime.tv_sec;
292 sb->st_spare3 = 0;
293 sb->st_blksize = vap->va_blocksize;
2ff0b8da
KM
294 sb->st_flags = vap->va_flags;
295 sb->st_gen = vap->va_gen;
366f2ef0 296 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
eb668bc6
KM
297 return (0);
298}
299
300/*
301 * Vnode ioctl call
302 */
303vn_ioctl(fp, com, data)
304 struct file *fp;
305 int com;
306 caddr_t data;
307{
308 register struct vnode *vp = ((struct vnode *)fp->f_data);
309 struct vattr vattr;
310 int error;
311
312 switch (vp->v_type) {
313
314 case VREG:
315 case VDIR:
316 if (com == FIONREAD) {
317 if (error = VOP_GETATTR(vp, &vattr, u.u_cred))
318 return (error);
319 *(off_t *)data = vattr.va_size - fp->f_offset;
320 return (0);
321 }
322 if (com == FIONBIO || com == FIOASYNC) /* XXX */
323 return (0); /* XXX */
324 /* fall into ... */
325
326 default:
327 return (ENOTTY);
328
0099f400 329 case VFIFO:
eb668bc6
KM
330 case VCHR:
331 case VBLK:
1665da5a
MT
332 error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred);
333 if (error == 0 && com == TIOCSCTTY) {
334 u.u_procp->p_session->s_ttyvp = vp;
335 VREF(vp);
336 }
337 return (error);
fc96c615 338 }
eb668bc6
KM
339}
340
341/*
342 * Vnode select call
343 */
344vn_select(fp, which)
345 struct file *fp;
346 int which;
347{
ccee3c59 348 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
0099f400 349 u.u_cred));
eb668bc6
KM
350}
351
352/*
353 * Vnode close call
354 */
355vn_close(fp)
356 register struct file *fp;
357{
358 struct vnode *vp = ((struct vnode *)fp->f_data);
359 int error;
360
361 if (fp->f_flag & (FSHLOCK|FEXLOCK))
362 vn_unlock(fp, FSHLOCK|FEXLOCK);
40123f2c 363 /*
eb668bc6
KM
364 * Must delete vnode reference from this file entry
365 * before VOP_CLOSE, so that only other references
366 * will prevent close.
40123f2c 367 */
eb668bc6
KM
368 fp->f_data = (caddr_t) 0;
369 error = VOP_CLOSE(vp, fp->f_flag, u.u_cred);
370 vrele(vp);
371 return (error);
372}
373
374/*
375 * Place an advisory lock on a vnode.
376 * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries
377 */
378vn_lock(fp, cmd)
379 register struct file *fp;
380 int cmd;
381{
382 register int priority = PLOCK;
383 register struct vnode *vp = (struct vnode *)fp->f_data;
ccee3c59
MK
384 int error = 0;
385 static char lockstr[] = "flock";
eb668bc6
KM
386
387 if ((cmd & LOCK_EX) == 0)
388 priority += 4;
ccee3c59
MK
389 priority |= PCATCH;
390
40123f2c 391 /*
eb668bc6
KM
392 * If there's a exclusive lock currently applied
393 * to the file, then we've gotta wait for the
394 * lock with everyone else.
40123f2c 395 */
eb668bc6
KM
396again:
397 while (vp->v_flag & VEXLOCK) {
398 /*
399 * If we're holding an exclusive
400 * lock, then release it.
401 */
402 if (fp->f_flag & FEXLOCK) {
403 vn_unlock(fp, FEXLOCK);
404 continue;
405 }
406 if (cmd & LOCK_NB)
407 return (EWOULDBLOCK);
408 vp->v_flag |= VLWAIT;
ccee3c59
MK
409 if (error = tsleep((caddr_t)&vp->v_exlockc, priority,
410 lockstr, 0))
411 return (error);
fc96c615 412 }
ccee3c59 413 if (error = 0 && (cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) {
eb668bc6
KM
414 /*
415 * Must wait for any shared locks to finish
416 * before we try to apply a exclusive lock.
417 *
418 * If we're holding a shared
419 * lock, then release it.
420 */
421 if (fp->f_flag & FSHLOCK) {
422 vn_unlock(fp, FSHLOCK);
423 goto again;
424 }
425 if (cmd & LOCK_NB)
426 return (EWOULDBLOCK);
427 vp->v_flag |= VLWAIT;
ccee3c59
MK
428 if (error = tsleep((caddr_t)&vp->v_shlockc, PLOCK | PCATCH,
429 lockstr, 0) == 0)
430 return (error);
eb668bc6
KM
431 }
432 if (fp->f_flag & FEXLOCK)
433 panic("vn_lock");
434 if (cmd & LOCK_EX) {
435 cmd &= ~LOCK_SH;
436 vp->v_exlockc++;
437 vp->v_flag |= VEXLOCK;
438 fp->f_flag |= FEXLOCK;
439 }
440 if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) {
441 vp->v_shlockc++;
442 vp->v_flag |= VSHLOCK;
443 fp->f_flag |= FSHLOCK;
849cbd39 444 }
eb668bc6 445 return (0);
fc96c615
BJ
446}
447
448/*
eb668bc6 449 * Unlock a file.
fc96c615 450 */
eb668bc6
KM
451vn_unlock(fp, kind)
452 register struct file *fp;
453 int kind;
fc96c615 454{
eb668bc6
KM
455 register struct vnode *vp = (struct vnode *)fp->f_data;
456 int flags;
fc96c615 457
eb668bc6
KM
458 kind &= fp->f_flag;
459 if (vp == NULL || kind == 0)
460 return;
461 flags = vp->v_flag;
462 if (kind & FSHLOCK) {
463 if ((flags & VSHLOCK) == 0)
464 panic("vn_unlock: SHLOCK");
465 if (--vp->v_shlockc == 0) {
466 vp->v_flag &= ~VSHLOCK;
467 if (flags & VLWAIT)
468 wakeup((caddr_t)&vp->v_shlockc);
469 }
470 fp->f_flag &= ~FSHLOCK;
471 }
472 if (kind & FEXLOCK) {
473 if ((flags & VEXLOCK) == 0)
474 panic("vn_unlock: EXLOCK");
475 if (--vp->v_exlockc == 0) {
476 vp->v_flag &= ~(VEXLOCK|VLWAIT);
477 if (flags & VLWAIT)
478 wakeup((caddr_t)&vp->v_exlockc);
479 }
480 fp->f_flag &= ~FEXLOCK;
fc96c615 481 }
eb668bc6
KM
482}
483
484/*
485 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
486 * - look up fsid in mount list (if not found ret error)
487 * - get vp by calling VFS_FHTOVP() macro
488 * - if lockflag lock it with VOP_LOCK()
489 */
490vn_fhtovp(fhp, lockflag, vpp)
491 fhandle_t *fhp;
492 int lockflag;
493 struct vnode **vpp;
494{
495 register struct mount *mp;
eb668bc6
KM
496
497 if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
498 return (ESTALE);
a2f658f9
KM
499 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
500 return (ESTALE);
501 if (!lockflag)
502 VOP_UNLOCK(*vpp);
eb668bc6
KM
503 return (0);
504}
505
eb668bc6
KM
506/*
507 * Noop
508 */
509vfs_noop()
510{
511
512 return (ENXIO);
513}
514
515/*
516 * Null op
517 */
518vfs_nullop()
519{
520
521 return (0);
fc96c615 522}