vfs_vnops.c revision 1.30
1/*	$NetBSD: vfs_vnops.c,v 1.30 1998/07/28 18:37:48 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.14 (Berkeley) 6/15/95
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#ifdef UNION
67#include <miscfs/union/union.h>
68#endif
69
70struct 	fileops vnops =
71	{ vn_read, vn_write, vn_ioctl, vn_poll, vn_closefile };
72
73/*
74 * Common code for vnode open operations.
75 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
76 */
77int
78vn_open(ndp, fmode, cmode)
79	register struct nameidata *ndp;
80	int fmode, cmode;
81{
82	register struct vnode *vp;
83	register struct proc *p = ndp->ni_cnd.cn_proc;
84	register struct ucred *cred = p->p_ucred;
85	struct vattr va;
86	int error;
87
88	if (fmode & O_CREAT) {
89		ndp->ni_cnd.cn_nameiop = CREATE;
90		ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
91		if ((fmode & O_EXCL) == 0)
92			ndp->ni_cnd.cn_flags |= FOLLOW;
93		if ((error = namei(ndp)) != 0)
94			return (error);
95		if (ndp->ni_vp == NULL) {
96			VATTR_NULL(&va);
97			va.va_type = VREG;
98			va.va_mode = cmode;
99			if (fmode & O_EXCL)
100				 va.va_vaflags |= VA_EXCLUSIVE;
101			VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
102			error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
103					   &ndp->ni_cnd, &va);
104			if (error)
105				return (error);
106			fmode &= ~O_TRUNC;
107			vp = ndp->ni_vp;
108		} else {
109			VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
110			if (ndp->ni_dvp == ndp->ni_vp)
111				vrele(ndp->ni_dvp);
112			else
113				vput(ndp->ni_dvp);
114			ndp->ni_dvp = NULL;
115			vp = ndp->ni_vp;
116			if (fmode & O_EXCL) {
117				error = EEXIST;
118				goto bad;
119			}
120			fmode &= ~O_CREAT;
121		}
122	} else {
123		ndp->ni_cnd.cn_nameiop = LOOKUP;
124		ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
125		if ((error = namei(ndp)) != 0)
126			return (error);
127		vp = ndp->ni_vp;
128	}
129	if (vp->v_type == VSOCK) {
130		error = EOPNOTSUPP;
131		goto bad;
132	}
133	if ((fmode & O_CREAT) == 0) {
134		if (fmode & FREAD) {
135			if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
136				goto bad;
137		}
138		if (fmode & (FWRITE | O_TRUNC)) {
139			if (vp->v_type == VDIR) {
140				error = EISDIR;
141				goto bad;
142			}
143			if ((error = vn_writechk(vp)) != 0 ||
144			    (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
145				goto bad;
146		}
147	}
148	if (fmode & O_TRUNC) {
149		VOP_UNLOCK(vp, 0);			/* XXX */
150		VOP_LEASE(vp, p, cred, LEASE_WRITE);
151		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);	/* XXX */
152		VATTR_NULL(&va);
153		va.va_size = 0;
154		if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
155			goto bad;
156	}
157	if ((error = VOP_OPEN(vp, fmode, cred, p)) != 0)
158		goto bad;
159	if (fmode & FWRITE)
160		vp->v_writecount++;
161	return (0);
162bad:
163	vput(vp);
164	return (error);
165}
166
167/*
168 * Check for write permissions on the specified vnode.
169 * Prototype text segments cannot be written.
170 */
171int
172vn_writechk(vp)
173	register struct vnode *vp;
174{
175
176	/*
177	 * If there's shared text associated with
178	 * the vnode, try to free it up once.  If
179	 * we fail, we can't allow writing.
180	 */
181#if defined(UVM)
182	if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp))
183		return (ETXTBSY);
184#else
185	if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
186		return (ETXTBSY);
187#endif
188	return (0);
189}
190
191/*
192 * Vnode close call
193 */
194int
195vn_close(vp, flags, cred, p)
196	register struct vnode *vp;
197	int flags;
198	struct ucred *cred;
199	struct proc *p;
200{
201	int error;
202
203	if (flags & FWRITE)
204		vp->v_writecount--;
205	error = VOP_CLOSE(vp, flags, cred, p);
206	vrele(vp);
207	return (error);
208}
209
210/*
211 * Package up an I/O request on a vnode into a uio and do it.
212 */
213int
214vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
215	enum uio_rw rw;
216	struct vnode *vp;
217	caddr_t base;
218	int len;
219	off_t offset;
220	enum uio_seg segflg;
221	int ioflg;
222	struct ucred *cred;
223	size_t *aresid;
224	struct proc *p;
225{
226	struct uio auio;
227	struct iovec aiov;
228	int error;
229
230	if ((ioflg & IO_NODELOCKED) == 0)
231		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
232	auio.uio_iov = &aiov;
233	auio.uio_iovcnt = 1;
234	aiov.iov_base = base;
235	aiov.iov_len = len;
236	auio.uio_resid = len;
237	auio.uio_offset = offset;
238	auio.uio_segflg = segflg;
239	auio.uio_rw = rw;
240	auio.uio_procp = p;
241	if (rw == UIO_READ) {
242		error = VOP_READ(vp, &auio, ioflg, cred);
243	} else {
244		error = VOP_WRITE(vp, &auio, ioflg, cred);
245	}
246	if (aresid)
247		*aresid = auio.uio_resid;
248	else
249		if (auio.uio_resid && error == 0)
250			error = EIO;
251	if ((ioflg & IO_NODELOCKED) == 0)
252		VOP_UNLOCK(vp, 0);
253	return (error);
254}
255
256int
257vn_readdir(fp, buf, segflg, count, done, p, cookies, ncookies)
258	struct file *fp;
259	char *buf;
260	int segflg, *done, *ncookies;
261	u_int count;
262	struct proc *p;
263	off_t **cookies;
264{
265	struct vnode *vp = (struct vnode *)fp->f_data;
266	struct iovec aiov;
267	struct uio auio;
268	int error, eofflag;
269
270unionread:
271	if (vp->v_type != VDIR)
272		return (EINVAL);
273	aiov.iov_base = buf;
274	aiov.iov_len = count;
275	auio.uio_iov = &aiov;
276	auio.uio_iovcnt = 1;
277	auio.uio_rw = UIO_READ;
278	auio.uio_segflg = segflg;
279	auio.uio_procp = p;
280	auio.uio_resid = count;
281	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
282	auio.uio_offset = fp->f_offset;
283	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, cookies,
284		    ncookies);
285	fp->f_offset = auio.uio_offset;
286	VOP_UNLOCK(vp, 0);
287	if (error)
288		return (error);
289
290#ifdef UNION
291{
292	extern int (**union_vnodeop_p) __P((void *));
293	extern struct vnode *union_dircache __P((struct vnode *));
294
295	if (count == auio.uio_resid && (vp->v_op == union_vnodeop_p)) {
296		struct vnode *lvp;
297
298		lvp = union_dircache(vp);
299		if (lvp != NULLVP) {
300			struct vattr va;
301
302			/*
303			 * If the directory is opaque,
304			 * then don't show lower entries
305			 */
306			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
307			if (va.va_flags & OPAQUE) {
308				vput(lvp);
309				lvp = NULL;
310			}
311		}
312
313		if (lvp != NULLVP) {
314			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
315			if (error) {
316				vput(lvp);
317				return (error);
318			}
319			VOP_UNLOCK(lvp, 0);
320			fp->f_data = (caddr_t) lvp;
321			fp->f_offset = 0;
322			error = vn_close(vp, FREAD, fp->f_cred, p);
323			if (error)
324				return (error);
325			vp = lvp;
326			goto unionread;
327		}
328	}
329}
330#endif /* UNION */
331
332	if (count == auio.uio_resid && (vp->v_flag & VROOT) &&
333	    (vp->v_mount->mnt_flag & MNT_UNION)) {
334		struct vnode *tvp = vp;
335		vp = vp->v_mount->mnt_vnodecovered;
336		VREF(vp);
337		fp->f_data = (caddr_t) vp;
338		fp->f_offset = 0;
339		vrele(tvp);
340		goto unionread;
341	}
342	*done = count - auio.uio_resid;
343	return error;
344}
345
346/*
347 * File table vnode read routine.
348 */
349int
350vn_read(fp, offset, uio, cred, flags)
351	struct file *fp;
352	off_t *offset;
353	struct uio *uio;
354	struct ucred *cred;
355	int flags;
356{
357	struct vnode *vp = (struct vnode *)fp->f_data;
358	int count, error;
359
360	VOP_LEASE(vp, uio->uio_procp, cred, LEASE_READ);
361	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
362	uio->uio_offset = *offset;
363	count = uio->uio_resid;
364	error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
365		cred);
366	if (flags & FOF_UPDATE_OFFSET)
367		*offset += count - uio->uio_resid;
368	VOP_UNLOCK(vp, 0);
369	return (error);
370}
371
372/*
373 * File table vnode write routine.
374 */
375int
376vn_write(fp, offset, uio, cred, flags)
377	struct file *fp;
378	off_t *offset;
379	struct uio *uio;
380	struct ucred *cred;
381	int flags;
382{
383	struct vnode *vp = (struct vnode *)fp->f_data;
384	int count, error, ioflag = IO_UNIT;
385
386	if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
387		ioflag |= IO_APPEND;
388	if (fp->f_flag & FNONBLOCK)
389		ioflag |= IO_NDELAY;
390	if (fp->f_flag & FFSYNC ||
391	    (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
392		ioflag |= IO_SYNC;
393	VOP_LEASE(vp, uio->uio_procp, cred, LEASE_WRITE);
394	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
395	uio->uio_offset = *offset;
396	count = uio->uio_resid;
397	error = VOP_WRITE(vp, uio, ioflag, cred);
398	if (flags & FOF_UPDATE_OFFSET) {
399		if (ioflag & IO_APPEND)
400			*offset = uio->uio_offset;
401		else
402			*offset += count - uio->uio_resid;
403	}
404	VOP_UNLOCK(vp, 0);
405	return (error);
406}
407
408/*
409 * File table vnode stat routine.
410 */
411int
412vn_stat(vp, sb, p)
413	struct vnode *vp;
414	register struct stat *sb;
415	struct proc *p;
416{
417	struct vattr va;
418	int error;
419	u_short mode;
420
421	error = VOP_GETATTR(vp, &va, p->p_ucred, p);
422	if (error)
423		return (error);
424	/*
425	 * Copy from vattr table
426	 */
427	sb->st_dev = va.va_fsid;
428	sb->st_ino = va.va_fileid;
429	mode = va.va_mode;
430	switch (vp->v_type) {
431	case VREG:
432		mode |= S_IFREG;
433		break;
434	case VDIR:
435		mode |= S_IFDIR;
436		break;
437	case VBLK:
438		mode |= S_IFBLK;
439		break;
440	case VCHR:
441		mode |= S_IFCHR;
442		break;
443	case VLNK:
444		mode |= S_IFLNK;
445		break;
446	case VSOCK:
447		mode |= S_IFSOCK;
448		break;
449	case VFIFO:
450		mode |= S_IFIFO;
451		break;
452	default:
453		return (EBADF);
454	};
455	sb->st_mode = mode;
456	sb->st_nlink = va.va_nlink;
457	sb->st_uid = va.va_uid;
458	sb->st_gid = va.va_gid;
459	sb->st_rdev = va.va_rdev;
460	sb->st_size = va.va_size;
461	sb->st_atimespec = va.va_atime;
462	sb->st_mtimespec = va.va_mtime;
463	sb->st_ctimespec = va.va_ctime;
464	sb->st_blksize = va.va_blocksize;
465	sb->st_flags = va.va_flags;
466	sb->st_gen = 0;
467	sb->st_blocks = va.va_bytes / S_BLKSIZE;
468	return (0);
469}
470
471/*
472 * File table vnode ioctl routine.
473 */
474int
475vn_ioctl(fp, com, data, p)
476	struct file *fp;
477	u_long com;
478	caddr_t data;
479	struct proc *p;
480{
481	register struct vnode *vp = ((struct vnode *)fp->f_data);
482	struct vattr vattr;
483	int error;
484
485	switch (vp->v_type) {
486
487	case VREG:
488	case VDIR:
489		if (com == FIONREAD) {
490			error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
491			if (error)
492				return (error);
493			*(int *)data = vattr.va_size - fp->f_offset;
494			return (0);
495		}
496		if (com == FIONBIO || com == FIOASYNC)	/* XXX */
497			return (0);			/* XXX */
498		/* fall into ... */
499
500	default:
501		return (ENOTTY);
502
503	case VFIFO:
504	case VCHR:
505	case VBLK:
506		error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
507		if (error == 0 && com == TIOCSCTTY) {
508			if (p->p_session->s_ttyvp)
509				vrele(p->p_session->s_ttyvp);
510			p->p_session->s_ttyvp = vp;
511			VREF(vp);
512		}
513		return (error);
514	}
515}
516
517/*
518 * File table vnode poll routine.
519 */
520int
521vn_poll(fp, events, p)
522	struct file *fp;
523	int events;
524	struct proc *p;
525{
526
527	return (VOP_POLL(((struct vnode *)fp->f_data), events, p));
528}
529
530/*
531 * Check that the vnode is still valid, and if so
532 * acquire requested lock.
533 */
534int
535vn_lock(vp, flags)
536	struct vnode *vp;
537	int flags;
538{
539	int error;
540
541	do {
542		if ((flags & LK_INTERLOCK) == 0)
543			simple_lock(&vp->v_interlock);
544		if (vp->v_flag & VXLOCK) {
545			vp->v_flag |= VXWANT;
546			simple_unlock(&vp->v_interlock);
547			tsleep((caddr_t)vp, PINOD, "vn_lock", 0);
548			error = ENOENT;
549		} else {
550			error = VOP_LOCK(vp, flags | LK_INTERLOCK);
551			if (error == 0)
552				return (error);
553		}
554		flags &= ~LK_INTERLOCK;
555	} while (flags & LK_RETRY);
556	return (error);
557}
558
559/*
560 * File table vnode close routine.
561 */
562int
563vn_closefile(fp, p)
564	struct file *fp;
565	struct proc *p;
566{
567
568	return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
569		fp->f_cred, p));
570}
571