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