add memory filesystem initialization
[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 *
366f2ef0 17 * @(#)vfs_vnops.c 7.9 (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"
33#include "../ufs/inode.h"
34#include "../ufs/fs.h"
35#include "../ufs/quota.h"
36#include "ioctl.h"
37#include "tty.h"
fc96c615 38
eb668bc6
KM
39int vn_read(), vn_write(), vn_ioctl(), vn_select(), vn_close();
40struct fileops vnops =
41 { vn_read, vn_write, vn_ioctl, vn_select, vn_close };
d301d150 42
fc96c615 43/*
eb668bc6
KM
44 * Common code for vnode open operations.
45 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
fc96c615 46 */
eb668bc6
KM
47vn_open(ndp, fmode, cmode)
48 register struct nameidata *ndp;
49 int fmode, cmode;
50{
51 register struct vnode *vp;
52 struct vattr vat;
53 struct vattr *vap = &vat;
54 int error;
55
56 if (fmode & FCREAT) {
57 ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
58 if ((fmode & FEXCL) == 0)
59 ndp->ni_nameiop |= FOLLOW;
60 if (error = namei(ndp))
61 return (error);
62 if (ndp->ni_vp == NULL) {
63 vattr_null(vap);
64 vap->va_type = VREG;
65 vap->va_mode = cmode;
66 if (error = VOP_CREATE(ndp, vap))
67 return (error);
68 fmode &= ~FTRUNC;
69 vp = ndp->ni_vp;
70 } else {
71 vp = ndp->ni_vp;
72 ndp->ni_vp = 0;
73 VOP_ABORTOP(ndp);
74 ndp->ni_vp = vp;
75 if (fmode & FEXCL) {
76 error = EEXIST;
77 goto bad;
78 }
79 fmode &= ~FCREAT;
80 }
81 } else {
82 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
83 if (error = namei(ndp))
84 return (error);
85 vp = ndp->ni_vp;
86 }
87 if (vp->v_type == VSOCK) {
88 error = EOPNOTSUPP;
89 goto bad;
90 }
91 if ((fmode & FCREAT) == 0) {
92 if (fmode & FREAD) {
cd811e9a 93 if (error = VOP_ACCESS(vp, VREAD, ndp->ni_cred))
eb668bc6
KM
94 goto bad;
95 }
96 if (fmode & (FWRITE|FTRUNC)) {
eb668bc6
KM
97 if (vp->v_type == VDIR) {
98 error = EISDIR;
99 goto bad;
100 }
cd811e9a
KM
101 if ((error = vn_writechk(vp)) ||
102 (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
103 goto bad;
eb668bc6
KM
104 }
105 }
106 if (fmode & FTRUNC) {
107 vattr_null(vap);
108 vap->va_size = 0;
109 if (error = VOP_SETATTR(vp, vap, ndp->ni_cred))
110 goto bad;
111 }
112 VOP_UNLOCK(vp);
113 if (setjmp(&u.u_qsave)) {
114 if (error == 0)
115 error = EINTR;
116 return (error);
117 }
d099f49b
KM
118 error = VOP_OPEN(vp, fmode, ndp->ni_cred);
119 if (error)
120 vrele(vp);
121 return (error);
eb668bc6
KM
122
123bad:
124 vput(vp);
125 return(error);
126}
127
128/*
cd811e9a
KM
129 * Check for write permissions on the specified vnode.
130 * The read-only status of the file system is checked.
131 * Also, prototype text segments cannot be written.
eb668bc6 132 */
cd811e9a 133vn_writechk(vp)
eb668bc6 134 register struct vnode *vp;
fc96c615 135{
fc96c615 136
cd811e9a
KM
137 /*
138 * Disallow write attempts on read-only file systems;
139 * unless the file is a socket or a block or character
140 * device resident on the file system.
141 */
142 if ((vp->v_mount->m_flag & M_RDONLY) && vp->v_type != VCHR &&
143 vp->v_type != VBLK && vp->v_type != VSOCK)
144 return (EROFS);
145 /*
146 * If there's shared text associated with
147 * the vnode, try to free it up once. If
148 * we fail, we can't allow writing.
149 */
150 if (vp->v_flag & VTEXT)
151 xrele(vp);
152 if (vp->v_flag & VTEXT)
153 return (ETXTBSY);
154 return (0);
eb668bc6
KM
155}
156
157/*
158 * Vnode version of rdwri() for calls on file systems.
159 */
160vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid)
161 enum uio_rw rw;
162 struct vnode *vp;
163 caddr_t base;
164 int len;
165 off_t offset;
166 enum uio_seg segflg;
167 int ioflg;
168 struct ucred *cred;
169 int *aresid;
170{
171 struct uio auio;
172 struct iovec aiov;
173 int error;
174
175 auio.uio_iov = &aiov;
176 auio.uio_iovcnt = 1;
177 aiov.iov_base = base;
178 aiov.iov_len = len;
179 auio.uio_resid = len;
180 auio.uio_offset = offset;
181 auio.uio_segflg = segflg;
182 auio.uio_rw = rw;
183 if (rw == UIO_READ)
184 error = VOP_READ(vp, &auio, &offset, ioflg, cred);
185 else
186 error = VOP_WRITE(vp, &auio, &offset, ioflg, cred);
187 if (aresid)
188 *aresid = auio.uio_resid;
189 else
190 if (auio.uio_resid && error == 0)
191 error = EIO;
192 return (error);
193}
194
195vn_read(fp, uio, cred)
196 struct file *fp;
197 struct uio *uio;
198 struct ucred *cred;
199{
200
201 return (VOP_READ((struct vnode *)fp->f_data, uio, &(fp->f_offset),
202 (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred));
203}
204
205vn_write(fp, uio, cred)
206 struct file *fp;
207 struct uio *uio;
208 struct ucred *cred;
209{
210 register struct vnode *vp = (struct vnode *)fp->f_data;
211 int ioflag = 0;
212
213 if (vp->v_type == VREG && (fp->f_flag & FAPPEND))
214 ioflag |= IO_APPEND;
215 if (fp->f_flag & FNDELAY)
216 ioflag |= IO_NDELAY;
217 return (VOP_WRITE(vp, uio, &(fp->f_offset), ioflag, cred));
218}
219
220/*
221 * Get stat info for a vnode.
222 */
223vn_stat(vp, sb)
224 struct vnode *vp;
225 register struct stat *sb;
226{
227 struct vattr vattr;
228 register struct vattr *vap;
229 int error;
230 u_short mode;
231
232 vap = &vattr;
233 error = VOP_GETATTR(vp, vap, u.u_cred);
234 if (error)
235 return (error);
236 /*
237 * Copy from vattr table
238 */
239 sb->st_dev = vap->va_fsid;
240 sb->st_ino = vap->va_fileid;
241 mode = vap->va_mode;
242 switch (vp->v_type) {
243 case VREG:
244 mode |= IFREG;
245 break;
246 case VDIR:
247 mode |= IFDIR;
248 break;
249 case VBLK:
250 mode |= IFBLK;
251 break;
252 case VCHR:
253 mode |= IFCHR;
254 break;
255 case VLNK:
256 mode |= IFLNK;
257 break;
258 case VSOCK:
259 mode |= IFSOCK;
260 break;
261 default:
262 return (EBADF);
263 };
264 sb->st_mode = mode;
265 sb->st_nlink = vap->va_nlink;
266 sb->st_uid = vap->va_uid;
267 sb->st_gid = vap->va_gid;
268 sb->st_rdev = vap->va_rdev;
269 sb->st_size = vap->va_size;
270 sb->st_atime = vap->va_atime.tv_sec;
271 sb->st_spare1 = 0;
272 sb->st_mtime = vap->va_mtime.tv_sec;
273 sb->st_spare2 = 0;
274 sb->st_ctime = vap->va_ctime.tv_sec;
275 sb->st_spare3 = 0;
276 sb->st_blksize = vap->va_blocksize;
2ff0b8da
KM
277 sb->st_flags = vap->va_flags;
278 sb->st_gen = vap->va_gen;
366f2ef0 279 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
eb668bc6
KM
280 return (0);
281}
282
283/*
284 * Vnode ioctl call
285 */
286vn_ioctl(fp, com, data)
287 struct file *fp;
288 int com;
289 caddr_t data;
290{
291 register struct vnode *vp = ((struct vnode *)fp->f_data);
292 struct vattr vattr;
293 int error;
294
295 switch (vp->v_type) {
296
297 case VREG:
298 case VDIR:
299 if (com == FIONREAD) {
300 if (error = VOP_GETATTR(vp, &vattr, u.u_cred))
301 return (error);
302 *(off_t *)data = vattr.va_size - fp->f_offset;
303 return (0);
304 }
305 if (com == FIONBIO || com == FIOASYNC) /* XXX */
306 return (0); /* XXX */
307 /* fall into ... */
308
309 default:
310 return (ENOTTY);
311
312 case VCHR:
313 case VBLK:
314 u.u_r.r_val1 = 0;
315 if (setjmp(&u.u_qsave)) {
316 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
317 return(EINTR);
318 u.u_eosys = RESTARTSYS;
319 return (0);
fc96c615 320 }
eb668bc6 321 return (VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred));
fc96c615 322 }
eb668bc6
KM
323}
324
325/*
326 * Vnode select call
327 */
328vn_select(fp, which)
329 struct file *fp;
330 int which;
331{
332 return(VOP_SELECT(((struct vnode *)fp->f_data), which, u.u_cred));
333}
334
335/*
336 * Vnode close call
337 */
338vn_close(fp)
339 register struct file *fp;
340{
341 struct vnode *vp = ((struct vnode *)fp->f_data);
342 int error;
343
344 if (fp->f_flag & (FSHLOCK|FEXLOCK))
345 vn_unlock(fp, FSHLOCK|FEXLOCK);
40123f2c 346 /*
eb668bc6
KM
347 * Must delete vnode reference from this file entry
348 * before VOP_CLOSE, so that only other references
349 * will prevent close.
40123f2c 350 */
eb668bc6
KM
351 fp->f_data = (caddr_t) 0;
352 error = VOP_CLOSE(vp, fp->f_flag, u.u_cred);
353 vrele(vp);
354 return (error);
355}
356
357/*
358 * Place an advisory lock on a vnode.
359 * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries
360 */
361vn_lock(fp, cmd)
362 register struct file *fp;
363 int cmd;
364{
365 register int priority = PLOCK;
366 register struct vnode *vp = (struct vnode *)fp->f_data;
367
368 if ((cmd & LOCK_EX) == 0)
369 priority += 4;
370 if (setjmp(&u.u_qsave)) {
371 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
372 return(EINTR);
373 u.u_eosys = RESTARTSYS;
fdd90ee3 374 return (0);
eb668bc6 375 }
40123f2c 376 /*
eb668bc6
KM
377 * If there's a exclusive lock currently applied
378 * to the file, then we've gotta wait for the
379 * lock with everyone else.
40123f2c 380 */
eb668bc6
KM
381again:
382 while (vp->v_flag & VEXLOCK) {
383 /*
384 * If we're holding an exclusive
385 * lock, then release it.
386 */
387 if (fp->f_flag & FEXLOCK) {
388 vn_unlock(fp, FEXLOCK);
389 continue;
390 }
391 if (cmd & LOCK_NB)
392 return (EWOULDBLOCK);
393 vp->v_flag |= VLWAIT;
394 sleep((caddr_t)&vp->v_exlockc, priority);
fc96c615 395 }
eb668bc6
KM
396 if ((cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) {
397 /*
398 * Must wait for any shared locks to finish
399 * before we try to apply a exclusive lock.
400 *
401 * If we're holding a shared
402 * lock, then release it.
403 */
404 if (fp->f_flag & FSHLOCK) {
405 vn_unlock(fp, FSHLOCK);
406 goto again;
407 }
408 if (cmd & LOCK_NB)
409 return (EWOULDBLOCK);
410 vp->v_flag |= VLWAIT;
411 sleep((caddr_t)&vp->v_shlockc, PLOCK);
412 goto again;
413 }
414 if (fp->f_flag & FEXLOCK)
415 panic("vn_lock");
416 if (cmd & LOCK_EX) {
417 cmd &= ~LOCK_SH;
418 vp->v_exlockc++;
419 vp->v_flag |= VEXLOCK;
420 fp->f_flag |= FEXLOCK;
421 }
422 if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) {
423 vp->v_shlockc++;
424 vp->v_flag |= VSHLOCK;
425 fp->f_flag |= FSHLOCK;
849cbd39 426 }
eb668bc6 427 return (0);
fc96c615
BJ
428}
429
430/*
eb668bc6 431 * Unlock a file.
fc96c615 432 */
eb668bc6
KM
433vn_unlock(fp, kind)
434 register struct file *fp;
435 int kind;
fc96c615 436{
eb668bc6
KM
437 register struct vnode *vp = (struct vnode *)fp->f_data;
438 int flags;
fc96c615 439
eb668bc6
KM
440 kind &= fp->f_flag;
441 if (vp == NULL || kind == 0)
442 return;
443 flags = vp->v_flag;
444 if (kind & FSHLOCK) {
445 if ((flags & VSHLOCK) == 0)
446 panic("vn_unlock: SHLOCK");
447 if (--vp->v_shlockc == 0) {
448 vp->v_flag &= ~VSHLOCK;
449 if (flags & VLWAIT)
450 wakeup((caddr_t)&vp->v_shlockc);
451 }
452 fp->f_flag &= ~FSHLOCK;
453 }
454 if (kind & FEXLOCK) {
455 if ((flags & VEXLOCK) == 0)
456 panic("vn_unlock: EXLOCK");
457 if (--vp->v_exlockc == 0) {
458 vp->v_flag &= ~(VEXLOCK|VLWAIT);
459 if (flags & VLWAIT)
460 wakeup((caddr_t)&vp->v_exlockc);
461 }
462 fp->f_flag &= ~FEXLOCK;
fc96c615 463 }
eb668bc6
KM
464}
465
466/*
467 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
468 * - look up fsid in mount list (if not found ret error)
469 * - get vp by calling VFS_FHTOVP() macro
470 * - if lockflag lock it with VOP_LOCK()
471 */
472vn_fhtovp(fhp, lockflag, vpp)
473 fhandle_t *fhp;
474 int lockflag;
475 struct vnode **vpp;
476{
477 register struct mount *mp;
478 int error;
479
480 if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
481 return (ESTALE);
a2f658f9
KM
482 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
483 return (ESTALE);
484 if (!lockflag)
485 VOP_UNLOCK(*vpp);
eb668bc6
KM
486 return (0);
487}
488
489/*
490 * Revoke access the current tty by all processes.
491 * Used only by the super-user in init
492 * to give ``clean'' terminals at login.
493 */
494vhangup()
495{
496
497 if (u.u_error = suser(u.u_cred, &u.u_acflag))
498 return;
499 if (u.u_ttyp == NULL)
500 return;
501 forceclose(u.u_ttyd);
502 if ((u.u_ttyp->t_state) & TS_ISOPEN)
503 gsignal(u.u_ttyp->t_pgid, SIGHUP);
504 u.u_ttyp->t_session = 0;
505 u.u_ttyp->t_pgid = 0;
506}
507
508forceclose(dev)
509 dev_t dev;
510{
511 register struct file *fp;
512 register struct vnode *vp;
513
514 for (fp = file; fp < fileNFILE; fp++) {
515 if (fp->f_count == 0)
516 continue;
517 if (fp->f_type != DTYPE_VNODE)
518 continue;
519 vp = (struct vnode *)fp->f_data;
520 if (vp == 0)
521 continue;
522 if (vp->v_type != VCHR)
523 continue;
524 if (vp->v_rdev != dev)
525 continue;
526 fp->f_flag &= ~(FREAD|FWRITE);
527 }
528}
529
d099f49b
KM
530/*
531 * Vnode reference, just increment the count
532 */
533void vref(vp)
534 struct vnode *vp;
535{
536
537 vp->v_count++;
538}
539
eb668bc6
KM
540/*
541 * Vnode release, just decrement the count and call VOP_INACTIVE()
542 */
543void vrele(vp)
544 register struct vnode *vp;
545{
546
547 if (vp == NULL)
548 return;
549 vp->v_count--;
550 if (vp->v_count < 0)
551 printf("inode %d, bad ref count %d\n",
552 VTOI(vp)->i_number, vp->v_count);
553 if (vp->v_count == 0)
554 VOP_INACTIVE(vp);
555}
556
557/*
558 * vput(), just unlock and vrele()
559 */
560vput(vp)
561 register struct vnode *vp;
562{
563 VOP_UNLOCK(vp);
564 vrele(vp);
565}
566
567/*
568 * Noop
569 */
570vfs_noop()
571{
572
573 return (ENXIO);
574}
575
576/*
577 * Null op
578 */
579vfs_nullop()
580{
581
582 return (0);
fc96c615 583}