xref: /original-bsd/sys/kern/vfs_vnops.c (revision 5429b474)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)vfs_vnops.c	7.24 (Berkeley) 08/22/90
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "user.h"
13 #include "kernel.h"
14 #include "file.h"
15 #include "stat.h"
16 #include "buf.h"
17 #include "proc.h"
18 #include "uio.h"
19 #include "socket.h"
20 #include "socketvar.h"
21 #include "mount.h"
22 #include "vnode.h"
23 #include "ioctl.h"
24 #include "tty.h"
25 
26 int	vn_read(), vn_write(), vn_ioctl(), vn_select(), vn_close();
27 struct 	fileops vnops =
28 	{ vn_read, vn_write, vn_ioctl, vn_select, vn_close };
29 
30 /*
31  * Common code for vnode open operations.
32  * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
33  */
34 vn_open(ndp, fmode, cmode)
35 	register struct nameidata *ndp;
36 	int fmode, cmode;
37 {
38 	register struct vnode *vp;
39 	struct vattr vat;
40 	struct vattr *vap = &vat;
41 	int error;
42 
43 	if (fmode & FCREAT) {
44 		ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
45 		if ((fmode & FEXCL) == 0)
46 			ndp->ni_nameiop |= FOLLOW;
47 		if (error = namei(ndp))
48 			return (error);
49 		if (ndp->ni_vp == NULL) {
50 			VATTR_NULL(vap);
51 			vap->va_type = VREG;
52 			vap->va_mode = cmode;
53 			if (error = VOP_CREATE(ndp, vap))
54 				return (error);
55 			fmode &= ~FTRUNC;
56 			vp = ndp->ni_vp;
57 		} else {
58 			if (ndp->ni_dvp == ndp->ni_vp)
59 				vrele(ndp->ni_dvp);
60 			else
61 				vput(ndp->ni_dvp);
62 			ndp->ni_dvp = NULL;
63 			vp = ndp->ni_vp;
64 			if (fmode & FEXCL) {
65 				error = EEXIST;
66 				goto bad;
67 			}
68 			fmode &= ~FCREAT;
69 		}
70 	} else {
71 		ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
72 		if (error = namei(ndp))
73 			return (error);
74 		vp = ndp->ni_vp;
75 	}
76 	if (vp->v_type == VSOCK) {
77 		error = EOPNOTSUPP;
78 		goto bad;
79 	}
80 	if ((fmode & FCREAT) == 0) {
81 		if (fmode & FREAD) {
82 			if (error = VOP_ACCESS(vp, VREAD, ndp->ni_cred))
83 				goto bad;
84 		}
85 		if (fmode & (FWRITE|FTRUNC)) {
86 			if (vp->v_type == VDIR) {
87 				error = EISDIR;
88 				goto bad;
89 			}
90 			if ((error = vn_writechk(vp)) ||
91 			    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
92 				goto bad;
93 		}
94 	}
95 	if (fmode & FTRUNC) {
96 		VATTR_NULL(vap);
97 		vap->va_size = 0;
98 		if (error = VOP_SETATTR(vp, vap, ndp->ni_cred))
99 			goto bad;
100 	}
101 	VOP_UNLOCK(vp);
102 	error = VOP_OPEN(vp, fmode, ndp->ni_cred);
103 	if (error)
104 		vrele(vp);
105 	return (error);
106 
107 bad:
108 	vput(vp);
109 	return (error);
110 }
111 
112 /*
113  * Check for write permissions on the specified vnode.
114  * The read-only status of the file system is checked.
115  * Also, prototype text segments cannot be written.
116  */
117 vn_writechk(vp)
118 	register struct vnode *vp;
119 {
120 
121 	/*
122 	 * Disallow write attempts on read-only file systems;
123 	 * unless the file is a socket or a block or character
124 	 * device resident on the file system.
125 	 */
126 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
127 		switch (vp->v_type) {
128 		case VREG: case VDIR: case VLNK:
129 			return (EROFS);
130 		}
131 	}
132 	/*
133 	 * If there's shared text associated with
134 	 * the vnode, try to free it up once.  If
135 	 * we fail, we can't allow writing.
136 	 */
137 	if (vp->v_flag & VTEXT)
138 		xrele(vp);
139 	if (vp->v_flag & VTEXT)
140 		return (ETXTBSY);
141 	return (0);
142 }
143 
144 /*
145  * Vnode version of rdwri() for calls on file systems.
146  */
147 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid)
148 	enum uio_rw rw;
149 	struct vnode *vp;
150 	caddr_t base;
151 	int len;
152 	off_t offset;
153 	enum uio_seg segflg;
154 	int ioflg;
155 	struct ucred *cred;
156 	int *aresid;
157 {
158 	struct uio auio;
159 	struct iovec aiov;
160 	int error;
161 
162 	if ((ioflg & IO_NODELOCKED) == 0)
163 		VOP_LOCK(vp);
164 	auio.uio_iov = &aiov;
165 	auio.uio_iovcnt = 1;
166 	aiov.iov_base = base;
167 	aiov.iov_len = len;
168 	auio.uio_resid = len;
169 	auio.uio_offset = offset;
170 	auio.uio_segflg = segflg;
171 	auio.uio_rw = rw;
172 	if (rw == UIO_READ)
173 		error = VOP_READ(vp, &auio, ioflg, cred);
174 	else
175 		error = VOP_WRITE(vp, &auio, ioflg, cred);
176 	if (aresid)
177 		*aresid = auio.uio_resid;
178 	else
179 		if (auio.uio_resid && error == 0)
180 			error = EIO;
181 	if ((ioflg & IO_NODELOCKED) == 0)
182 		VOP_UNLOCK(vp);
183 	return (error);
184 }
185 
186 vn_read(fp, uio, cred)
187 	struct file *fp;
188 	struct uio *uio;
189 	struct ucred *cred;
190 {
191 	register struct vnode *vp = (struct vnode *)fp->f_data;
192 	int count, error;
193 
194 	VOP_LOCK(vp);
195 	uio->uio_offset = fp->f_offset;
196 	count = uio->uio_resid;
197 	error = VOP_READ(vp, uio, (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred);
198 	fp->f_offset += count - uio->uio_resid;
199 	VOP_UNLOCK(vp);
200 	return (error);
201 }
202 
203 vn_write(fp, uio, cred)
204 	struct file *fp;
205 	struct uio *uio;
206 	struct ucred *cred;
207 {
208 	register struct vnode *vp = (struct vnode *)fp->f_data;
209 	int count, error, ioflag = 0;
210 
211 	if (vp->v_type == VREG && (fp->f_flag & FAPPEND))
212 		ioflag |= IO_APPEND;
213 	if (fp->f_flag & FNDELAY)
214 		ioflag |= IO_NDELAY;
215 	VOP_LOCK(vp);
216 	uio->uio_offset = fp->f_offset;
217 	count = uio->uio_resid;
218 	error = VOP_WRITE(vp, uio, ioflag, cred);
219 	if (ioflag & IO_APPEND)
220 		fp->f_offset = uio->uio_offset;
221 	else
222 		fp->f_offset += count - uio->uio_resid;
223 	VOP_UNLOCK(vp);
224 	return (error);
225 }
226 
227 /*
228  * Get stat info for a vnode.
229  */
230 vn_stat(vp, sb)
231 	struct vnode *vp;
232 	register struct stat *sb;
233 {
234 	struct vattr vattr;
235 	register struct vattr *vap;
236 	int error;
237 	u_short mode;
238 
239 	vap = &vattr;
240 	error = VOP_GETATTR(vp, vap, u.u_cred);
241 	if (error)
242 		return (error);
243 	/*
244 	 * Copy from vattr table
245 	 */
246 	sb->st_dev = vap->va_fsid;
247 	sb->st_ino = vap->va_fileid;
248 	mode = vap->va_mode;
249 	switch (vp->v_type) {
250 	case VREG:
251 		mode |= S_IFREG;
252 		break;
253 	case VDIR:
254 		mode |= S_IFDIR;
255 		break;
256 	case VBLK:
257 		mode |= S_IFBLK;
258 		break;
259 	case VCHR:
260 		mode |= S_IFCHR;
261 		break;
262 	case VLNK:
263 		mode |= S_IFLNK;
264 		break;
265 	case VSOCK:
266 		mode |= S_IFSOCK;
267 		break;
268 	case VFIFO:
269 		mode |= S_IFIFO;
270 		break;
271 	default:
272 		return (EBADF);
273 	};
274 	sb->st_mode = mode;
275 	sb->st_nlink = vap->va_nlink;
276 	sb->st_uid = vap->va_uid;
277 	sb->st_gid = vap->va_gid;
278 	sb->st_rdev = vap->va_rdev;
279 	sb->st_size = vap->va_size;
280 	sb->st_atime = vap->va_atime.tv_sec;
281 	sb->st_spare1 = 0;
282 	sb->st_mtime = vap->va_mtime.tv_sec;
283 	sb->st_spare2 = 0;
284 	sb->st_ctime = vap->va_ctime.tv_sec;
285 	sb->st_spare3 = 0;
286 	sb->st_blksize = vap->va_blocksize;
287 	sb->st_flags = vap->va_flags;
288 	sb->st_gen = vap->va_gen;
289 	sb->st_blocks = vap->va_bytes / S_BLKSIZE;
290 	return (0);
291 }
292 
293 /*
294  * Vnode ioctl call
295  */
296 vn_ioctl(fp, com, data)
297 	struct file *fp;
298 	int com;
299 	caddr_t data;
300 {
301 	register struct vnode *vp = ((struct vnode *)fp->f_data);
302 	struct vattr vattr;
303 	int error;
304 
305 	switch (vp->v_type) {
306 
307 	case VREG:
308 	case VDIR:
309 		if (com == FIONREAD) {
310 			if (error = VOP_GETATTR(vp, &vattr, u.u_cred))
311 				return (error);
312 			*(off_t *)data = vattr.va_size - fp->f_offset;
313 			return (0);
314 		}
315 		if (com == FIONBIO || com == FIOASYNC)	/* XXX */
316 			return (0);			/* XXX */
317 		/* fall into ... */
318 
319 	default:
320 		return (ENOTTY);
321 
322 	case VFIFO:
323 	case VCHR:
324 	case VBLK:
325 		error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred);
326 		if (error == 0 && com == TIOCSCTTY) {
327 			u.u_procp->p_session->s_ttyvp = vp;
328 			VREF(vp);
329 		}
330 		return (error);
331 	}
332 }
333 
334 /*
335  * Vnode select call
336  */
337 vn_select(fp, which)
338 	struct file *fp;
339 	int which;
340 {
341 	return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
342 		u.u_cred));
343 }
344 
345 /*
346  * Vnode close call
347  */
348 vn_close(fp)
349 	register struct file *fp;
350 {
351 	struct vnode *vp = ((struct vnode *)fp->f_data);
352 	int error;
353 
354 	if (fp->f_flag & (FSHLOCK|FEXLOCK))
355 		vn_unlock(fp, FSHLOCK|FEXLOCK);
356 	/*
357 	 * Must delete vnode reference from this file entry
358 	 * before VOP_CLOSE, so that only other references
359 	 * will prevent close.
360 	 */
361 	fp->f_data = (caddr_t) 0;
362 	error = VOP_CLOSE(vp, fp->f_flag, u.u_cred);
363 	vrele(vp);
364 	return (error);
365 }
366 
367 /*
368  * Place an advisory lock on a vnode.
369  * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries
370  */
371 vn_lock(fp, cmd)
372 	register struct file *fp;
373 	int cmd;
374 {
375 	register int priority = PLOCK;
376 	register struct vnode *vp = (struct vnode *)fp->f_data;
377 	int error = 0;
378 	static char lockstr[] = "flock";
379 
380 	if ((cmd & LOCK_EX) == 0)
381 		priority += 4;
382 	priority |= PCATCH;
383 
384 	/*
385 	 * If there's a exclusive lock currently applied
386 	 * to the file, then we've gotta wait for the
387 	 * lock with everyone else.
388 	 */
389 again:
390 	while (vp->v_flag & VEXLOCK) {
391 		/*
392 		 * If we're holding an exclusive
393 		 * lock, then release it.
394 		 */
395 		if (fp->f_flag & FEXLOCK) {
396 			vn_unlock(fp, FEXLOCK);
397 			continue;
398 		}
399 		if (cmd & LOCK_NB)
400 			return (EWOULDBLOCK);
401 		vp->v_flag |= VLWAIT;
402 		if (error = tsleep((caddr_t)&vp->v_exlockc, priority,
403 		    lockstr, 0))
404 			return (error);
405 	}
406 	if (error == 0 && (cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) {
407 		/*
408 		 * Must wait for any shared locks to finish
409 		 * before we try to apply a exclusive lock.
410 		 *
411 		 * If we're holding a shared
412 		 * lock, then release it.
413 		 */
414 		if (fp->f_flag & FSHLOCK) {
415 			vn_unlock(fp, FSHLOCK);
416 			goto again;
417 		}
418 		if (cmd & LOCK_NB)
419 			return (EWOULDBLOCK);
420 		vp->v_flag |= VLWAIT;
421 		if (error = tsleep((caddr_t)&vp->v_shlockc, PLOCK | PCATCH,
422 		    lockstr, 0))
423 			return (error);
424 	}
425 	if (fp->f_flag & FEXLOCK)
426 		panic("vn_lock");
427 	if (cmd & LOCK_EX) {
428 		cmd &= ~LOCK_SH;
429 		vp->v_exlockc++;
430 		vp->v_flag |= VEXLOCK;
431 		fp->f_flag |= FEXLOCK;
432 	}
433 	if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) {
434 		vp->v_shlockc++;
435 		vp->v_flag |= VSHLOCK;
436 		fp->f_flag |= FSHLOCK;
437 	}
438 	return (0);
439 }
440 
441 /*
442  * Unlock a file.
443  */
444 vn_unlock(fp, kind)
445 	register struct file *fp;
446 	int kind;
447 {
448 	register struct vnode *vp = (struct vnode *)fp->f_data;
449 	int flags;
450 
451 	kind &= fp->f_flag;
452 	if (vp == NULL || kind == 0)
453 		return;
454 	flags = vp->v_flag;
455 	if (kind & FSHLOCK) {
456 		if ((flags & VSHLOCK) == 0)
457 			panic("vn_unlock: SHLOCK");
458 		if (--vp->v_shlockc == 0) {
459 			vp->v_flag &= ~VSHLOCK;
460 			if (flags & VLWAIT)
461 				wakeup((caddr_t)&vp->v_shlockc);
462 		}
463 		fp->f_flag &= ~FSHLOCK;
464 	}
465 	if (kind & FEXLOCK) {
466 		if ((flags & VEXLOCK) == 0)
467 			panic("vn_unlock: EXLOCK");
468 		if (--vp->v_exlockc == 0) {
469 			vp->v_flag &= ~(VEXLOCK|VLWAIT);
470 			if (flags & VLWAIT)
471 				wakeup((caddr_t)&vp->v_exlockc);
472 		}
473 		fp->f_flag &= ~FEXLOCK;
474 	}
475 }
476 
477 /*
478  * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
479  * 	- look up fsid in mount list (if not found ret error)
480  *	- get vp by calling VFS_FHTOVP() macro
481  *	- if lockflag lock it with VOP_LOCK()
482  */
483 vn_fhtovp(fhp, lockflag, vpp)
484 	fhandle_t *fhp;
485 	int lockflag;
486 	struct vnode **vpp;
487 {
488 	register struct mount *mp;
489 
490 	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
491 		return (ESTALE);
492 	if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
493 		return (ESTALE);
494 	if (!lockflag)
495 		VOP_UNLOCK(*vpp);
496 	return (0);
497 }
498 
499 /*
500  * Noop
501  */
502 vfs_noop()
503 {
504 
505 	return (ENXIO);
506 }
507 
508 /*
509  * Null op
510  */
511 vfs_nullop()
512 {
513 
514 	return (0);
515 }
516