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