vfs_vnops.c revision 1.13 1 /* $NetBSD: vfs_vnops.c,v 1.13 1994/09/14 00:35:29 cgd 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.2 (Berkeley) 1/21/94
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/file.h>
47 #include <sys/stat.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/mount.h>
51 #include <sys/namei.h>
52 #include <sys/vnode.h>
53 #include <sys/ioctl.h>
54 #include <sys/tty.h>
55
56 #include <vm/vm.h>
57
58 struct fileops vnops =
59 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
60
61 /*
62 * Common code for vnode open operations.
63 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
64 */
65 vn_open(ndp, fmode, cmode)
66 register struct nameidata *ndp;
67 int fmode, cmode;
68 {
69 register struct vnode *vp;
70 register struct proc *p = ndp->ni_cnd.cn_proc;
71 register struct ucred *cred = p->p_ucred;
72 struct vattr vat;
73 struct vattr *vap = &vat;
74 int error;
75
76 if (fmode & O_CREAT) {
77 ndp->ni_cnd.cn_nameiop = CREATE;
78 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
79 if ((fmode & O_EXCL) == 0)
80 ndp->ni_cnd.cn_flags |= FOLLOW;
81 if (error = namei(ndp))
82 return (error);
83 if (ndp->ni_vp == NULL) {
84 VATTR_NULL(vap);
85 vap->va_type = VREG;
86 vap->va_mode = cmode;
87 LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE);
88 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
89 &ndp->ni_cnd, vap))
90 return (error);
91 fmode &= ~O_TRUNC;
92 vp = ndp->ni_vp;
93 } else {
94 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
95 if (ndp->ni_dvp == ndp->ni_vp)
96 vrele(ndp->ni_dvp);
97 else
98 vput(ndp->ni_dvp);
99 ndp->ni_dvp = NULL;
100 vp = ndp->ni_vp;
101 if (fmode & O_EXCL) {
102 error = EEXIST;
103 goto bad;
104 }
105 fmode &= ~O_CREAT;
106 }
107 } else {
108 ndp->ni_cnd.cn_nameiop = LOOKUP;
109 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
110 if (error = namei(ndp))
111 return (error);
112 vp = ndp->ni_vp;
113 }
114 if (vp->v_type == VSOCK) {
115 error = EOPNOTSUPP;
116 goto bad;
117 }
118 if ((fmode & O_CREAT) == 0) {
119 if (fmode & FREAD) {
120 if (error = VOP_ACCESS(vp, VREAD, cred, p))
121 goto bad;
122 }
123 if (fmode & (FWRITE | O_TRUNC)) {
124 if (vp->v_type == VDIR) {
125 error = EISDIR;
126 goto bad;
127 }
128 if ((error = vn_writechk(vp)) ||
129 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
130 goto bad;
131 }
132 }
133 if (fmode & O_TRUNC) {
134 VOP_UNLOCK(vp); /* XXX */
135 LEASE_CHECK(vp, p, cred, LEASE_WRITE);
136 VOP_LOCK(vp); /* XXX */
137 VATTR_NULL(vap);
138 vap->va_size = 0;
139 if (error = VOP_SETATTR(vp, vap, cred, p))
140 goto bad;
141 }
142 if (error = VOP_OPEN(vp, fmode, cred, p))
143 goto bad;
144 if (fmode & FWRITE)
145 vp->v_writecount++;
146 return (0);
147 bad:
148 vput(vp);
149 return (error);
150 }
151
152 /*
153 * Check for write permissions on the specified vnode.
154 * The read-only status of the file system is checked.
155 * Also, prototype text segments cannot be written.
156 */
157 vn_writechk(vp)
158 register struct vnode *vp;
159 {
160
161 /*
162 * Disallow write attempts on read-only file systems;
163 * unless the file is a socket or a block or character
164 * device resident on the file system.
165 */
166 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
167 switch (vp->v_type) {
168 case VREG: case VDIR: case VLNK:
169 return (EROFS);
170 }
171 }
172 /*
173 * If there's shared text associated with
174 * the vnode, try to free it up once. If
175 * we fail, we can't allow writing.
176 */
177 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
178 return (ETXTBSY);
179 return (0);
180 }
181
182 /*
183 * Vnode close call
184 */
185 vn_close(vp, flags, cred, p)
186 register struct vnode *vp;
187 int flags;
188 struct ucred *cred;
189 struct proc *p;
190 {
191 int error;
192
193 if (flags & FWRITE)
194 vp->v_writecount--;
195 error = VOP_CLOSE(vp, flags, cred, p);
196 vrele(vp);
197 return (error);
198 }
199
200 /*
201 * Package up an I/O request on a vnode into a uio and do it.
202 */
203 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
204 enum uio_rw rw;
205 struct vnode *vp;
206 caddr_t base;
207 int len;
208 off_t offset;
209 enum uio_seg segflg;
210 int ioflg;
211 struct ucred *cred;
212 int *aresid;
213 struct proc *p;
214 {
215 struct uio auio;
216 struct iovec aiov;
217 int error;
218
219 if ((ioflg & IO_NODELOCKED) == 0)
220 VOP_LOCK(vp);
221 auio.uio_iov = &aiov;
222 auio.uio_iovcnt = 1;
223 aiov.iov_base = base;
224 aiov.iov_len = len;
225 auio.uio_resid = len;
226 auio.uio_offset = offset;
227 auio.uio_segflg = segflg;
228 auio.uio_rw = rw;
229 auio.uio_procp = p;
230 if (rw == UIO_READ) {
231 error = VOP_READ(vp, &auio, ioflg, cred);
232 } else {
233 error = VOP_WRITE(vp, &auio, ioflg, cred);
234 }
235 if (aresid)
236 *aresid = auio.uio_resid;
237 else
238 if (auio.uio_resid && error == 0)
239 error = EIO;
240 if ((ioflg & IO_NODELOCKED) == 0)
241 VOP_UNLOCK(vp);
242 return (error);
243 }
244
245 /*
246 * File table vnode read routine.
247 */
248 vn_read(fp, uio, cred)
249 struct file *fp;
250 struct uio *uio;
251 struct ucred *cred;
252 {
253 register struct vnode *vp = (struct vnode *)fp->f_data;
254 int count, error;
255
256 LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ);
257 VOP_LOCK(vp);
258 uio->uio_offset = fp->f_offset;
259 count = uio->uio_resid;
260 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
261 cred);
262 fp->f_offset += count - uio->uio_resid;
263 VOP_UNLOCK(vp);
264 return (error);
265 }
266
267 /*
268 * File table vnode write routine.
269 */
270 vn_write(fp, uio, cred)
271 struct file *fp;
272 struct uio *uio;
273 struct ucred *cred;
274 {
275 register struct vnode *vp = (struct vnode *)fp->f_data;
276 int count, error, ioflag = 0;
277
278 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
279 ioflag |= IO_APPEND;
280 if (fp->f_flag & FNONBLOCK)
281 ioflag |= IO_NDELAY;
282 LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE);
283 VOP_LOCK(vp);
284 uio->uio_offset = fp->f_offset;
285 count = uio->uio_resid;
286 error = VOP_WRITE(vp, uio, ioflag, cred);
287 if (ioflag & IO_APPEND)
288 fp->f_offset = uio->uio_offset;
289 else
290 fp->f_offset += count - uio->uio_resid;
291 VOP_UNLOCK(vp);
292 return (error);
293 }
294
295 /*
296 * File table vnode stat routine.
297 */
298 vn_stat(vp, sb, p)
299 struct vnode *vp;
300 register struct stat *sb;
301 struct proc *p;
302 {
303 struct vattr vattr;
304 register struct vattr *vap;
305 int error;
306 u_short mode;
307
308 vap = &vattr;
309 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
310 if (error)
311 return (error);
312 /*
313 * Copy from vattr table
314 */
315 sb->st_dev = vap->va_fsid;
316 sb->st_ino = vap->va_fileid;
317 mode = vap->va_mode;
318 switch (vp->v_type) {
319 case VREG:
320 mode |= S_IFREG;
321 break;
322 case VDIR:
323 mode |= S_IFDIR;
324 break;
325 case VBLK:
326 mode |= S_IFBLK;
327 break;
328 case VCHR:
329 mode |= S_IFCHR;
330 break;
331 case VLNK:
332 mode |= S_IFLNK;
333 break;
334 case VSOCK:
335 mode |= S_IFSOCK;
336 break;
337 case VFIFO:
338 mode |= S_IFIFO;
339 break;
340 default:
341 return (EBADF);
342 };
343 sb->st_mode = mode;
344 sb->st_nlink = vap->va_nlink;
345 sb->st_uid = vap->va_uid;
346 sb->st_gid = vap->va_gid;
347 sb->st_rdev = vap->va_rdev;
348 sb->st_size = vap->va_size;
349 sb->st_atimespec = vap->va_atime;
350 sb->st_mtimespec= vap->va_mtime;
351 sb->st_ctimespec = vap->va_ctime;
352 sb->st_blksize = vap->va_blocksize;
353 sb->st_flags = vap->va_flags;
354 sb->st_gen = vap->va_gen;
355 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
356 return (0);
357 }
358
359 /*
360 * File table vnode ioctl routine.
361 */
362 vn_ioctl(fp, com, data, p)
363 struct file *fp;
364 int com;
365 caddr_t data;
366 struct proc *p;
367 {
368 register struct vnode *vp = ((struct vnode *)fp->f_data);
369 struct vattr vattr;
370 int error;
371
372 switch (vp->v_type) {
373
374 case VREG:
375 case VDIR:
376 if (com == FIONREAD) {
377 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
378 return (error);
379 *(int *)data = vattr.va_size - fp->f_offset;
380 return (0);
381 }
382 if (com == FIONBIO || com == FIOASYNC) /* XXX */
383 return (0); /* XXX */
384 /* fall into ... */
385
386 default:
387 return (ENOTTY);
388
389 case VFIFO:
390 case VCHR:
391 case VBLK:
392 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
393 if (error == 0 && com == TIOCSCTTY) {
394 if (p->p_session->s_ttyvp)
395 vrele(p->p_session->s_ttyvp);
396 p->p_session->s_ttyvp = vp;
397 VREF(vp);
398 }
399 return (error);
400 }
401 }
402
403 /*
404 * File table vnode select routine.
405 */
406 vn_select(fp, which, p)
407 struct file *fp;
408 int which;
409 struct proc *p;
410 {
411
412 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
413 fp->f_cred, p));
414 }
415
416 /*
417 * File table vnode close routine.
418 */
419 vn_closefile(fp, p)
420 struct file *fp;
421 struct proc *p;
422 {
423
424 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
425 fp->f_cred, p));
426 }
427