must lock before calling READ/WRITE
[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 *
1665da5a 17 * @(#)vfs_vnops.c 7.11 (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
174 auio.uio_iov = &aiov;
175 auio.uio_iovcnt = 1;
176 aiov.iov_base = base;
177 aiov.iov_len = len;
178 auio.uio_resid = len;
179 auio.uio_offset = offset;
180 auio.uio_segflg = segflg;
181 auio.uio_rw = rw;
182 if (rw == UIO_READ)
183 error = VOP_READ(vp, &auio, &offset, ioflg, cred);
184 else
185 error = VOP_WRITE(vp, &auio, &offset, ioflg, cred);
186 if (aresid)
187 *aresid = auio.uio_resid;
188 else
189 if (auio.uio_resid && error == 0)
190 error = EIO;
191 return (error);
192}
193
194vn_read(fp, uio, cred)
195 struct file *fp;
196 struct uio *uio;
197 struct ucred *cred;
198{
199
200 return (VOP_READ((struct vnode *)fp->f_data, uio, &(fp->f_offset),
201 (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred));
202}
203
204vn_write(fp, uio, cred)
205 struct file *fp;
206 struct uio *uio;
207 struct ucred *cred;
208{
209 register struct vnode *vp = (struct vnode *)fp->f_data;
210 int ioflag = 0;
211
212 if (vp->v_type == VREG && (fp->f_flag & FAPPEND))
213 ioflag |= IO_APPEND;
214 if (fp->f_flag & FNDELAY)
215 ioflag |= IO_NDELAY;
216 return (VOP_WRITE(vp, uio, &(fp->f_offset), ioflag, cred));
217}
218
219/*
220 * Get stat info for a vnode.
221 */
222vn_stat(vp, sb)
223 struct vnode *vp;
224 register struct stat *sb;
225{
226 struct vattr vattr;
227 register struct vattr *vap;
228 int error;
229 u_short mode;
230
231 vap = &vattr;
232 error = VOP_GETATTR(vp, vap, u.u_cred);
233 if (error)
234 return (error);
235 /*
236 * Copy from vattr table
237 */
238 sb->st_dev = vap->va_fsid;
239 sb->st_ino = vap->va_fileid;
240 mode = vap->va_mode;
241 switch (vp->v_type) {
242 case VREG:
2e3baa4b 243 mode |= S_IFREG;
eb668bc6
KM
244 break;
245 case VDIR:
2e3baa4b 246 mode |= S_IFDIR;
eb668bc6
KM
247 break;
248 case VBLK:
2e3baa4b 249 mode |= S_IFBLK;
eb668bc6
KM
250 break;
251 case VCHR:
2e3baa4b 252 mode |= S_IFCHR;
eb668bc6
KM
253 break;
254 case VLNK:
2e3baa4b 255 mode |= S_IFLNK;
eb668bc6
KM
256 break;
257 case VSOCK:
2e3baa4b 258 mode |= S_IFSOCK;
eb668bc6
KM
259 break;
260 default:
261 return (EBADF);
262 };
263 sb->st_mode = mode;
264 sb->st_nlink = vap->va_nlink;
265 sb->st_uid = vap->va_uid;
266 sb->st_gid = vap->va_gid;
267 sb->st_rdev = vap->va_rdev;
268 sb->st_size = vap->va_size;
269 sb->st_atime = vap->va_atime.tv_sec;
270 sb->st_spare1 = 0;
271 sb->st_mtime = vap->va_mtime.tv_sec;
272 sb->st_spare2 = 0;
273 sb->st_ctime = vap->va_ctime.tv_sec;
274 sb->st_spare3 = 0;
275 sb->st_blksize = vap->va_blocksize;
2ff0b8da
KM
276 sb->st_flags = vap->va_flags;
277 sb->st_gen = vap->va_gen;
366f2ef0 278 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
eb668bc6
KM
279 return (0);
280}
281
282/*
283 * Vnode ioctl call
284 */
285vn_ioctl(fp, com, data)
286 struct file *fp;
287 int com;
288 caddr_t data;
289{
290 register struct vnode *vp = ((struct vnode *)fp->f_data);
291 struct vattr vattr;
292 int error;
293
294 switch (vp->v_type) {
295
296 case VREG:
297 case VDIR:
298 if (com == FIONREAD) {
299 if (error = VOP_GETATTR(vp, &vattr, u.u_cred))
300 return (error);
301 *(off_t *)data = vattr.va_size - fp->f_offset;
302 return (0);
303 }
304 if (com == FIONBIO || com == FIOASYNC) /* XXX */
305 return (0); /* XXX */
306 /* fall into ... */
307
308 default:
309 return (ENOTTY);
310
311 case VCHR:
312 case VBLK:
313 u.u_r.r_val1 = 0;
314 if (setjmp(&u.u_qsave)) {
315 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
316 return(EINTR);
317 u.u_eosys = RESTARTSYS;
318 return (0);
fc96c615 319 }
1665da5a
MT
320 error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred);
321 if (error == 0 && com == TIOCSCTTY) {
322 u.u_procp->p_session->s_ttyvp = vp;
323 VREF(vp);
324 }
325 return (error);
fc96c615 326 }
eb668bc6
KM
327}
328
329/*
330 * Vnode select call
331 */
332vn_select(fp, which)
333 struct file *fp;
334 int which;
335{
336 return(VOP_SELECT(((struct vnode *)fp->f_data), which, u.u_cred));
337}
338
339/*
340 * Vnode close call
341 */
342vn_close(fp)
343 register struct file *fp;
344{
345 struct vnode *vp = ((struct vnode *)fp->f_data);
346 int error;
347
348 if (fp->f_flag & (FSHLOCK|FEXLOCK))
349 vn_unlock(fp, FSHLOCK|FEXLOCK);
40123f2c 350 /*
eb668bc6
KM
351 * Must delete vnode reference from this file entry
352 * before VOP_CLOSE, so that only other references
353 * will prevent close.
40123f2c 354 */
eb668bc6
KM
355 fp->f_data = (caddr_t) 0;
356 error = VOP_CLOSE(vp, fp->f_flag, u.u_cred);
357 vrele(vp);
358 return (error);
359}
360
361/*
362 * Place an advisory lock on a vnode.
363 * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries
364 */
365vn_lock(fp, cmd)
366 register struct file *fp;
367 int cmd;
368{
369 register int priority = PLOCK;
370 register struct vnode *vp = (struct vnode *)fp->f_data;
371
372 if ((cmd & LOCK_EX) == 0)
373 priority += 4;
374 if (setjmp(&u.u_qsave)) {
375 if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
376 return(EINTR);
377 u.u_eosys = RESTARTSYS;
fdd90ee3 378 return (0);
eb668bc6 379 }
40123f2c 380 /*
eb668bc6
KM
381 * If there's a exclusive lock currently applied
382 * to the file, then we've gotta wait for the
383 * lock with everyone else.
40123f2c 384 */
eb668bc6
KM
385again:
386 while (vp->v_flag & VEXLOCK) {
387 /*
388 * If we're holding an exclusive
389 * lock, then release it.
390 */
391 if (fp->f_flag & FEXLOCK) {
392 vn_unlock(fp, FEXLOCK);
393 continue;
394 }
395 if (cmd & LOCK_NB)
396 return (EWOULDBLOCK);
397 vp->v_flag |= VLWAIT;
398 sleep((caddr_t)&vp->v_exlockc, priority);
fc96c615 399 }
eb668bc6
KM
400 if ((cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) {
401 /*
402 * Must wait for any shared locks to finish
403 * before we try to apply a exclusive lock.
404 *
405 * If we're holding a shared
406 * lock, then release it.
407 */
408 if (fp->f_flag & FSHLOCK) {
409 vn_unlock(fp, FSHLOCK);
410 goto again;
411 }
412 if (cmd & LOCK_NB)
413 return (EWOULDBLOCK);
414 vp->v_flag |= VLWAIT;
415 sleep((caddr_t)&vp->v_shlockc, PLOCK);
416 goto again;
417 }
418 if (fp->f_flag & FEXLOCK)
419 panic("vn_lock");
420 if (cmd & LOCK_EX) {
421 cmd &= ~LOCK_SH;
422 vp->v_exlockc++;
423 vp->v_flag |= VEXLOCK;
424 fp->f_flag |= FEXLOCK;
425 }
426 if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) {
427 vp->v_shlockc++;
428 vp->v_flag |= VSHLOCK;
429 fp->f_flag |= FSHLOCK;
849cbd39 430 }
eb668bc6 431 return (0);
fc96c615
BJ
432}
433
434/*
eb668bc6 435 * Unlock a file.
fc96c615 436 */
eb668bc6
KM
437vn_unlock(fp, kind)
438 register struct file *fp;
439 int kind;
fc96c615 440{
eb668bc6
KM
441 register struct vnode *vp = (struct vnode *)fp->f_data;
442 int flags;
fc96c615 443
eb668bc6
KM
444 kind &= fp->f_flag;
445 if (vp == NULL || kind == 0)
446 return;
447 flags = vp->v_flag;
448 if (kind & FSHLOCK) {
449 if ((flags & VSHLOCK) == 0)
450 panic("vn_unlock: SHLOCK");
451 if (--vp->v_shlockc == 0) {
452 vp->v_flag &= ~VSHLOCK;
453 if (flags & VLWAIT)
454 wakeup((caddr_t)&vp->v_shlockc);
455 }
456 fp->f_flag &= ~FSHLOCK;
457 }
458 if (kind & FEXLOCK) {
459 if ((flags & VEXLOCK) == 0)
460 panic("vn_unlock: EXLOCK");
461 if (--vp->v_exlockc == 0) {
462 vp->v_flag &= ~(VEXLOCK|VLWAIT);
463 if (flags & VLWAIT)
464 wakeup((caddr_t)&vp->v_exlockc);
465 }
466 fp->f_flag &= ~FEXLOCK;
fc96c615 467 }
eb668bc6
KM
468}
469
470/*
471 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
472 * - look up fsid in mount list (if not found ret error)
473 * - get vp by calling VFS_FHTOVP() macro
474 * - if lockflag lock it with VOP_LOCK()
475 */
476vn_fhtovp(fhp, lockflag, vpp)
477 fhandle_t *fhp;
478 int lockflag;
479 struct vnode **vpp;
480{
481 register struct mount *mp;
eb668bc6
KM
482
483 if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
484 return (ESTALE);
a2f658f9
KM
485 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
486 return (ESTALE);
487 if (!lockflag)
488 VOP_UNLOCK(*vpp);
eb668bc6
KM
489 return (0);
490}
491
eb668bc6
KM
492/*
493 * Noop
494 */
495vfs_noop()
496{
497
498 return (ENXIO);
499}
500
501/*
502 * Null op
503 */
504vfs_nullop()
505{
506
507 return (0);
fc96c615 508}