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