xref: /csrg-svn/sys/kern/vfs_vnops.c (revision 44460)
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.23 (Berkeley) 06/28/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) && vp->v_type != VCHR &&
127 	    vp->v_type != VBLK && vp->v_type != VSOCK)
128 		return (EROFS);
129 	/*
130 	 * If there's shared text associated with
131 	 * the vnode, try to free it up once.  If
132 	 * we fail, we can't allow writing.
133 	 */
134 	if (vp->v_flag & VTEXT)
135 		xrele(vp);
136 	if (vp->v_flag & VTEXT)
137 		return (ETXTBSY);
138 	return (0);
139 }
140 
141 /*
142  * Vnode version of rdwri() for calls on file systems.
143  */
144 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid)
145 	enum uio_rw rw;
146 	struct vnode *vp;
147 	caddr_t base;
148 	int len;
149 	off_t offset;
150 	enum uio_seg segflg;
151 	int ioflg;
152 	struct ucred *cred;
153 	int *aresid;
154 {
155 	struct uio auio;
156 	struct iovec aiov;
157 	int error;
158 
159 	if ((ioflg & IO_NODELOCKED) == 0)
160 		VOP_LOCK(vp);
161 	auio.uio_iov = &aiov;
162 	auio.uio_iovcnt = 1;
163 	aiov.iov_base = base;
164 	aiov.iov_len = len;
165 	auio.uio_resid = len;
166 	auio.uio_offset = offset;
167 	auio.uio_segflg = segflg;
168 	auio.uio_rw = rw;
169 	if (rw == UIO_READ)
170 		error = VOP_READ(vp, &auio, ioflg, cred);
171 	else
172 		error = VOP_WRITE(vp, &auio, ioflg, cred);
173 	if (aresid)
174 		*aresid = auio.uio_resid;
175 	else
176 		if (auio.uio_resid && error == 0)
177 			error = EIO;
178 	if ((ioflg & IO_NODELOCKED) == 0)
179 		VOP_UNLOCK(vp);
180 	return (error);
181 }
182 
183 vn_read(fp, uio, cred)
184 	struct file *fp;
185 	struct uio *uio;
186 	struct ucred *cred;
187 {
188 	register struct vnode *vp = (struct vnode *)fp->f_data;
189 	int count, error;
190 
191 	VOP_LOCK(vp);
192 	uio->uio_offset = fp->f_offset;
193 	count = uio->uio_resid;
194 	error = VOP_READ(vp, uio, (fp->f_flag & FNDELAY) ? IO_NDELAY : 0, cred);
195 	fp->f_offset += count - uio->uio_resid;
196 	VOP_UNLOCK(vp);
197 	return (error);
198 }
199 
200 vn_write(fp, uio, cred)
201 	struct file *fp;
202 	struct uio *uio;
203 	struct ucred *cred;
204 {
205 	register struct vnode *vp = (struct vnode *)fp->f_data;
206 	int count, error, ioflag = 0;
207 
208 	if (vp->v_type == VREG && (fp->f_flag & FAPPEND))
209 		ioflag |= IO_APPEND;
210 	if (fp->f_flag & FNDELAY)
211 		ioflag |= IO_NDELAY;
212 	VOP_LOCK(vp);
213 	uio->uio_offset = fp->f_offset;
214 	count = uio->uio_resid;
215 	error = VOP_WRITE(vp, uio, ioflag, cred);
216 	if (ioflag & IO_APPEND)
217 		fp->f_offset = uio->uio_offset;
218 	else
219 		fp->f_offset += count - uio->uio_resid;
220 	VOP_UNLOCK(vp);
221 	return (error);
222 }
223 
224 /*
225  * Get stat info for a vnode.
226  */
227 vn_stat(vp, sb)
228 	struct vnode *vp;
229 	register struct stat *sb;
230 {
231 	struct vattr vattr;
232 	register struct vattr *vap;
233 	int error;
234 	u_short mode;
235 
236 	vap = &vattr;
237 	error = VOP_GETATTR(vp, vap, u.u_cred);
238 	if (error)
239 		return (error);
240 	/*
241 	 * Copy from vattr table
242 	 */
243 	sb->st_dev = vap->va_fsid;
244 	sb->st_ino = vap->va_fileid;
245 	mode = vap->va_mode;
246 	switch (vp->v_type) {
247 	case VREG:
248 		mode |= S_IFREG;
249 		break;
250 	case VDIR:
251 		mode |= S_IFDIR;
252 		break;
253 	case VBLK:
254 		mode |= S_IFBLK;
255 		break;
256 	case VCHR:
257 		mode |= S_IFCHR;
258 		break;
259 	case VLNK:
260 		mode |= S_IFLNK;
261 		break;
262 	case VSOCK:
263 		mode |= S_IFSOCK;
264 		break;
265 	case VFIFO:
266 		mode |= S_IFIFO;
267 		break;
268 	default:
269 		return (EBADF);
270 	};
271 	sb->st_mode = mode;
272 	sb->st_nlink = vap->va_nlink;
273 	sb->st_uid = vap->va_uid;
274 	sb->st_gid = vap->va_gid;
275 	sb->st_rdev = vap->va_rdev;
276 	sb->st_size = vap->va_size;
277 	sb->st_atime = vap->va_atime.tv_sec;
278 	sb->st_spare1 = 0;
279 	sb->st_mtime = vap->va_mtime.tv_sec;
280 	sb->st_spare2 = 0;
281 	sb->st_ctime = vap->va_ctime.tv_sec;
282 	sb->st_spare3 = 0;
283 	sb->st_blksize = vap->va_blocksize;
284 	sb->st_flags = vap->va_flags;
285 	sb->st_gen = vap->va_gen;
286 	sb->st_blocks = vap->va_bytes / S_BLKSIZE;
287 	return (0);
288 }
289 
290 /*
291  * Vnode ioctl call
292  */
293 vn_ioctl(fp, com, data)
294 	struct file *fp;
295 	int com;
296 	caddr_t data;
297 {
298 	register struct vnode *vp = ((struct vnode *)fp->f_data);
299 	struct vattr vattr;
300 	int error;
301 
302 	switch (vp->v_type) {
303 
304 	case VREG:
305 	case VDIR:
306 		if (com == FIONREAD) {
307 			if (error = VOP_GETATTR(vp, &vattr, u.u_cred))
308 				return (error);
309 			*(off_t *)data = vattr.va_size - fp->f_offset;
310 			return (0);
311 		}
312 		if (com == FIONBIO || com == FIOASYNC)	/* XXX */
313 			return (0);			/* XXX */
314 		/* fall into ... */
315 
316 	default:
317 		return (ENOTTY);
318 
319 	case VFIFO:
320 	case VCHR:
321 	case VBLK:
322 		error = VOP_IOCTL(vp, com, data, fp->f_flag, u.u_cred);
323 		if (error == 0 && com == TIOCSCTTY) {
324 			u.u_procp->p_session->s_ttyvp = vp;
325 			VREF(vp);
326 		}
327 		return (error);
328 	}
329 }
330 
331 /*
332  * Vnode select call
333  */
334 vn_select(fp, which)
335 	struct file *fp;
336 	int which;
337 {
338 	return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
339 		u.u_cred));
340 }
341 
342 /*
343  * Vnode close call
344  */
345 vn_close(fp)
346 	register struct file *fp;
347 {
348 	struct vnode *vp = ((struct vnode *)fp->f_data);
349 	int error;
350 
351 	if (fp->f_flag & (FSHLOCK|FEXLOCK))
352 		vn_unlock(fp, FSHLOCK|FEXLOCK);
353 	/*
354 	 * Must delete vnode reference from this file entry
355 	 * before VOP_CLOSE, so that only other references
356 	 * will prevent close.
357 	 */
358 	fp->f_data = (caddr_t) 0;
359 	error = VOP_CLOSE(vp, fp->f_flag, u.u_cred);
360 	vrele(vp);
361 	return (error);
362 }
363 
364 /*
365  * Place an advisory lock on a vnode.
366  * !! THIS IMPLIES THAT ALL STATEFUL FILE SERVERS WILL USE file table entries
367  */
368 vn_lock(fp, cmd)
369 	register struct file *fp;
370 	int cmd;
371 {
372 	register int priority = PLOCK;
373 	register struct vnode *vp = (struct vnode *)fp->f_data;
374 	int error = 0;
375 	static char lockstr[] = "flock";
376 
377 	if ((cmd & LOCK_EX) == 0)
378 		priority += 4;
379 	priority |= PCATCH;
380 
381 	/*
382 	 * If there's a exclusive lock currently applied
383 	 * to the file, then we've gotta wait for the
384 	 * lock with everyone else.
385 	 */
386 again:
387 	while (vp->v_flag & VEXLOCK) {
388 		/*
389 		 * If we're holding an exclusive
390 		 * lock, then release it.
391 		 */
392 		if (fp->f_flag & FEXLOCK) {
393 			vn_unlock(fp, FEXLOCK);
394 			continue;
395 		}
396 		if (cmd & LOCK_NB)
397 			return (EWOULDBLOCK);
398 		vp->v_flag |= VLWAIT;
399 		if (error = tsleep((caddr_t)&vp->v_exlockc, priority,
400 		    lockstr, 0))
401 			return (error);
402 	}
403 	if (error = 0 && (cmd & LOCK_EX) && (vp->v_flag & VSHLOCK)) {
404 		/*
405 		 * Must wait for any shared locks to finish
406 		 * before we try to apply a exclusive lock.
407 		 *
408 		 * If we're holding a shared
409 		 * lock, then release it.
410 		 */
411 		if (fp->f_flag & FSHLOCK) {
412 			vn_unlock(fp, FSHLOCK);
413 			goto again;
414 		}
415 		if (cmd & LOCK_NB)
416 			return (EWOULDBLOCK);
417 		vp->v_flag |= VLWAIT;
418 		if (error = tsleep((caddr_t)&vp->v_shlockc, PLOCK | PCATCH,
419 		    lockstr, 0) == 0)
420 			return (error);
421 	}
422 	if (fp->f_flag & FEXLOCK)
423 		panic("vn_lock");
424 	if (cmd & LOCK_EX) {
425 		cmd &= ~LOCK_SH;
426 		vp->v_exlockc++;
427 		vp->v_flag |= VEXLOCK;
428 		fp->f_flag |= FEXLOCK;
429 	}
430 	if ((cmd & LOCK_SH) && (fp->f_flag & FSHLOCK) == 0) {
431 		vp->v_shlockc++;
432 		vp->v_flag |= VSHLOCK;
433 		fp->f_flag |= FSHLOCK;
434 	}
435 	return (0);
436 }
437 
438 /*
439  * Unlock a file.
440  */
441 vn_unlock(fp, kind)
442 	register struct file *fp;
443 	int kind;
444 {
445 	register struct vnode *vp = (struct vnode *)fp->f_data;
446 	int flags;
447 
448 	kind &= fp->f_flag;
449 	if (vp == NULL || kind == 0)
450 		return;
451 	flags = vp->v_flag;
452 	if (kind & FSHLOCK) {
453 		if ((flags & VSHLOCK) == 0)
454 			panic("vn_unlock: SHLOCK");
455 		if (--vp->v_shlockc == 0) {
456 			vp->v_flag &= ~VSHLOCK;
457 			if (flags & VLWAIT)
458 				wakeup((caddr_t)&vp->v_shlockc);
459 		}
460 		fp->f_flag &= ~FSHLOCK;
461 	}
462 	if (kind & FEXLOCK) {
463 		if ((flags & VEXLOCK) == 0)
464 			panic("vn_unlock: EXLOCK");
465 		if (--vp->v_exlockc == 0) {
466 			vp->v_flag &= ~(VEXLOCK|VLWAIT);
467 			if (flags & VLWAIT)
468 				wakeup((caddr_t)&vp->v_exlockc);
469 		}
470 		fp->f_flag &= ~FEXLOCK;
471 	}
472 }
473 
474 /*
475  * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
476  * 	- look up fsid in mount list (if not found ret error)
477  *	- get vp by calling VFS_FHTOVP() macro
478  *	- if lockflag lock it with VOP_LOCK()
479  */
480 vn_fhtovp(fhp, lockflag, vpp)
481 	fhandle_t *fhp;
482 	int lockflag;
483 	struct vnode **vpp;
484 {
485 	register struct mount *mp;
486 
487 	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
488 		return (ESTALE);
489 	if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
490 		return (ESTALE);
491 	if (!lockflag)
492 		VOP_UNLOCK(*vpp);
493 	return (0);
494 }
495 
496 /*
497  * Noop
498  */
499 vfs_noop()
500 {
501 
502 	return (ENXIO);
503 }
504 
505 /*
506  * Null op
507  */
508 vfs_nullop()
509 {
510 
511 	return (0);
512 }
513