clean up unexecuted code; lint
[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 *
54fb9dc2 17 * @(#)vfs_vnops.c 7.20 (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);
70 else if (ndp->ni_dvp != NULL)
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:
332 u.u_r.r_val1 = 0;
1665da5a
MT
333 error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred);
334 if (error == 0 && com == TIOCSCTTY) {
335 u.u_procp->p_session->s_ttyvp = vp;
336 VREF(vp);
337 }
338 return (error);
fc96c615 339 }
eb668bc6
KM
340}
341
342/*
343 * Vnode select call
344 */
345vn_select(fp, which)
346 struct file *fp;
347 int which;
348{
ccee3c59 349 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
0099f400 350 u.u_cred));
eb668bc6
KM
351}
352
353/*
354 * Vnode close call
355 */
356vn_close(fp)
357 register struct file *fp;
358{
359 struct vnode *vp = ((struct vnode *)fp->f_data);
360 int error;
361
362 if (fp->f_flag & (FSHLOCK|FEXLOCK))
363 vn_unlock(fp, FSHLOCK|FEXLOCK);
40123f2c 364 /*
eb668bc6
KM
365 * Must delete vnode reference from this file entry
366 * before VOP_CLOSE, so that only other references
367 * will prevent close.
40123f2c 368 */
eb668bc6
KM
369 fp->f_data = (caddr_t) 0;
370 error = VOP_CLOSE(vp, fp->f_flag, u.u_cred);
371 vrele(vp);
372 return (error);
373}
374
375/*
376 * Place an advisory lock on a vnode.
377 * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries
378 */
379vn_lock(fp, cmd)
380 register struct file *fp;
381 int cmd;
382{
383 register int priority = PLOCK;
384 register struct vnode *vp = (struct vnode *)fp->f_data;
ccee3c59
MK
385 int error = 0;
386 static char lockstr[] = "flock";
eb668bc6
KM
387
388 if ((cmd & LOCK_EX) == 0)
389 priority += 4;
ccee3c59
MK
390 priority |= PCATCH;
391
40123f2c 392 /*
eb668bc6
KM
393 * If there's a exclusive lock currently applied
394 * to the file, then we've gotta wait for the
395 * lock with everyone else.
40123f2c 396 */
eb668bc6
KM
397again:
398 while (vp->v_flag & VEXLOCK) {
399 /*
400 * If we're holding an exclusive
401 * lock, then release it.
402 */
403 if (fp->f_flag & FEXLOCK) {
404 vn_unlock(fp, FEXLOCK);
405 continue;
406 }
407 if (cmd & LOCK_NB)
408 return (EWOULDBLOCK);
409 vp->v_flag |= VLWAIT;
ccee3c59
MK
410 if (error = tsleep((caddr_t)&vp->v_exlockc, priority,
411 lockstr, 0))
412 return (error);
fc96c615 413 }
ccee3c59 414 if (error = 0 && (cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) {
eb668bc6
KM
415 /*
416 * Must wait for any shared locks to finish
417 * before we try to apply a exclusive lock.
418 *
419 * If we're holding a shared
420 * lock, then release it.
421 */
422 if (fp->f_flag & FSHLOCK) {
423 vn_unlock(fp, FSHLOCK);
424 goto again;
425 }
426 if (cmd & LOCK_NB)
427 return (EWOULDBLOCK);
428 vp->v_flag |= VLWAIT;
ccee3c59
MK
429 if (error = tsleep((caddr_t)&vp->v_shlockc, PLOCK | PCATCH,
430 lockstr, 0) == 0)
431 return (error);
eb668bc6
KM
432 }
433 if (fp->f_flag & FEXLOCK)
434 panic("vn_lock");
435 if (cmd & LOCK_EX) {
436 cmd &= ~LOCK_SH;
437 vp->v_exlockc++;
438 vp->v_flag |= VEXLOCK;
439 fp->f_flag |= FEXLOCK;
440 }
441 if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) {
442 vp->v_shlockc++;
443 vp->v_flag |= VSHLOCK;
444 fp->f_flag |= FSHLOCK;
849cbd39 445 }
eb668bc6 446 return (0);
fc96c615
BJ
447}
448
449/*
eb668bc6 450 * Unlock a file.
fc96c615 451 */
eb668bc6
KM
452vn_unlock(fp, kind)
453 register struct file *fp;
454 int kind;
fc96c615 455{
eb668bc6
KM
456 register struct vnode *vp = (struct vnode *)fp->f_data;
457 int flags;
fc96c615 458
eb668bc6
KM
459 kind &= fp->f_flag;
460 if (vp == NULL || kind == 0)
461 return;
462 flags = vp->v_flag;
463 if (kind & FSHLOCK) {
464 if ((flags & VSHLOCK) == 0)
465 panic("vn_unlock: SHLOCK");
466 if (--vp->v_shlockc == 0) {
467 vp->v_flag &= ~VSHLOCK;
468 if (flags & VLWAIT)
469 wakeup((caddr_t)&vp->v_shlockc);
470 }
471 fp->f_flag &= ~FSHLOCK;
472 }
473 if (kind & FEXLOCK) {
474 if ((flags & VEXLOCK) == 0)
475 panic("vn_unlock: EXLOCK");
476 if (--vp->v_exlockc == 0) {
477 vp->v_flag &= ~(VEXLOCK|VLWAIT);
478 if (flags & VLWAIT)
479 wakeup((caddr_t)&vp->v_exlockc);
480 }
481 fp->f_flag &= ~FEXLOCK;
fc96c615 482 }
eb668bc6
KM
483}
484
485/*
486 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
487 * - look up fsid in mount list (if not found ret error)
488 * - get vp by calling VFS_FHTOVP() macro
489 * - if lockflag lock it with VOP_LOCK()
490 */
491vn_fhtovp(fhp, lockflag, vpp)
492 fhandle_t *fhp;
493 int lockflag;
494 struct vnode **vpp;
495{
496 register struct mount *mp;
eb668bc6
KM
497
498 if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
499 return (ESTALE);
a2f658f9
KM
500 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
501 return (ESTALE);
502 if (!lockflag)
503 VOP_UNLOCK(*vpp);
eb668bc6
KM
504 return (0);
505}
506
eb668bc6
KM
507/*
508 * Noop
509 */
510vfs_noop()
511{
512
513 return (ENXIO);
514}
515
516/*
517 * Null op
518 */
519vfs_nullop()
520{
521
522 return (0);
fc96c615 523}