vfs_vnops.c revision 1.27 1 /* $NetBSD: vfs_vnops.c,v 1.27 1998/02/19 00:53:46 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)vfs_vnops.c 8.5 (Berkeley) 12/8/94
41 */
42
43 #include "fs_union.h"
44 #include "opt_uvm.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/file.h>
50 #include <sys/stat.h>
51 #include <sys/buf.h>
52 #include <sys/proc.h>
53 #include <sys/mount.h>
54 #include <sys/namei.h>
55 #include <sys/vnode.h>
56 #include <sys/ioctl.h>
57 #include <sys/tty.h>
58 #include <sys/poll.h>
59
60 #include <vm/vm.h>
61
62 #if defined(UVM)
63 #include <uvm/uvm_extern.h>
64 #endif
65
66 struct fileops vnops =
67 { vn_read, vn_write, vn_ioctl, vn_poll, vn_closefile };
68
69 /*
70 * Common code for vnode open operations.
71 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
72 */
73 int
74 vn_open(ndp, fmode, cmode)
75 register struct nameidata *ndp;
76 int fmode, cmode;
77 {
78 register struct vnode *vp;
79 register struct proc *p = ndp->ni_cnd.cn_proc;
80 register struct ucred *cred = p->p_ucred;
81 struct vattr va;
82 int error;
83
84 if (fmode & O_CREAT) {
85 ndp->ni_cnd.cn_nameiop = CREATE;
86 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
87 if ((fmode & O_EXCL) == 0)
88 ndp->ni_cnd.cn_flags |= FOLLOW;
89 if ((error = namei(ndp)) != 0)
90 return (error);
91 if (ndp->ni_vp == NULL) {
92 VATTR_NULL(&va);
93 va.va_type = VREG;
94 va.va_mode = cmode;
95 VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
96 error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
97 &ndp->ni_cnd, &va);
98 if (error)
99 return (error);
100 fmode &= ~O_TRUNC;
101 vp = ndp->ni_vp;
102 } else {
103 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
104 if (ndp->ni_dvp == ndp->ni_vp)
105 vrele(ndp->ni_dvp);
106 else
107 vput(ndp->ni_dvp);
108 ndp->ni_dvp = NULL;
109 vp = ndp->ni_vp;
110 if (fmode & O_EXCL) {
111 error = EEXIST;
112 goto bad;
113 }
114 fmode &= ~O_CREAT;
115 }
116 } else {
117 ndp->ni_cnd.cn_nameiop = LOOKUP;
118 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
119 if ((error = namei(ndp)) != 0)
120 return (error);
121 vp = ndp->ni_vp;
122 }
123 if (vp->v_type == VSOCK) {
124 error = EOPNOTSUPP;
125 goto bad;
126 }
127 if ((fmode & O_CREAT) == 0) {
128 if (fmode & FREAD) {
129 if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
130 goto bad;
131 }
132 if (fmode & (FWRITE | O_TRUNC)) {
133 if (vp->v_type == VDIR) {
134 error = EISDIR;
135 goto bad;
136 }
137 if ((error = vn_writechk(vp)) != 0 ||
138 (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
139 goto bad;
140 }
141 }
142 if (fmode & O_TRUNC) {
143 VOP_UNLOCK(vp); /* XXX */
144 VOP_LEASE(vp, p, cred, LEASE_WRITE);
145 VOP_LOCK(vp); /* XXX */
146 VATTR_NULL(&va);
147 va.va_size = 0;
148 if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
149 goto bad;
150 }
151 if ((error = VOP_OPEN(vp, fmode, cred, p)) != 0)
152 goto bad;
153 if (fmode & FWRITE)
154 vp->v_writecount++;
155 return (0);
156 bad:
157 vput(vp);
158 return (error);
159 }
160
161 /*
162 * Check for write permissions on the specified vnode.
163 * The read-only status of the file system is checked.
164 * Also, prototype text segments cannot be written.
165 */
166 int
167 vn_writechk(vp)
168 register struct vnode *vp;
169 {
170
171 /*
172 * Disallow write attempts on read-only file systems;
173 * unless the file is a socket or a block or character
174 * device resident on the file system.
175 */
176 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
177 switch (vp->v_type) {
178 case VREG: case VDIR: case VLNK:
179 return (EROFS);
180 case VNON: case VCHR: case VSOCK:
181 case VFIFO: case VBAD: case VBLK:
182 break;
183 }
184 }
185 /*
186 * If there's shared text associated with
187 * the vnode, try to free it up once. If
188 * we fail, we can't allow writing.
189 */
190 #if defined(UVM)
191 if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp))
192 return (ETXTBSY);
193 #else
194 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
195 return (ETXTBSY);
196 #endif
197 return (0);
198 }
199
200 /*
201 * Vnode close call
202 */
203 int
204 vn_close(vp, flags, cred, p)
205 register struct vnode *vp;
206 int flags;
207 struct ucred *cred;
208 struct proc *p;
209 {
210 int error;
211
212 if (flags & FWRITE)
213 vp->v_writecount--;
214 error = VOP_CLOSE(vp, flags, cred, p);
215 vrele(vp);
216 return (error);
217 }
218
219 /*
220 * Package up an I/O request on a vnode into a uio and do it.
221 */
222 int
223 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
224 enum uio_rw rw;
225 struct vnode *vp;
226 caddr_t base;
227 int len;
228 off_t offset;
229 enum uio_seg segflg;
230 int ioflg;
231 struct ucred *cred;
232 int *aresid;
233 struct proc *p;
234 {
235 struct uio auio;
236 struct iovec aiov;
237 int error;
238
239 if ((ioflg & IO_NODELOCKED) == 0)
240 VOP_LOCK(vp);
241 auio.uio_iov = &aiov;
242 auio.uio_iovcnt = 1;
243 aiov.iov_base = base;
244 aiov.iov_len = len;
245 auio.uio_resid = len;
246 auio.uio_offset = offset;
247 auio.uio_segflg = segflg;
248 auio.uio_rw = rw;
249 auio.uio_procp = p;
250 if (rw == UIO_READ) {
251 error = VOP_READ(vp, &auio, ioflg, cred);
252 } else {
253 error = VOP_WRITE(vp, &auio, ioflg, cred);
254 }
255 if (aresid)
256 *aresid = auio.uio_resid;
257 else
258 if (auio.uio_resid && error == 0)
259 error = EIO;
260 if ((ioflg & IO_NODELOCKED) == 0)
261 VOP_UNLOCK(vp);
262 return (error);
263 }
264
265 int
266 vn_readdir(fp, buf, segflg, count, done, p, cookies, ncookies)
267 struct file *fp;
268 char *buf;
269 int segflg, *done, ncookies;
270 u_int count;
271 struct proc *p;
272 off_t *cookies;
273 {
274 struct vnode *vp = (struct vnode *)fp->f_data;
275 struct iovec aiov;
276 struct uio auio;
277 int error, eofflag;
278
279 unionread:
280 if (vp->v_type != VDIR)
281 return (EINVAL);
282 aiov.iov_base = buf;
283 aiov.iov_len = count;
284 auio.uio_iov = &aiov;
285 auio.uio_iovcnt = 1;
286 auio.uio_rw = UIO_READ;
287 auio.uio_segflg = segflg;
288 auio.uio_procp = p;
289 auio.uio_resid = count;
290 VOP_LOCK(vp);
291 auio.uio_offset = fp->f_offset;
292 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (off_t *)cookies,
293 ncookies);
294 fp->f_offset = auio.uio_offset;
295 VOP_UNLOCK(vp);
296 if (error)
297 return (error);
298
299 #ifdef UNION
300 {
301 extern int (**union_vnodeop_p) __P((void *));
302 extern struct vnode *union_dircache __P((struct vnode *));
303
304 if (count == auio.uio_resid && (vp->v_op == union_vnodeop_p)) {
305 struct vnode *lvp;
306
307 lvp = union_dircache(vp);
308 if (lvp != NULLVP) {
309 struct vattr va;
310
311 /*
312 * If the directory is opaque,
313 * then don't show lower entries
314 */
315 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
316 if (va.va_flags & OPAQUE) {
317 vput(lvp);
318 lvp = NULL;
319 }
320 }
321
322 if (lvp != NULLVP) {
323 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
324 VOP_UNLOCK(lvp);
325
326 if (error) {
327 vrele(lvp);
328 return (error);
329 }
330 fp->f_data = (caddr_t) lvp;
331 fp->f_offset = 0;
332 error = vn_close(vp, FREAD, fp->f_cred, p);
333 if (error)
334 return (error);
335 vp = lvp;
336 goto unionread;
337 }
338 }
339 }
340 #endif /* UNION */
341
342 if (count == auio.uio_resid && (vp->v_flag & VROOT) &&
343 (vp->v_mount->mnt_flag & MNT_UNION)) {
344 struct vnode *tvp = vp;
345 vp = vp->v_mount->mnt_vnodecovered;
346 VREF(vp);
347 fp->f_data = (caddr_t) vp;
348 fp->f_offset = 0;
349 vrele(tvp);
350 goto unionread;
351 }
352 *done = count - auio.uio_resid;
353 return error;
354 }
355
356 /*
357 * File table vnode read routine.
358 */
359 int
360 vn_read(fp, uio, cred)
361 struct file *fp;
362 struct uio *uio;
363 struct ucred *cred;
364 {
365 register struct vnode *vp = (struct vnode *)fp->f_data;
366 int count, error;
367
368 VOP_LEASE(vp, uio->uio_procp, cred, LEASE_READ);
369 VOP_LOCK(vp);
370 uio->uio_offset = fp->f_offset;
371 count = uio->uio_resid;
372 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
373 cred);
374 fp->f_offset += count - uio->uio_resid;
375 VOP_UNLOCK(vp);
376 return (error);
377 }
378
379 /*
380 * File table vnode write routine.
381 */
382 int
383 vn_write(fp, uio, cred)
384 struct file *fp;
385 struct uio *uio;
386 struct ucred *cred;
387 {
388 register struct vnode *vp = (struct vnode *)fp->f_data;
389 int count, error, ioflag = IO_UNIT;
390
391 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
392 ioflag |= IO_APPEND;
393 if (fp->f_flag & FNONBLOCK)
394 ioflag |= IO_NDELAY;
395 if (fp->f_flag & FFSYNC ||
396 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
397 ioflag |= IO_SYNC;
398 VOP_LEASE(vp, uio->uio_procp, cred, LEASE_WRITE);
399 VOP_LOCK(vp);
400 uio->uio_offset = fp->f_offset;
401 count = uio->uio_resid;
402 error = VOP_WRITE(vp, uio, ioflag, cred);
403 if (ioflag & IO_APPEND)
404 fp->f_offset = uio->uio_offset;
405 else
406 fp->f_offset += count - uio->uio_resid;
407 VOP_UNLOCK(vp);
408 return (error);
409 }
410
411 /*
412 * File table vnode stat routine.
413 */
414 int
415 vn_stat(vp, sb, p)
416 struct vnode *vp;
417 register struct stat *sb;
418 struct proc *p;
419 {
420 struct vattr va;
421 int error;
422 u_short mode;
423
424 error = VOP_GETATTR(vp, &va, p->p_ucred, p);
425 if (error)
426 return (error);
427 /*
428 * Copy from vattr table
429 */
430 sb->st_dev = va.va_fsid;
431 sb->st_ino = va.va_fileid;
432 mode = va.va_mode;
433 switch (vp->v_type) {
434 case VREG:
435 mode |= S_IFREG;
436 break;
437 case VDIR:
438 mode |= S_IFDIR;
439 break;
440 case VBLK:
441 mode |= S_IFBLK;
442 break;
443 case VCHR:
444 mode |= S_IFCHR;
445 break;
446 case VLNK:
447 mode |= S_IFLNK;
448 break;
449 case VSOCK:
450 mode |= S_IFSOCK;
451 break;
452 case VFIFO:
453 mode |= S_IFIFO;
454 break;
455 default:
456 return (EBADF);
457 };
458 sb->st_mode = mode;
459 sb->st_nlink = va.va_nlink;
460 sb->st_uid = va.va_uid;
461 sb->st_gid = va.va_gid;
462 sb->st_rdev = va.va_rdev;
463 sb->st_size = va.va_size;
464 sb->st_atimespec = va.va_atime;
465 sb->st_mtimespec = va.va_mtime;
466 sb->st_ctimespec = va.va_ctime;
467 sb->st_blksize = va.va_blocksize;
468 sb->st_flags = va.va_flags;
469 sb->st_gen = 0;
470 sb->st_blocks = va.va_bytes / S_BLKSIZE;
471 return (0);
472 }
473
474 /*
475 * File table vnode ioctl routine.
476 */
477 int
478 vn_ioctl(fp, com, data, p)
479 struct file *fp;
480 u_long com;
481 caddr_t data;
482 struct proc *p;
483 {
484 register struct vnode *vp = ((struct vnode *)fp->f_data);
485 struct vattr vattr;
486 int error;
487
488 switch (vp->v_type) {
489
490 case VREG:
491 case VDIR:
492 if (com == FIONREAD) {
493 error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
494 if (error)
495 return (error);
496 *(int *)data = vattr.va_size - fp->f_offset;
497 return (0);
498 }
499 if (com == FIONBIO || com == FIOASYNC) /* XXX */
500 return (0); /* XXX */
501 /* fall into ... */
502
503 default:
504 return (ENOTTY);
505
506 case VFIFO:
507 case VCHR:
508 case VBLK:
509 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
510 if (error == 0 && com == TIOCSCTTY) {
511 if (p->p_session->s_ttyvp)
512 vrele(p->p_session->s_ttyvp);
513 p->p_session->s_ttyvp = vp;
514 VREF(vp);
515 }
516 return (error);
517 }
518 }
519
520 /*
521 * File table vnode poll routine.
522 */
523 int
524 vn_poll(fp, events, p)
525 struct file *fp;
526 int events;
527 struct proc *p;
528 {
529
530 return (VOP_POLL(((struct vnode *)fp->f_data), events, p));
531 }
532
533 /*
534 * File table vnode close routine.
535 */
536 int
537 vn_closefile(fp, p)
538 struct file *fp;
539 struct proc *p;
540 {
541
542 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
543 fp->f_cred, p));
544 }
545