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