xref: /csrg-svn/sys/kern/vfs_vnops.c (revision 43404)
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.22 (Berkeley) 06/21/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
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 		error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred);
333 		if (error == 0 && com == TIOCSCTTY) {
334 			u.u_procp->p_session->s_ttyvp = vp;
335 			VREF(vp);
336 		}
337 		return (error);
338 	}
339 }
340 
341 /*
342  * Vnode select call
343  */
344 vn_select(fp, which)
345 	struct file *fp;
346 	int which;
347 {
348 	return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
349 		u.u_cred));
350 }
351 
352 /*
353  * Vnode close call
354  */
355 vn_close(fp)
356 	register struct file *fp;
357 {
358 	struct vnode *vp = ((struct vnode *)fp->f_data);
359 	int error;
360 
361 	if (fp->f_flag & (FSHLOCK|FEXLOCK))
362 		vn_unlock(fp, FSHLOCK|FEXLOCK);
363 	/*
364 	 * Must delete vnode reference from this file entry
365 	 * before VOP_CLOSE, so that only other references
366 	 * will prevent close.
367 	 */
368 	fp->f_data = (caddr_t) 0;
369 	error = VOP_CLOSE(vp, fp->f_flag, u.u_cred);
370 	vrele(vp);
371 	return (error);
372 }
373 
374 /*
375  * Place an advisory lock on a vnode.
376  * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries
377  */
378 vn_lock(fp, cmd)
379 	register struct file *fp;
380 	int cmd;
381 {
382 	register int priority = PLOCK;
383 	register struct vnode *vp = (struct vnode *)fp->f_data;
384 	int error = 0;
385 	static char lockstr[] = "flock";
386 
387 	if ((cmd & LOCK_EX) == 0)
388 		priority += 4;
389 	priority |= PCATCH;
390 
391 	/*
392 	 * If there's a exclusive lock currently applied
393 	 * to the file, then we've gotta wait for the
394 	 * lock with everyone else.
395 	 */
396 again:
397 	while (vp->v_flag & VEXLOCK) {
398 		/*
399 		 * If we're holding an exclusive
400 		 * lock, then release it.
401 		 */
402 		if (fp->f_flag & FEXLOCK) {
403 			vn_unlock(fp, FEXLOCK);
404 			continue;
405 		}
406 		if (cmd & LOCK_NB)
407 			return (EWOULDBLOCK);
408 		vp->v_flag |= VLWAIT;
409 		if (error = tsleep((caddr_t)&vp->v_exlockc, priority,
410 		    lockstr, 0))
411 			return (error);
412 	}
413 	if (error = 0 && (cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) {
414 		/*
415 		 * Must wait for any shared locks to finish
416 		 * before we try to apply a exclusive lock.
417 		 *
418 		 * If we're holding a shared
419 		 * lock, then release it.
420 		 */
421 		if (fp->f_flag & FSHLOCK) {
422 			vn_unlock(fp, FSHLOCK);
423 			goto again;
424 		}
425 		if (cmd & LOCK_NB)
426 			return (EWOULDBLOCK);
427 		vp->v_flag |= VLWAIT;
428 		if (error = tsleep((caddr_t)&vp->v_shlockc, PLOCK | PCATCH,
429 		    lockstr, 0) == 0)
430 			return (error);
431 	}
432 	if (fp->f_flag & FEXLOCK)
433 		panic("vn_lock");
434 	if (cmd & LOCK_EX) {
435 		cmd &= ~LOCK_SH;
436 		vp->v_exlockc++;
437 		vp->v_flag |= VEXLOCK;
438 		fp->f_flag |= FEXLOCK;
439 	}
440 	if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) {
441 		vp->v_shlockc++;
442 		vp->v_flag |= VSHLOCK;
443 		fp->f_flag |= FSHLOCK;
444 	}
445 	return (0);
446 }
447 
448 /*
449  * Unlock a file.
450  */
451 vn_unlock(fp, kind)
452 	register struct file *fp;
453 	int kind;
454 {
455 	register struct vnode *vp = (struct vnode *)fp->f_data;
456 	int flags;
457 
458 	kind &= fp->f_flag;
459 	if (vp == NULL || kind == 0)
460 		return;
461 	flags = vp->v_flag;
462 	if (kind & FSHLOCK) {
463 		if ((flags & VSHLOCK) == 0)
464 			panic("vn_unlock: SHLOCK");
465 		if (--vp->v_shlockc == 0) {
466 			vp->v_flag &= ~VSHLOCK;
467 			if (flags & VLWAIT)
468 				wakeup((caddr_t)&vp->v_shlockc);
469 		}
470 		fp->f_flag &= ~FSHLOCK;
471 	}
472 	if (kind & FEXLOCK) {
473 		if ((flags & VEXLOCK) == 0)
474 			panic("vn_unlock: EXLOCK");
475 		if (--vp->v_exlockc == 0) {
476 			vp->v_flag &= ~(VEXLOCK|VLWAIT);
477 			if (flags & VLWAIT)
478 				wakeup((caddr_t)&vp->v_exlockc);
479 		}
480 		fp->f_flag &= ~FEXLOCK;
481 	}
482 }
483 
484 /*
485  * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
486  * 	- look up fsid in mount list (if not found ret error)
487  *	- get vp by calling VFS_FHTOVP() macro
488  *	- if lockflag lock it with VOP_LOCK()
489  */
490 vn_fhtovp(fhp, lockflag, vpp)
491 	fhandle_t *fhp;
492 	int lockflag;
493 	struct vnode **vpp;
494 {
495 	register struct mount *mp;
496 
497 	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
498 		return (ESTALE);
499 	if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
500 		return (ESTALE);
501 	if (!lockflag)
502 		VOP_UNLOCK(*vpp);
503 	return (0);
504 }
505 
506 /*
507  * Noop
508  */
509 vfs_noop()
510 {
511 
512 	return (ENXIO);
513 }
514 
515 /*
516  * Null op
517  */
518 vfs_nullop()
519 {
520 
521 	return (0);
522 }
523