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