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