xref: /freebsd/sys/fs/tmpfs/tmpfs_vnops.c (revision 54ebdd631db8c0bba2baab0155f603a8b5cf014a)
1 /*	$NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9  * 2005 program.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * tmpfs vnode interface.
35  */
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 #include <sys/param.h>
40 #include <sys/fcntl.h>
41 #include <sys/lockf.h>
42 #include <sys/namei.h>
43 #include <sys/priv.h>
44 #include <sys/proc.h>
45 #include <sys/resourcevar.h>
46 #include <sys/stat.h>
47 #include <sys/systm.h>
48 #include <sys/unistd.h>
49 #include <sys/vnode.h>
50 
51 #include <vm/vm.h>
52 #include <vm/vm_object.h>
53 #include <vm/vm_page.h>
54 #include <vm/vm_pager.h>
55 #include <sys/sched.h>
56 #include <sys/sf_buf.h>
57 #include <machine/_inttypes.h>
58 
59 #include <fs/fifofs/fifo.h>
60 #include <fs/tmpfs/tmpfs_vnops.h>
61 #include <fs/tmpfs/tmpfs.h>
62 
63 /* --------------------------------------------------------------------- */
64 
65 static int
66 tmpfs_lookup(struct vop_cachedlookup_args *v)
67 {
68 	struct vnode *dvp = v->a_dvp;
69 	struct vnode **vpp = v->a_vpp;
70 	struct componentname *cnp = v->a_cnp;
71 	struct thread *td = cnp->cn_thread;
72 
73 	int error;
74 	struct tmpfs_dirent *de;
75 	struct tmpfs_node *dnode;
76 
77 	dnode = VP_TO_TMPFS_DIR(dvp);
78 	*vpp = NULLVP;
79 
80 	/* Check accessibility of requested node as a first step. */
81 	error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td);
82 	if (error != 0)
83 		goto out;
84 
85 	/* We cannot be requesting the parent directory of the root node. */
86 	MPASS(IMPLIES(dnode->tn_type == VDIR &&
87 	    dnode->tn_dir.tn_parent == dnode,
88 	    !(cnp->cn_flags & ISDOTDOT)));
89 
90 	if (cnp->cn_flags & ISDOTDOT) {
91 		int ltype = 0;
92 
93 		ltype = VOP_ISLOCKED(dvp);
94 		vhold(dvp);
95 		VOP_UNLOCK(dvp, 0);
96 		/* Allocate a new vnode on the matching entry. */
97 		error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent,
98 		    cnp->cn_lkflags, vpp, td);
99 
100 		vn_lock(dvp, ltype | LK_RETRY);
101 		vdrop(dvp);
102 	} else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
103 		VREF(dvp);
104 		*vpp = dvp;
105 		error = 0;
106 	} else {
107 		de = tmpfs_dir_lookup(dnode, cnp);
108 		if (de == NULL) {
109 			/* The entry was not found in the directory.
110 			 * This is OK if we are creating or renaming an
111 			 * entry and are working on the last component of
112 			 * the path name. */
113 			if ((cnp->cn_flags & ISLASTCN) &&
114 			    (cnp->cn_nameiop == CREATE || \
115 			    cnp->cn_nameiop == RENAME)) {
116 				error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
117 				    cnp->cn_thread);
118 				if (error != 0)
119 					goto out;
120 
121 				/* Keep the component name in the buffer for
122 				 * future uses. */
123 				cnp->cn_flags |= SAVENAME;
124 
125 				error = EJUSTRETURN;
126 			} else
127 				error = ENOENT;
128 		} else {
129 			struct tmpfs_node *tnode;
130 
131 			/* The entry was found, so get its associated
132 			 * tmpfs_node. */
133 			tnode = de->td_node;
134 
135 			/* If we are not at the last path component and
136 			 * found a non-directory or non-link entry (which
137 			 * may itself be pointing to a directory), raise
138 			 * an error. */
139 			if ((tnode->tn_type != VDIR &&
140 			    tnode->tn_type != VLNK) &&
141 			    !(cnp->cn_flags & ISLASTCN)) {
142 				error = ENOTDIR;
143 				goto out;
144 			}
145 
146 			/* If we are deleting or renaming the entry, keep
147 			 * track of its tmpfs_dirent so that it can be
148 			 * easily deleted later. */
149 			if ((cnp->cn_flags & ISLASTCN) &&
150 			    (cnp->cn_nameiop == DELETE ||
151 			    cnp->cn_nameiop == RENAME)) {
152 				error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
153 				    cnp->cn_thread);
154 				if (error != 0)
155 					goto out;
156 
157 				/* Allocate a new vnode on the matching entry. */
158 				error = tmpfs_alloc_vp(dvp->v_mount, tnode,
159 						cnp->cn_lkflags, vpp, td);
160 				if (error != 0)
161 					goto out;
162 
163 				if ((dnode->tn_mode & S_ISTXT) &&
164 				  VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, cnp->cn_thread) &&
165 				  VOP_ACCESS(*vpp, VADMIN, cnp->cn_cred, cnp->cn_thread)) {
166 					error = EPERM;
167 					vput(*vpp);
168 					*vpp = NULL;
169 					goto out;
170 				}
171 				cnp->cn_flags |= SAVENAME;
172 			} else {
173 				error = tmpfs_alloc_vp(dvp->v_mount, tnode,
174 						cnp->cn_lkflags, vpp, td);
175 			}
176 		}
177 	}
178 
179 	/* Store the result of this lookup in the cache.  Avoid this if the
180 	 * request was for creation, as it does not improve timings on
181 	 * emprical tests. */
182 	if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE)
183 		cache_enter(dvp, *vpp, cnp);
184 
185 out:
186 	/* If there were no errors, *vpp cannot be null and it must be
187 	 * locked. */
188 	MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp)));
189 
190 	return error;
191 }
192 
193 /* --------------------------------------------------------------------- */
194 
195 static int
196 tmpfs_create(struct vop_create_args *v)
197 {
198 	struct vnode *dvp = v->a_dvp;
199 	struct vnode **vpp = v->a_vpp;
200 	struct componentname *cnp = v->a_cnp;
201 	struct vattr *vap = v->a_vap;
202 
203 	MPASS(vap->va_type == VREG || vap->va_type == VSOCK);
204 
205 	return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
206 }
207 /* --------------------------------------------------------------------- */
208 
209 static int
210 tmpfs_mknod(struct vop_mknod_args *v)
211 {
212 	struct vnode *dvp = v->a_dvp;
213 	struct vnode **vpp = v->a_vpp;
214 	struct componentname *cnp = v->a_cnp;
215 	struct vattr *vap = v->a_vap;
216 
217 	if (vap->va_type != VBLK && vap->va_type != VCHR &&
218 	    vap->va_type != VFIFO)
219 		return EINVAL;
220 
221 	return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
222 }
223 
224 /* --------------------------------------------------------------------- */
225 
226 static int
227 tmpfs_open(struct vop_open_args *v)
228 {
229 	struct vnode *vp = v->a_vp;
230 	int mode = v->a_mode;
231 
232 	int error;
233 	struct tmpfs_node *node;
234 
235 	MPASS(VOP_ISLOCKED(vp));
236 
237 	node = VP_TO_TMPFS_NODE(vp);
238 
239 	/* The file is still active but all its names have been removed
240 	 * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
241 	 * it is about to die. */
242 	if (node->tn_links < 1)
243 		return (ENOENT);
244 
245 	/* If the file is marked append-only, deny write requests. */
246 	if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
247 		error = EPERM;
248 	else {
249 		error = 0;
250 		vnode_create_vobject(vp, node->tn_size, v->a_td);
251 	}
252 
253 	MPASS(VOP_ISLOCKED(vp));
254 	return error;
255 }
256 
257 /* --------------------------------------------------------------------- */
258 
259 static int
260 tmpfs_close(struct vop_close_args *v)
261 {
262 	struct vnode *vp = v->a_vp;
263 
264 	struct tmpfs_node *node;
265 
266 	MPASS(VOP_ISLOCKED(vp));
267 
268 	node = VP_TO_TMPFS_NODE(vp);
269 
270 	if (node->tn_links > 0) {
271 		/* Update node times.  No need to do it if the node has
272 		 * been deleted, because it will vanish after we return. */
273 		tmpfs_update(vp);
274 	}
275 
276 	return 0;
277 }
278 
279 /* --------------------------------------------------------------------- */
280 
281 int
282 tmpfs_access(struct vop_access_args *v)
283 {
284 	struct vnode *vp = v->a_vp;
285 	accmode_t accmode = v->a_accmode;
286 	struct ucred *cred = v->a_cred;
287 
288 	int error;
289 	struct tmpfs_node *node;
290 
291 	MPASS(VOP_ISLOCKED(vp));
292 
293 	node = VP_TO_TMPFS_NODE(vp);
294 
295 	switch (vp->v_type) {
296 	case VDIR:
297 		/* FALLTHROUGH */
298 	case VLNK:
299 		/* FALLTHROUGH */
300 	case VREG:
301 		if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
302 			error = EROFS;
303 			goto out;
304 		}
305 		break;
306 
307 	case VBLK:
308 		/* FALLTHROUGH */
309 	case VCHR:
310 		/* FALLTHROUGH */
311 	case VSOCK:
312 		/* FALLTHROUGH */
313 	case VFIFO:
314 		break;
315 
316 	default:
317 		error = EINVAL;
318 		goto out;
319 	}
320 
321 	if (accmode & VWRITE && node->tn_flags & IMMUTABLE) {
322 		error = EPERM;
323 		goto out;
324 	}
325 
326 	error = vaccess(vp->v_type, node->tn_mode, node->tn_uid,
327 	    node->tn_gid, accmode, cred, NULL);
328 
329 out:
330 	MPASS(VOP_ISLOCKED(vp));
331 
332 	return error;
333 }
334 
335 /* --------------------------------------------------------------------- */
336 
337 int
338 tmpfs_getattr(struct vop_getattr_args *v)
339 {
340 	struct vnode *vp = v->a_vp;
341 	struct vattr *vap = v->a_vap;
342 
343 	struct tmpfs_node *node;
344 
345 	node = VP_TO_TMPFS_NODE(vp);
346 
347 	tmpfs_update(vp);
348 
349 	vap->va_type = vp->v_type;
350 	vap->va_mode = node->tn_mode;
351 	vap->va_nlink = node->tn_links;
352 	vap->va_uid = node->tn_uid;
353 	vap->va_gid = node->tn_gid;
354 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
355 	vap->va_fileid = node->tn_id;
356 	vap->va_size = node->tn_size;
357 	vap->va_blocksize = PAGE_SIZE;
358 	vap->va_atime = node->tn_atime;
359 	vap->va_mtime = node->tn_mtime;
360 	vap->va_ctime = node->tn_ctime;
361 	vap->va_birthtime = node->tn_birthtime;
362 	vap->va_gen = node->tn_gen;
363 	vap->va_flags = node->tn_flags;
364 	vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
365 		node->tn_rdev : NODEV;
366 	vap->va_bytes = round_page(node->tn_size);
367 	vap->va_filerev = 0;
368 
369 	return 0;
370 }
371 
372 /* --------------------------------------------------------------------- */
373 
374 /* XXX Should this operation be atomic?  I think it should, but code in
375  * XXX other places (e.g., ufs) doesn't seem to be... */
376 int
377 tmpfs_setattr(struct vop_setattr_args *v)
378 {
379 	struct vnode *vp = v->a_vp;
380 	struct vattr *vap = v->a_vap;
381 	struct ucred *cred = v->a_cred;
382 	struct thread *td = curthread;
383 
384 	int error;
385 
386 	MPASS(VOP_ISLOCKED(vp));
387 
388 	error = 0;
389 
390 	/* Abort if any unsettable attribute is given. */
391 	if (vap->va_type != VNON ||
392 	    vap->va_nlink != VNOVAL ||
393 	    vap->va_fsid != VNOVAL ||
394 	    vap->va_fileid != VNOVAL ||
395 	    vap->va_blocksize != VNOVAL ||
396 	    vap->va_gen != VNOVAL ||
397 	    vap->va_rdev != VNOVAL ||
398 	    vap->va_bytes != VNOVAL)
399 		error = EINVAL;
400 
401 	if (error == 0 && (vap->va_flags != VNOVAL))
402 		error = tmpfs_chflags(vp, vap->va_flags, cred, td);
403 
404 	if (error == 0 && (vap->va_size != VNOVAL))
405 		error = tmpfs_chsize(vp, vap->va_size, cred, td);
406 
407 	if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
408 		error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td);
409 
410 	if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
411 		error = tmpfs_chmod(vp, vap->va_mode, cred, td);
412 
413 	if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
414 	    vap->va_atime.tv_nsec != VNOVAL) ||
415 	    (vap->va_mtime.tv_sec != VNOVAL &&
416 	    vap->va_mtime.tv_nsec != VNOVAL) ||
417 	    (vap->va_birthtime.tv_sec != VNOVAL &&
418 	    vap->va_birthtime.tv_nsec != VNOVAL)))
419 		error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
420 			&vap->va_birthtime, vap->va_vaflags, cred, td);
421 
422 	/* Update the node times.  We give preference to the error codes
423 	 * generated by this function rather than the ones that may arise
424 	 * from tmpfs_update. */
425 	tmpfs_update(vp);
426 
427 	MPASS(VOP_ISLOCKED(vp));
428 
429 	return error;
430 }
431 
432 /* --------------------------------------------------------------------- */
433 
434 static int
435 tmpfs_mappedread(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio)
436 {
437 	vm_pindex_t	idx;
438 	vm_page_t	m;
439 	struct sf_buf	*sf;
440 	off_t		offset, addr;
441 	size_t		tlen;
442 	caddr_t		va;
443 	int		error;
444 
445 	addr = uio->uio_offset;
446 	idx = OFF_TO_IDX(addr);
447 	offset = addr & PAGE_MASK;
448 	tlen = MIN(PAGE_SIZE - offset, len);
449 
450 	if ((vobj == NULL) || (vobj->resident_page_count == 0))
451 		goto nocache;
452 
453 	VM_OBJECT_LOCK(vobj);
454 lookupvpg:
455 	if (((m = vm_page_lookup(vobj, idx)) != NULL) &&
456 	    vm_page_is_valid(m, offset, tlen)) {
457 		if (vm_page_sleep_if_busy(m, FALSE, "tmfsmr"))
458 			goto lookupvpg;
459 		vm_page_busy(m);
460 		VM_OBJECT_UNLOCK(vobj);
461 		sched_pin();
462 		sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
463 		va = (caddr_t)sf_buf_kva(sf);
464 		error = uiomove(va + offset, tlen, uio);
465 		sf_buf_free(sf);
466 		sched_unpin();
467 		VM_OBJECT_LOCK(vobj);
468 		vm_page_wakeup(m);
469 		VM_OBJECT_UNLOCK(vobj);
470 		return	(error);
471 	}
472 	VM_OBJECT_UNLOCK(vobj);
473 nocache:
474 	VM_OBJECT_LOCK(tobj);
475 	vm_object_pip_add(tobj, 1);
476 	m = vm_page_grab(tobj, idx, VM_ALLOC_WIRED |
477 	    VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
478 	if (m->valid != VM_PAGE_BITS_ALL) {
479 		int behind, ahead;
480 		if (vm_pager_has_page(tobj, idx, &behind, &ahead)) {
481 			error = vm_pager_get_pages(tobj, &m, 1, 0);
482 			if (error != 0) {
483 				printf("tmpfs get pages from pager error [read]\n");
484 				goto out;
485 			}
486 		} else
487 			vm_page_zero_invalid(m, TRUE);
488 	}
489 	VM_OBJECT_UNLOCK(tobj);
490 	sched_pin();
491 	sf = sf_buf_alloc(m, SFB_CPUPRIVATE);
492 	va = (caddr_t)sf_buf_kva(sf);
493 	error = uiomove(va + offset, tlen, uio);
494 	sf_buf_free(sf);
495 	sched_unpin();
496 	VM_OBJECT_LOCK(tobj);
497 out:
498 	vm_page_lock_queues();
499 	vm_page_unwire(m, 0);
500 	vm_page_activate(m);
501 	vm_page_unlock_queues();
502 	vm_page_wakeup(m);
503 	vm_object_pip_subtract(tobj, 1);
504 	VM_OBJECT_UNLOCK(tobj);
505 
506 	return	(error);
507 }
508 
509 static int
510 tmpfs_read(struct vop_read_args *v)
511 {
512 	struct vnode *vp = v->a_vp;
513 	struct uio *uio = v->a_uio;
514 
515 	struct tmpfs_node *node;
516 	vm_object_t uobj;
517 	size_t len;
518 	int resid;
519 
520 	int error = 0;
521 
522 	node = VP_TO_TMPFS_NODE(vp);
523 
524 	if (vp->v_type != VREG) {
525 		error = EISDIR;
526 		goto out;
527 	}
528 
529 	if (uio->uio_offset < 0) {
530 		error = EINVAL;
531 		goto out;
532 	}
533 
534 	node->tn_status |= TMPFS_NODE_ACCESSED;
535 
536 	uobj = node->tn_reg.tn_aobj;
537 	while ((resid = uio->uio_resid) > 0) {
538 		error = 0;
539 		if (node->tn_size <= uio->uio_offset)
540 			break;
541 		len = MIN(node->tn_size - uio->uio_offset, resid);
542 		if (len == 0)
543 			break;
544 		error = tmpfs_mappedread(vp->v_object, uobj, len, uio);
545 		if ((error != 0) || (resid == uio->uio_resid))
546 			break;
547 	}
548 
549 out:
550 
551 	return error;
552 }
553 
554 /* --------------------------------------------------------------------- */
555 
556 static int
557 tmpfs_mappedwrite(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio)
558 {
559 	vm_pindex_t	idx;
560 	vm_page_t	vpg, tpg;
561 	struct sf_buf	*sf;
562 	off_t		offset, addr;
563 	size_t		tlen;
564 	caddr_t		va;
565 	int		error;
566 
567 	error = 0;
568 
569 	addr = uio->uio_offset;
570 	idx = OFF_TO_IDX(addr);
571 	offset = addr & PAGE_MASK;
572 	tlen = MIN(PAGE_SIZE - offset, len);
573 
574 	if ((vobj == NULL) || (vobj->resident_page_count == 0)) {
575 		vpg = NULL;
576 		goto nocache;
577 	}
578 
579 	VM_OBJECT_LOCK(vobj);
580 lookupvpg:
581 	if (((vpg = vm_page_lookup(vobj, idx)) != NULL) &&
582 	    vm_page_is_valid(vpg, offset, tlen)) {
583 		if (vm_page_sleep_if_busy(vpg, FALSE, "tmfsmw"))
584 			goto lookupvpg;
585 		vm_page_busy(vpg);
586 		vm_page_lock_queues();
587 		vm_page_undirty(vpg);
588 		vm_page_unlock_queues();
589 		VM_OBJECT_UNLOCK(vobj);
590 		sched_pin();
591 		sf = sf_buf_alloc(vpg, SFB_CPUPRIVATE);
592 		va = (caddr_t)sf_buf_kva(sf);
593 		error = uiomove(va + offset, tlen, uio);
594 		sf_buf_free(sf);
595 		sched_unpin();
596 	} else {
597 		VM_OBJECT_UNLOCK(vobj);
598 		vpg = NULL;
599 	}
600 nocache:
601 	VM_OBJECT_LOCK(tobj);
602 	vm_object_pip_add(tobj, 1);
603 	tpg = vm_page_grab(tobj, idx, VM_ALLOC_WIRED |
604 	    VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
605 	if (tpg->valid != VM_PAGE_BITS_ALL) {
606 		int behind, ahead;
607 		if (vm_pager_has_page(tobj, idx, &behind, &ahead)) {
608 			error = vm_pager_get_pages(tobj, &tpg, 1, 0);
609 			if (error != 0) {
610 				printf("tmpfs get pages from pager error [write]\n");
611 				goto out;
612 			}
613 		} else
614 			vm_page_zero_invalid(tpg, TRUE);
615 	}
616 	VM_OBJECT_UNLOCK(tobj);
617 	if (vpg == NULL) {
618 		sched_pin();
619 		sf = sf_buf_alloc(tpg, SFB_CPUPRIVATE);
620 		va = (caddr_t)sf_buf_kva(sf);
621 		error = uiomove(va + offset, tlen, uio);
622 		sf_buf_free(sf);
623 		sched_unpin();
624 	} else {
625 		KASSERT(vpg->valid == VM_PAGE_BITS_ALL, ("parts of vpg invalid"));
626 		pmap_copy_page(vpg, tpg);
627 	}
628 	VM_OBJECT_LOCK(tobj);
629 out:
630 	if (vobj != NULL)
631 		VM_OBJECT_LOCK(vobj);
632 	vm_page_lock_queues();
633 	if (error == 0) {
634 		vm_page_set_validclean(tpg, offset, tlen);
635 		vm_page_zero_invalid(tpg, TRUE);
636 		vm_page_dirty(tpg);
637 	}
638 	vm_page_unwire(tpg, 0);
639 	vm_page_activate(tpg);
640 	vm_page_unlock_queues();
641 	vm_page_wakeup(tpg);
642 	if (vpg != NULL)
643 		vm_page_wakeup(vpg);
644 	if (vobj != NULL)
645 		VM_OBJECT_UNLOCK(vobj);
646 	vm_object_pip_subtract(tobj, 1);
647 	VM_OBJECT_UNLOCK(tobj);
648 
649 	return	(error);
650 }
651 
652 static int
653 tmpfs_write(struct vop_write_args *v)
654 {
655 	struct vnode *vp = v->a_vp;
656 	struct uio *uio = v->a_uio;
657 	int ioflag = v->a_ioflag;
658 	struct thread *td = uio->uio_td;
659 
660 	boolean_t extended;
661 	int error = 0;
662 	off_t oldsize;
663 	struct tmpfs_node *node;
664 	vm_object_t uobj;
665 	size_t len;
666 	int resid;
667 
668 	node = VP_TO_TMPFS_NODE(vp);
669 	oldsize = node->tn_size;
670 
671 	if (uio->uio_offset < 0 || vp->v_type != VREG) {
672 		error = EINVAL;
673 		goto out;
674 	}
675 
676 	if (uio->uio_resid == 0) {
677 		error = 0;
678 		goto out;
679 	}
680 
681 	if (ioflag & IO_APPEND)
682 		uio->uio_offset = node->tn_size;
683 
684 	if (uio->uio_offset + uio->uio_resid >
685 	  VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
686 		return (EFBIG);
687 
688 	if (vp->v_type == VREG && td != NULL) {
689 		PROC_LOCK(td->td_proc);
690 		if (uio->uio_offset + uio->uio_resid >
691 		  lim_cur(td->td_proc, RLIMIT_FSIZE)) {
692 			psignal(td->td_proc, SIGXFSZ);
693 			PROC_UNLOCK(td->td_proc);
694 			return (EFBIG);
695 		}
696 		PROC_UNLOCK(td->td_proc);
697 	}
698 
699 	extended = uio->uio_offset + uio->uio_resid > node->tn_size;
700 	if (extended) {
701 		error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid);
702 		if (error != 0)
703 			goto out;
704 	}
705 
706 	uobj = node->tn_reg.tn_aobj;
707 	while ((resid = uio->uio_resid) > 0) {
708 		if (node->tn_size <= uio->uio_offset)
709 			break;
710 		len = MIN(node->tn_size - uio->uio_offset, resid);
711 		if (len == 0)
712 			break;
713 		error = tmpfs_mappedwrite(vp->v_object, uobj, len, uio);
714 		if ((error != 0) || (resid == uio->uio_resid))
715 			break;
716 	}
717 
718 	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
719 	    (extended ? TMPFS_NODE_CHANGED : 0);
720 
721 	if (node->tn_mode & (S_ISUID | S_ISGID)) {
722 		if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0))
723 			node->tn_mode &= ~(S_ISUID | S_ISGID);
724 	}
725 
726 	if (error != 0)
727 		(void)tmpfs_reg_resize(vp, oldsize);
728 
729 out:
730 	MPASS(IMPLIES(error == 0, uio->uio_resid == 0));
731 	MPASS(IMPLIES(error != 0, oldsize == node->tn_size));
732 
733 	return error;
734 }
735 
736 /* --------------------------------------------------------------------- */
737 
738 static int
739 tmpfs_fsync(struct vop_fsync_args *v)
740 {
741 	struct vnode *vp = v->a_vp;
742 
743 	MPASS(VOP_ISLOCKED(vp));
744 
745 	tmpfs_update(vp);
746 
747 	return 0;
748 }
749 
750 /* --------------------------------------------------------------------- */
751 
752 static int
753 tmpfs_remove(struct vop_remove_args *v)
754 {
755 	struct vnode *dvp = v->a_dvp;
756 	struct vnode *vp = v->a_vp;
757 
758 	int error;
759 	struct tmpfs_dirent *de;
760 	struct tmpfs_mount *tmp;
761 	struct tmpfs_node *dnode;
762 	struct tmpfs_node *node;
763 
764 	MPASS(VOP_ISLOCKED(dvp));
765 	MPASS(VOP_ISLOCKED(vp));
766 
767 	if (vp->v_type == VDIR) {
768 		error = EISDIR;
769 		goto out;
770 	}
771 
772 	dnode = VP_TO_TMPFS_DIR(dvp);
773 	node = VP_TO_TMPFS_NODE(vp);
774 	tmp = VFS_TO_TMPFS(vp->v_mount);
775 	de = tmpfs_dir_search(dnode, node);
776 	MPASS(de != NULL);
777 
778 	/* Files marked as immutable or append-only cannot be deleted. */
779 	if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
780 	    (dnode->tn_flags & APPEND)) {
781 		error = EPERM;
782 		goto out;
783 	}
784 
785 	/* Remove the entry from the directory; as it is a file, we do not
786 	 * have to change the number of hard links of the directory. */
787 	tmpfs_dir_detach(dvp, de);
788 
789 	/* Free the directory entry we just deleted.  Note that the node
790 	 * referred by it will not be removed until the vnode is really
791 	 * reclaimed. */
792 	tmpfs_free_dirent(tmp, de, TRUE);
793 
794 	if (node->tn_links > 0)
795 		node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
796 	    TMPFS_NODE_MODIFIED;
797 	error = 0;
798 
799 out:
800 
801 	return error;
802 }
803 
804 /* --------------------------------------------------------------------- */
805 
806 static int
807 tmpfs_link(struct vop_link_args *v)
808 {
809 	struct vnode *dvp = v->a_tdvp;
810 	struct vnode *vp = v->a_vp;
811 	struct componentname *cnp = v->a_cnp;
812 
813 	int error;
814 	struct tmpfs_dirent *de;
815 	struct tmpfs_node *node;
816 
817 	MPASS(VOP_ISLOCKED(dvp));
818 	MPASS(cnp->cn_flags & HASBUF);
819 	MPASS(dvp != vp); /* XXX When can this be false? */
820 
821 	node = VP_TO_TMPFS_NODE(vp);
822 
823 	/* XXX: Why aren't the following two tests done by the caller? */
824 
825 	/* Hard links of directories are forbidden. */
826 	if (vp->v_type == VDIR) {
827 		error = EPERM;
828 		goto out;
829 	}
830 
831 	/* Cannot create cross-device links. */
832 	if (dvp->v_mount != vp->v_mount) {
833 		error = EXDEV;
834 		goto out;
835 	}
836 
837 	/* Ensure that we do not overflow the maximum number of links imposed
838 	 * by the system. */
839 	MPASS(node->tn_links <= LINK_MAX);
840 	if (node->tn_links == LINK_MAX) {
841 		error = EMLINK;
842 		goto out;
843 	}
844 
845 	/* We cannot create links of files marked immutable or append-only. */
846 	if (node->tn_flags & (IMMUTABLE | APPEND)) {
847 		error = EPERM;
848 		goto out;
849 	}
850 
851 	/* Allocate a new directory entry to represent the node. */
852 	error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
853 	    cnp->cn_nameptr, cnp->cn_namelen, &de);
854 	if (error != 0)
855 		goto out;
856 
857 	/* Insert the new directory entry into the appropriate directory. */
858 	tmpfs_dir_attach(dvp, de);
859 
860 	/* vp link count has changed, so update node times. */
861 	node->tn_status |= TMPFS_NODE_CHANGED;
862 	tmpfs_update(vp);
863 
864 	error = 0;
865 
866 out:
867 	return error;
868 }
869 
870 /* --------------------------------------------------------------------- */
871 
872 static int
873 tmpfs_rename(struct vop_rename_args *v)
874 {
875 	struct vnode *fdvp = v->a_fdvp;
876 	struct vnode *fvp = v->a_fvp;
877 	struct componentname *fcnp = v->a_fcnp;
878 	struct vnode *tdvp = v->a_tdvp;
879 	struct vnode *tvp = v->a_tvp;
880 	struct componentname *tcnp = v->a_tcnp;
881 
882 	char *newname;
883 	int error;
884 	struct tmpfs_dirent *de;
885 	struct tmpfs_node *fdnode;
886 	struct tmpfs_node *fnode;
887 	struct tmpfs_node *tnode;
888 	struct tmpfs_node *tdnode;
889 
890 	MPASS(VOP_ISLOCKED(tdvp));
891 	MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp)));
892 	MPASS(fcnp->cn_flags & HASBUF);
893 	MPASS(tcnp->cn_flags & HASBUF);
894 
895   	tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
896 
897 	/* Disallow cross-device renames.
898 	 * XXX Why isn't this done by the caller? */
899 	if (fvp->v_mount != tdvp->v_mount ||
900 	    (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
901 		error = EXDEV;
902 		goto out;
903 	}
904 
905 	tdnode = VP_TO_TMPFS_DIR(tdvp);
906 
907 	/* If source and target are the same file, there is nothing to do. */
908 	if (fvp == tvp) {
909 		error = 0;
910 		goto out;
911 	}
912 
913 	/* If we need to move the directory between entries, lock the
914 	 * source so that we can safely operate on it. */
915 	if (tdvp != fdvp) {
916 		error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
917 		if (error != 0)
918 			goto out;
919 	}
920 	fdnode = VP_TO_TMPFS_DIR(fdvp);
921 	fnode = VP_TO_TMPFS_NODE(fvp);
922 	de = tmpfs_dir_search(fdnode, fnode);
923 
924 	/* Avoid manipulating '.' and '..' entries. */
925 	if (de == NULL) {
926 		MPASS(fvp->v_type == VDIR);
927 		error = EINVAL;
928 		goto out_locked;
929 	}
930 	MPASS(de->td_node == fnode);
931 
932 	/* If re-naming a directory to another preexisting directory
933 	 * ensure that the target directory is empty so that its
934 	 * removal causes no side effects.
935 	 * Kern_rename gurantees the destination to be a directory
936 	 * if the source is one. */
937 	if (tvp != NULL) {
938 		MPASS(tnode != NULL);
939 
940 		if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
941 		    (tdnode->tn_flags & (APPEND | IMMUTABLE))) {
942 			error = EPERM;
943 			goto out_locked;
944 		}
945 
946 		if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
947 			if (tnode->tn_size > 0) {
948 				error = ENOTEMPTY;
949 				goto out_locked;
950 			}
951 		} else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
952 			error = ENOTDIR;
953 			goto out_locked;
954 		} else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
955 			error = EISDIR;
956 			goto out_locked;
957 		} else {
958 			MPASS(fnode->tn_type != VDIR &&
959 				tnode->tn_type != VDIR);
960 		}
961 	}
962 
963 	if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))
964 	    || (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
965 		error = EPERM;
966 		goto out_locked;
967 	}
968 
969 	/* Ensure that we have enough memory to hold the new name, if it
970 	 * has to be changed. */
971 	if (fcnp->cn_namelen != tcnp->cn_namelen ||
972 	    bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
973 		newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK);
974 	} else
975 		newname = NULL;
976 
977 	/* If the node is being moved to another directory, we have to do
978 	 * the move. */
979 	if (fdnode != tdnode) {
980 		/* In case we are moving a directory, we have to adjust its
981 		 * parent to point to the new parent. */
982 		if (de->td_node->tn_type == VDIR) {
983 			struct tmpfs_node *n;
984 
985 			/* Ensure the target directory is not a child of the
986 			 * directory being moved.  Otherwise, we'd end up
987 			 * with stale nodes. */
988 			n = tdnode;
989 			while (n != n->tn_dir.tn_parent) {
990 				if (n == fnode) {
991 					error = EINVAL;
992 					if (newname != NULL)
993 						    free(newname, M_TMPFSNAME);
994 					goto out_locked;
995 				}
996 				n = n->tn_dir.tn_parent;
997 			}
998 
999 			/* Adjust the parent pointer. */
1000 			TMPFS_VALIDATE_DIR(fnode);
1001 			de->td_node->tn_dir.tn_parent = tdnode;
1002 
1003 			/* As a result of changing the target of the '..'
1004 			 * entry, the link count of the source and target
1005 			 * directories has to be adjusted. */
1006 			fdnode->tn_links--;
1007 			tdnode->tn_links++;
1008 		}
1009 
1010 		/* Do the move: just remove the entry from the source directory
1011 		 * and insert it into the target one. */
1012 		tmpfs_dir_detach(fdvp, de);
1013 		tmpfs_dir_attach(tdvp, de);
1014 	}
1015 
1016 	/* If the name has changed, we need to make it effective by changing
1017 	 * it in the directory entry. */
1018 	if (newname != NULL) {
1019 		MPASS(tcnp->cn_namelen <= MAXNAMLEN);
1020 
1021 		free(de->td_name, M_TMPFSNAME);
1022 		de->td_namelen = (uint16_t)tcnp->cn_namelen;
1023 		memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen);
1024 		de->td_name = newname;
1025 
1026 		fnode->tn_status |= TMPFS_NODE_CHANGED;
1027 		tdnode->tn_status |= TMPFS_NODE_MODIFIED;
1028 	}
1029 
1030 	/* If we are overwriting an entry, we have to remove the old one
1031 	 * from the target directory. */
1032 	if (tvp != NULL) {
1033 		/* Remove the old entry from the target directory. */
1034 		de = tmpfs_dir_search(tdnode, tnode);
1035 		tmpfs_dir_detach(tdvp, de);
1036 
1037 		/* Free the directory entry we just deleted.  Note that the
1038 		 * node referred by it will not be removed until the vnode is
1039 		 * really reclaimed. */
1040 		tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE);
1041 	}
1042 
1043 	error = 0;
1044 
1045 out_locked:
1046 	if (fdnode != tdnode)
1047 		VOP_UNLOCK(fdvp, 0);
1048 
1049 out:
1050 	/* Release target nodes. */
1051 	/* XXX: I don't understand when tdvp can be the same as tvp, but
1052 	 * other code takes care of this... */
1053 	if (tdvp == tvp)
1054 		vrele(tdvp);
1055 	else
1056 		vput(tdvp);
1057 	if (tvp != NULL)
1058 		vput(tvp);
1059 
1060 	/* Release source nodes. */
1061 	vrele(fdvp);
1062 	vrele(fvp);
1063 
1064 	return error;
1065 }
1066 
1067 /* --------------------------------------------------------------------- */
1068 
1069 static int
1070 tmpfs_mkdir(struct vop_mkdir_args *v)
1071 {
1072 	struct vnode *dvp = v->a_dvp;
1073 	struct vnode **vpp = v->a_vpp;
1074 	struct componentname *cnp = v->a_cnp;
1075 	struct vattr *vap = v->a_vap;
1076 
1077 	MPASS(vap->va_type == VDIR);
1078 
1079 	return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
1080 }
1081 
1082 /* --------------------------------------------------------------------- */
1083 
1084 static int
1085 tmpfs_rmdir(struct vop_rmdir_args *v)
1086 {
1087 	struct vnode *dvp = v->a_dvp;
1088 	struct vnode *vp = v->a_vp;
1089 
1090 	int error;
1091 	struct tmpfs_dirent *de;
1092 	struct tmpfs_mount *tmp;
1093 	struct tmpfs_node *dnode;
1094 	struct tmpfs_node *node;
1095 
1096 	MPASS(VOP_ISLOCKED(dvp));
1097 	MPASS(VOP_ISLOCKED(vp));
1098 
1099 	tmp = VFS_TO_TMPFS(dvp->v_mount);
1100 	dnode = VP_TO_TMPFS_DIR(dvp);
1101 	node = VP_TO_TMPFS_DIR(vp);
1102 
1103 	/* Directories with more than two entries ('.' and '..') cannot be
1104 	 * removed. */
1105 	 if (node->tn_size > 0) {
1106 		 error = ENOTEMPTY;
1107 		 goto out;
1108 	 }
1109 
1110 	if ((dnode->tn_flags & APPEND)
1111 	    || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1112 		error = EPERM;
1113 		goto out;
1114 	}
1115 
1116 	/* This invariant holds only if we are not trying to remove "..".
1117 	  * We checked for that above so this is safe now. */
1118 	MPASS(node->tn_dir.tn_parent == dnode);
1119 
1120 	/* Get the directory entry associated with node (vp).  This was
1121 	 * filled by tmpfs_lookup while looking up the entry. */
1122 	de = tmpfs_dir_search(dnode, node);
1123 	MPASS(TMPFS_DIRENT_MATCHES(de,
1124 	    v->a_cnp->cn_nameptr,
1125 	    v->a_cnp->cn_namelen));
1126 
1127 	/* Check flags to see if we are allowed to remove the directory. */
1128 	if (dnode->tn_flags & APPEND
1129 		|| node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) {
1130 		error = EPERM;
1131 		goto out;
1132 	}
1133 
1134 	/* Detach the directory entry from the directory (dnode). */
1135 	tmpfs_dir_detach(dvp, de);
1136 
1137 	node->tn_links--;
1138 	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
1139 	    TMPFS_NODE_MODIFIED;
1140 	node->tn_dir.tn_parent->tn_links--;
1141 	node->tn_dir.tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \
1142 	    TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
1143 
1144 	cache_purge(dvp);
1145 	cache_purge(vp);
1146 
1147 	/* Free the directory entry we just deleted.  Note that the node
1148 	 * referred by it will not be removed until the vnode is really
1149 	 * reclaimed. */
1150 	tmpfs_free_dirent(tmp, de, TRUE);
1151 
1152 	/* Release the deleted vnode (will destroy the node, notify
1153 	 * interested parties and clean it from the cache). */
1154 
1155 	dnode->tn_status |= TMPFS_NODE_CHANGED;
1156 	tmpfs_update(dvp);
1157 
1158 	error = 0;
1159 
1160 out:
1161 	return error;
1162 }
1163 
1164 /* --------------------------------------------------------------------- */
1165 
1166 static int
1167 tmpfs_symlink(struct vop_symlink_args *v)
1168 {
1169 	struct vnode *dvp = v->a_dvp;
1170 	struct vnode **vpp = v->a_vpp;
1171 	struct componentname *cnp = v->a_cnp;
1172 	struct vattr *vap = v->a_vap;
1173 	char *target = v->a_target;
1174 
1175 #ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */
1176 	MPASS(vap->va_type == VLNK);
1177 #else
1178 	vap->va_type = VLNK;
1179 #endif
1180 
1181 	return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
1182 }
1183 
1184 /* --------------------------------------------------------------------- */
1185 
1186 static int
1187 tmpfs_readdir(struct vop_readdir_args *v)
1188 {
1189 	struct vnode *vp = v->a_vp;
1190 	struct uio *uio = v->a_uio;
1191 	int *eofflag = v->a_eofflag;
1192 	u_long **cookies = v->a_cookies;
1193 	int *ncookies = v->a_ncookies;
1194 
1195 	int error;
1196 	off_t startoff;
1197 	off_t cnt = 0;
1198 	struct tmpfs_node *node;
1199 
1200 	/* This operation only makes sense on directory nodes. */
1201 	if (vp->v_type != VDIR)
1202 		return ENOTDIR;
1203 
1204 	node = VP_TO_TMPFS_DIR(vp);
1205 
1206 	startoff = uio->uio_offset;
1207 
1208 	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
1209 		error = tmpfs_dir_getdotdent(node, uio);
1210 		if (error != 0)
1211 			goto outok;
1212 		cnt++;
1213 	}
1214 
1215 	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
1216 		error = tmpfs_dir_getdotdotdent(node, uio);
1217 		if (error != 0)
1218 			goto outok;
1219 		cnt++;
1220 	}
1221 
1222 	error = tmpfs_dir_getdents(node, uio, &cnt);
1223 
1224 outok:
1225 	MPASS(error >= -1);
1226 
1227 	if (error == -1)
1228 		error = 0;
1229 
1230 	if (eofflag != NULL)
1231 		*eofflag =
1232 		    (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
1233 
1234 	/* Update NFS-related variables. */
1235 	if (error == 0 && cookies != NULL && ncookies != NULL) {
1236 		off_t i;
1237 		off_t off = startoff;
1238 		struct tmpfs_dirent *de = NULL;
1239 
1240 		*ncookies = cnt;
1241 		*cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);
1242 
1243 		for (i = 0; i < cnt; i++) {
1244 			MPASS(off != TMPFS_DIRCOOKIE_EOF);
1245 			if (off == TMPFS_DIRCOOKIE_DOT) {
1246 				off = TMPFS_DIRCOOKIE_DOTDOT;
1247 			} else {
1248 				if (off == TMPFS_DIRCOOKIE_DOTDOT) {
1249 					de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
1250 				} else if (de != NULL) {
1251 					de = TAILQ_NEXT(de, td_entries);
1252 				} else {
1253 					de = tmpfs_dir_lookupbycookie(node,
1254 					    off);
1255 					MPASS(de != NULL);
1256 					de = TAILQ_NEXT(de, td_entries);
1257 				}
1258 				if (de == NULL)
1259 					off = TMPFS_DIRCOOKIE_EOF;
1260 				else
1261 					off = tmpfs_dircookie(de);
1262 			}
1263 
1264 			(*cookies)[i] = off;
1265 		}
1266 		MPASS(uio->uio_offset == off);
1267 	}
1268 
1269 	return error;
1270 }
1271 
1272 /* --------------------------------------------------------------------- */
1273 
1274 static int
1275 tmpfs_readlink(struct vop_readlink_args *v)
1276 {
1277 	struct vnode *vp = v->a_vp;
1278 	struct uio *uio = v->a_uio;
1279 
1280 	int error;
1281 	struct tmpfs_node *node;
1282 
1283 	MPASS(uio->uio_offset == 0);
1284 	MPASS(vp->v_type == VLNK);
1285 
1286 	node = VP_TO_TMPFS_NODE(vp);
1287 
1288 	error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
1289 	    uio);
1290 	node->tn_status |= TMPFS_NODE_ACCESSED;
1291 
1292 	return error;
1293 }
1294 
1295 /* --------------------------------------------------------------------- */
1296 
1297 static int
1298 tmpfs_inactive(struct vop_inactive_args *v)
1299 {
1300 	struct vnode *vp = v->a_vp;
1301 	struct thread *l = v->a_td;
1302 
1303 	struct tmpfs_node *node;
1304 
1305 	MPASS(VOP_ISLOCKED(vp));
1306 
1307 	node = VP_TO_TMPFS_NODE(vp);
1308 
1309 	if (node->tn_links == 0)
1310 		vrecycle(vp, l);
1311 
1312 	return 0;
1313 }
1314 
1315 /* --------------------------------------------------------------------- */
1316 
1317 int
1318 tmpfs_reclaim(struct vop_reclaim_args *v)
1319 {
1320 	struct vnode *vp = v->a_vp;
1321 
1322 	struct tmpfs_mount *tmp;
1323 	struct tmpfs_node *node;
1324 
1325 	node = VP_TO_TMPFS_NODE(vp);
1326 	tmp = VFS_TO_TMPFS(vp->v_mount);
1327 
1328 	vnode_destroy_vobject(vp);
1329 	cache_purge(vp);
1330 	tmpfs_free_vp(vp);
1331 
1332 	/* If the node referenced by this vnode was deleted by the user,
1333 	 * we must free its associated data structures (now that the vnode
1334 	 * is being reclaimed). */
1335 	if (node->tn_links == 0)
1336 		tmpfs_free_node(tmp, node);
1337 
1338 	MPASS(vp->v_data == NULL);
1339 	return 0;
1340 }
1341 
1342 /* --------------------------------------------------------------------- */
1343 
1344 static int
1345 tmpfs_print(struct vop_print_args *v)
1346 {
1347 	struct vnode *vp = v->a_vp;
1348 
1349 	struct tmpfs_node *node;
1350 
1351 	node = VP_TO_TMPFS_NODE(vp);
1352 
1353 	printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n",
1354 	    node, node->tn_flags, node->tn_links);
1355 	printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX
1356 	    ", status 0x%x\n",
1357 	    node->tn_mode, node->tn_uid, node->tn_gid,
1358 	    (uintmax_t)node->tn_size, node->tn_status);
1359 
1360 	if (vp->v_type == VFIFO)
1361 		fifo_printinfo(vp);
1362 
1363 	printf("\n");
1364 
1365 	return 0;
1366 }
1367 
1368 /* --------------------------------------------------------------------- */
1369 
1370 static int
1371 tmpfs_pathconf(struct vop_pathconf_args *v)
1372 {
1373 	int name = v->a_name;
1374 	register_t *retval = v->a_retval;
1375 
1376 	int error;
1377 
1378 	error = 0;
1379 
1380 	switch (name) {
1381 	case _PC_LINK_MAX:
1382 		*retval = LINK_MAX;
1383 		break;
1384 
1385 	case _PC_NAME_MAX:
1386 		*retval = NAME_MAX;
1387 		break;
1388 
1389 	case _PC_PATH_MAX:
1390 		*retval = PATH_MAX;
1391 		break;
1392 
1393 	case _PC_PIPE_BUF:
1394 		*retval = PIPE_BUF;
1395 		break;
1396 
1397 	case _PC_CHOWN_RESTRICTED:
1398 		*retval = 1;
1399 		break;
1400 
1401 	case _PC_NO_TRUNC:
1402 		*retval = 1;
1403 		break;
1404 
1405 	case _PC_SYNC_IO:
1406 		*retval = 1;
1407 		break;
1408 
1409 	case _PC_FILESIZEBITS:
1410 		*retval = 0; /* XXX Don't know which value should I return. */
1411 		break;
1412 
1413 	default:
1414 		error = EINVAL;
1415 	}
1416 
1417 	return error;
1418 }
1419 
1420 static int
1421 tmpfs_vptofh(struct vop_vptofh_args *ap)
1422 {
1423 	struct tmpfs_fid *tfhp;
1424 	struct tmpfs_node *node;
1425 
1426 	tfhp = (struct tmpfs_fid *)ap->a_fhp;
1427 	node = VP_TO_TMPFS_NODE(ap->a_vp);
1428 
1429 	tfhp->tf_len = sizeof(struct tmpfs_fid);
1430 	tfhp->tf_id = node->tn_id;
1431 	tfhp->tf_gen = node->tn_gen;
1432 
1433 	return (0);
1434 }
1435 
1436 /* --------------------------------------------------------------------- */
1437 
1438 /*
1439  * vnode operations vector used for files stored in a tmpfs file system.
1440  */
1441 struct vop_vector tmpfs_vnodeop_entries = {
1442 	.vop_default =			&default_vnodeops,
1443 	.vop_lookup =			vfs_cache_lookup,
1444 	.vop_cachedlookup =		tmpfs_lookup,
1445 	.vop_create =			tmpfs_create,
1446 	.vop_mknod =			tmpfs_mknod,
1447 	.vop_open =			tmpfs_open,
1448 	.vop_close =			tmpfs_close,
1449 	.vop_access =			tmpfs_access,
1450 	.vop_getattr =			tmpfs_getattr,
1451 	.vop_setattr =			tmpfs_setattr,
1452 	.vop_read =			tmpfs_read,
1453 	.vop_write =			tmpfs_write,
1454 	.vop_fsync =			tmpfs_fsync,
1455 	.vop_remove =			tmpfs_remove,
1456 	.vop_link =			tmpfs_link,
1457 	.vop_rename =			tmpfs_rename,
1458 	.vop_mkdir =			tmpfs_mkdir,
1459 	.vop_rmdir =			tmpfs_rmdir,
1460 	.vop_symlink =			tmpfs_symlink,
1461 	.vop_readdir =			tmpfs_readdir,
1462 	.vop_readlink =			tmpfs_readlink,
1463 	.vop_inactive =			tmpfs_inactive,
1464 	.vop_reclaim =			tmpfs_reclaim,
1465 	.vop_print =			tmpfs_print,
1466 	.vop_pathconf =			tmpfs_pathconf,
1467 	.vop_vptofh =			tmpfs_vptofh,
1468 	.vop_bmap =			VOP_EOPNOTSUPP,
1469 };
1470 
1471