xref: /dflybsd-src/sys/vfs/tmpfs/tmpfs_vnops.c (revision ee65b806ac08b188bcab21ef0f1efda2cd5bdef7)
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 
38 #include <sys/kernel.h>
39 #include <sys/kern_syscall.h>
40 #include <sys/param.h>
41 #include <sys/fcntl.h>
42 #include <sys/lockf.h>
43 #include <sys/priv.h>
44 #include <sys/proc.h>
45 #include <sys/resourcevar.h>
46 #include <sys/sched.h>
47 #include <sys/stat.h>
48 #include <sys/systm.h>
49 #include <sys/unistd.h>
50 #include <sys/vfsops.h>
51 #include <sys/vnode.h>
52 
53 #include <sys/mplock2.h>
54 
55 #include <vm/vm.h>
56 #include <vm/vm_object.h>
57 #include <vm/vm_page.h>
58 #include <vm/vm_pager.h>
59 
60 #include <vfs/fifofs/fifo.h>
61 #include <vfs/tmpfs/tmpfs_vnops.h>
62 #include <vfs/tmpfs/tmpfs.h>
63 
64 MALLOC_DECLARE(M_TMPFS);
65 
66 /* --------------------------------------------------------------------- */
67 
68 static int
69 tmpfs_nresolve(struct vop_nresolve_args *v)
70 {
71 	struct vnode *dvp = v->a_dvp;
72 	struct vnode *vp = NULL;
73 	struct namecache *ncp = v->a_nch->ncp;
74 	struct tmpfs_node *tnode;
75 
76 	int error;
77 	struct tmpfs_dirent *de;
78 	struct tmpfs_node *dnode;
79 
80 	dnode = VP_TO_TMPFS_DIR(dvp);
81 
82 	de = tmpfs_dir_lookup(dnode, NULL, ncp);
83 	if (de == NULL) {
84 		error = ENOENT;
85 	} else {
86 		/*
87 		 * Allocate a vnode for the node we found.
88 		 */
89 		tnode = de->td_node;
90 		error = tmpfs_alloc_vp(dvp->v_mount, tnode,
91 				       LK_EXCLUSIVE | LK_RETRY, &vp);
92 		if (error)
93 			goto out;
94 		KKASSERT(vp);
95 	}
96 
97 out:
98 	/*
99 	 * Store the result of this lookup in the cache.  Avoid this if the
100 	 * request was for creation, as it does not improve timings on
101 	 * emprical tests.
102 	 */
103 	if (vp) {
104 		vn_unlock(vp);
105 		cache_setvp(v->a_nch, vp);
106 		vrele(vp);
107 	} else if (error == ENOENT) {
108 		cache_setvp(v->a_nch, NULL);
109 	}
110 	return error;
111 }
112 
113 static int
114 tmpfs_nlookupdotdot(struct vop_nlookupdotdot_args *v)
115 {
116 	struct vnode *dvp = v->a_dvp;
117 	struct vnode **vpp = v->a_vpp;
118 	struct tmpfs_node *dnode = VP_TO_TMPFS_NODE(dvp);
119 	struct ucred *cred = v->a_cred;
120 	int error;
121 
122 	*vpp = NULL;
123 	/* Check accessibility of requested node as a first step. */
124 	error = VOP_ACCESS(dvp, VEXEC, cred);
125 	if (error != 0)
126 		return error;
127 
128 	if (dnode->tn_dir.tn_parent != NULL) {
129 		/* Allocate a new vnode on the matching entry. */
130 		error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent,
131 		    LK_EXCLUSIVE | LK_RETRY, vpp);
132 
133 		if (*vpp)
134 			vn_unlock(*vpp);
135 	}
136 
137 	return (*vpp == NULL) ? ENOENT : 0;
138 }
139 
140 /* --------------------------------------------------------------------- */
141 
142 static int
143 tmpfs_ncreate(struct vop_ncreate_args *v)
144 {
145 	struct vnode *dvp = v->a_dvp;
146 	struct vnode **vpp = v->a_vpp;
147 	struct namecache *ncp = v->a_nch->ncp;
148 	struct vattr *vap = v->a_vap;
149 	struct ucred *cred = v->a_cred;
150 	int error;
151 
152 	KKASSERT(vap->va_type == VREG || vap->va_type == VSOCK);
153 
154 	error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
155 	if (error == 0) {
156 		cache_setunresolved(v->a_nch);
157 		cache_setvp(v->a_nch, *vpp);
158 	}
159 
160 	return error;
161 }
162 /* --------------------------------------------------------------------- */
163 
164 static int
165 tmpfs_nmknod(struct vop_nmknod_args *v)
166 {
167 	struct vnode *dvp = v->a_dvp;
168 	struct vnode **vpp = v->a_vpp;
169 	struct namecache *ncp = v->a_nch->ncp;
170 	struct vattr *vap = v->a_vap;
171 	struct ucred *cred = v->a_cred;
172 	int error;
173 
174 	if (vap->va_type != VBLK && vap->va_type != VCHR &&
175 	    vap->va_type != VFIFO)
176 		return EINVAL;
177 
178 	error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
179 	if (error == 0) {
180 		cache_setunresolved(v->a_nch);
181 		cache_setvp(v->a_nch, *vpp);
182 	}
183 
184 	return error;
185 }
186 
187 /* --------------------------------------------------------------------- */
188 
189 static int
190 tmpfs_open(struct vop_open_args *v)
191 {
192 	struct vnode *vp = v->a_vp;
193 	int mode = v->a_mode;
194 
195 	int error;
196 	struct tmpfs_node *node;
197 
198 	node = VP_TO_TMPFS_NODE(vp);
199 
200 	/* The file is still active but all its names have been removed
201 	 * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
202 	 * it is about to die. */
203 	if (node->tn_links < 1)
204 		return (ENOENT);
205 
206 	/* If the file is marked append-only, deny write requests. */
207 	if ((node->tn_flags & APPEND) &&
208 	    (mode & (FWRITE | O_APPEND)) == FWRITE) {
209 		error = EPERM;
210 	} else {
211 		return (vop_stdopen(v));
212 	}
213 	return error;
214 }
215 
216 /* --------------------------------------------------------------------- */
217 
218 static int
219 tmpfs_close(struct vop_close_args *v)
220 {
221 	struct vnode *vp = v->a_vp;
222 	struct tmpfs_node *node;
223 
224 	node = VP_TO_TMPFS_NODE(vp);
225 
226 	if (node->tn_links > 0) {
227 		/* Update node times.  No need to do it if the node has
228 		 * been deleted, because it will vanish after we return. */
229 		tmpfs_update(vp);
230 	}
231 
232 	return vop_stdclose(v);
233 }
234 
235 /* --------------------------------------------------------------------- */
236 
237 int
238 tmpfs_access(struct vop_access_args *v)
239 {
240 	struct vnode *vp = v->a_vp;
241 	int error;
242 	struct tmpfs_node *node;
243 
244 	node = VP_TO_TMPFS_NODE(vp);
245 
246 	switch (vp->v_type) {
247 	case VDIR:
248 		/* FALLTHROUGH */
249 	case VLNK:
250 		/* FALLTHROUGH */
251 	case VREG:
252 		if (VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
253 			error = EROFS;
254 			goto out;
255 		}
256 		break;
257 
258 	case VBLK:
259 		/* FALLTHROUGH */
260 	case VCHR:
261 		/* FALLTHROUGH */
262 	case VSOCK:
263 		/* FALLTHROUGH */
264 	case VFIFO:
265 		break;
266 
267 	default:
268 		error = EINVAL;
269 		goto out;
270 	}
271 
272 	if (VWRITE && node->tn_flags & IMMUTABLE) {
273 		error = EPERM;
274 		goto out;
275 	}
276 
277 	error = vop_helper_access(v, node->tn_uid, node->tn_gid, node->tn_mode, 0);
278 
279 out:
280 
281 	return error;
282 }
283 
284 /* --------------------------------------------------------------------- */
285 
286 int
287 tmpfs_getattr(struct vop_getattr_args *v)
288 {
289 	struct vnode *vp = v->a_vp;
290 	struct vattr *vap = v->a_vap;
291 	struct tmpfs_node *node;
292 
293 	node = VP_TO_TMPFS_NODE(vp);
294 
295 	tmpfs_update(vp);
296 
297 	vap->va_type = vp->v_type;
298 	vap->va_mode = node->tn_mode;
299 	vap->va_nlink = node->tn_links;
300 	vap->va_uid = node->tn_uid;
301 	vap->va_gid = node->tn_gid;
302 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
303 	vap->va_fileid = node->tn_id;
304 	vap->va_size = node->tn_size;
305 	vap->va_blocksize = PAGE_SIZE;
306 	vap->va_atime.tv_sec = node->tn_atime;
307 	vap->va_atime.tv_nsec = node->tn_atimensec;
308 	vap->va_mtime.tv_sec = node->tn_mtime;
309 	vap->va_mtime.tv_nsec = node->tn_mtimensec;
310 	vap->va_ctime.tv_sec = node->tn_ctime;
311 	vap->va_ctime.tv_nsec = node->tn_ctimensec;
312 	vap->va_gen = node->tn_gen;
313 	vap->va_flags = node->tn_flags;
314 	if (vp->v_type == VBLK || vp->v_type == VCHR)
315 	{
316 		vap->va_rmajor = umajor(node->tn_rdev);
317 		vap->va_rminor = uminor(node->tn_rdev);
318 	}
319 	vap->va_bytes = round_page(node->tn_size);
320 	vap->va_filerev = 0;
321 
322 	return 0;
323 }
324 
325 /* --------------------------------------------------------------------- */
326 
327 int
328 tmpfs_setattr(struct vop_setattr_args *v)
329 {
330 	struct vnode *vp = v->a_vp;
331 	struct vattr *vap = v->a_vap;
332 	struct ucred *cred = v->a_cred;
333 	int error = 0;
334 
335 	if (error == 0 && (vap->va_flags != VNOVAL))
336 		error = tmpfs_chflags(vp, vap->va_flags, cred);
337 
338 	if (error == 0 && (vap->va_size != VNOVAL))
339 		error = tmpfs_chsize(vp, vap->va_size, cred);
340 
341 	if (error == 0 && (vap->va_uid != (uid_t)VNOVAL ||
342 			   vap->va_gid != (gid_t)VNOVAL)) {
343 		error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred);
344 	}
345 
346 	if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
347 		error = tmpfs_chmod(vp, vap->va_mode, cred);
348 
349 	if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
350 	    vap->va_atime.tv_nsec != VNOVAL) ||
351 	    (vap->va_mtime.tv_sec != VNOVAL &&
352 	    vap->va_mtime.tv_nsec != VNOVAL) )) {
353 		error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
354 				      vap->va_vaflags, cred);
355 	}
356 
357 	/* Update the node times.  We give preference to the error codes
358 	 * generated by this function rather than the ones that may arise
359 	 * from tmpfs_update. */
360 	tmpfs_update(vp);
361 
362 	return error;
363 }
364 
365 /* --------------------------------------------------------------------- */
366 
367 /*
368  * fsync is usually a NOP, but we must take action when unmounting or
369  * when recycling.
370  */
371 static int
372 tmpfs_fsync(struct vop_fsync_args *v)
373 {
374 	struct tmpfs_mount *tmp;
375 	struct tmpfs_node *node;
376 	struct vnode *vp = v->a_vp;
377 
378 	tmp = VFS_TO_TMPFS(vp->v_mount);
379 	node = VP_TO_TMPFS_NODE(vp);
380 
381 	tmpfs_update(vp);
382 	if (vp->v_type == VREG) {
383 		if (vp->v_flag & VRECLAIMED) {
384 			if (node->tn_links == 0)
385 				tmpfs_truncate(vp, 0);
386 			else
387 				vfsync(v->a_vp, v->a_waitfor, 1, NULL, NULL);
388 		}
389 	}
390 	return 0;
391 }
392 
393 /* --------------------------------------------------------------------- */
394 
395 static int
396 tmpfs_read (struct vop_read_args *ap)
397 {
398 	struct buf *bp;
399 	struct vnode *vp = ap->a_vp;
400 	struct uio *uio = ap->a_uio;
401 	struct tmpfs_node *node;
402 	off_t base_offset;
403 	size_t offset;
404 	size_t len;
405 	int got_mplock;
406 	int error;
407 
408 	error = 0;
409 	if (uio->uio_resid == 0) {
410 		return error;
411 	}
412 
413 	node = VP_TO_TMPFS_NODE(vp);
414 
415 	if (uio->uio_offset < 0)
416 		return (EINVAL);
417 	if (vp->v_type != VREG)
418 		return (EINVAL);
419 
420 #ifdef SMP
421 	if(curthread->td_mpcount)
422 		got_mplock = -1;
423 	else
424 		got_mplock = 0;
425 #else
426 		got_mplock = -1;
427 #endif
428 
429 	while (uio->uio_resid > 0 && uio->uio_offset < node->tn_size) {
430 		/*
431 		 * Use buffer cache I/O (via tmpfs_strategy)
432 		 */
433 		offset = (size_t)uio->uio_offset & BMASK;
434 		base_offset = (off_t)uio->uio_offset - offset;
435 		bp = getcacheblk(vp, base_offset);
436 		if (bp == NULL)
437 		{
438 			if (got_mplock == 0) {
439 				got_mplock = 1;
440 				get_mplock();
441 			}
442 
443 			error = bread(vp, base_offset, BSIZE, &bp);
444 			if (error) {
445 				brelse(bp);
446 				kprintf("tmpfs_read bread error %d\n", error);
447 				break;
448 			}
449 		}
450 
451 		if (got_mplock == 0) {
452 			got_mplock = 1;
453 			get_mplock();
454 		}
455 
456 		/*
457 		 * Figure out how many bytes we can actually copy this loop.
458 		 */
459 		len = BSIZE - offset;
460 		if (len > uio->uio_resid)
461 			len = uio->uio_resid;
462 		if (len > node->tn_size - uio->uio_offset)
463 			len = (size_t)(node->tn_size - uio->uio_offset);
464 
465 		error = uiomove((char *)bp->b_data + offset, len, uio);
466 		bqrelse(bp);
467 		if (error) {
468 			kprintf("tmpfs_read uiomove error %d\n", error);
469 			break;
470 		}
471 	}
472 
473 	if (got_mplock > 0)
474 		rel_mplock();
475 
476 	TMPFS_NODE_LOCK(node);
477 	node->tn_status |= TMPFS_NODE_ACCESSED;
478 	TMPFS_NODE_UNLOCK(node);
479 
480 	return(error);
481 }
482 
483 static int
484 tmpfs_write (struct vop_write_args *ap)
485 {
486 	struct buf *bp;
487 	struct vnode *vp = ap->a_vp;
488 	struct uio *uio = ap->a_uio;
489 	struct thread *td = uio->uio_td;
490 	struct tmpfs_node *node;
491 	boolean_t extended;
492 	off_t oldsize;
493 	int error;
494 	off_t base_offset;
495 	size_t offset;
496 	size_t len;
497 	struct rlimit limit;
498 	int got_mplock;
499 	int trivial = 0;
500 
501 	error = 0;
502 	if (uio->uio_resid == 0) {
503 		return error;
504 	}
505 
506 	node = VP_TO_TMPFS_NODE(vp);
507 
508 	if (vp->v_type != VREG)
509 		return (EINVAL);
510 
511 	oldsize = node->tn_size;
512 	if (ap->a_ioflag & IO_APPEND)
513 		uio->uio_offset = node->tn_size;
514 
515 	/*
516 	 * Check for illegal write offsets.
517 	 */
518 	if (uio->uio_offset + uio->uio_resid >
519 	  VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
520 		return (EFBIG);
521 
522 	if (vp->v_type == VREG && td != NULL) {
523 		error = kern_getrlimit(RLIMIT_FSIZE, &limit);
524 		if (error != 0)
525 			return error;
526 		if (uio->uio_offset + uio->uio_resid > limit.rlim_cur) {
527 			ksignal(td->td_proc, SIGXFSZ);
528 			return (EFBIG);
529 		}
530 	}
531 
532 
533 	/*
534 	 * Extend the file's size if necessary
535 	 */
536 	extended = ((uio->uio_offset + uio->uio_resid) > node->tn_size);
537 
538 #ifdef SMP
539 	if (curthread->td_mpcount) {
540 		got_mplock = -1;
541 	} else {
542 		got_mplock = 1;
543 		get_mplock();
544 	}
545 #else
546 	got_mplock = -1;
547 #endif
548 	while (uio->uio_resid > 0) {
549 		/*
550 		 * Use buffer cache I/O (via tmpfs_strategy)
551 		 */
552 		offset = (size_t)uio->uio_offset & BMASK;
553 		base_offset = (off_t)uio->uio_offset - offset;
554 		len = BSIZE - offset;
555 		if (len > uio->uio_resid)
556 			len = uio->uio_resid;
557 
558 		if ((uio->uio_offset + len) > node->tn_size) {
559 			trivial = (uio->uio_offset <= node->tn_size);
560 			error = tmpfs_reg_resize(vp, uio->uio_offset + len,  trivial);
561 			if (error)
562 				break;
563 		}
564 
565 		/*
566 		 * Read to fill in any gaps.  Theoretically we could
567 		 * optimize this if the write covers the entire buffer
568 		 * and is not a UIO_NOCOPY write, however this can lead
569 		 * to a security violation exposing random kernel memory
570 		 * (whatever junk was in the backing VM pages before).
571 		 *
572 		 * So just use bread() to do the right thing.
573 		 */
574 		error = bread(vp, base_offset, BSIZE, &bp);
575 		error = uiomove((char *)bp->b_data + offset, len, uio);
576 		if (error) {
577 			kprintf("tmpfs_write uiomove error %d\n", error);
578 			brelse(bp);
579 			break;
580 		}
581 
582 		if (uio->uio_offset > node->tn_size)
583 			node->tn_size = uio->uio_offset;
584 
585 		/*
586 		 * The data has been loaded into the buffer, write it out.
587 		 *
588 		 * We want tmpfs to be able to use all available ram, not
589 		 * just the buffer cache, so if not explicitly paging we
590 		 * use buwrite() to leave the buffer clean but mark all the
591 		 * VM pages valid+dirty.
592 		 *
593 		 * When the kernel is paging, either via normal pageout
594 		 * operation or when cleaning the object during a recycle,
595 		 * the underlying VM pages are going to get thrown away
596 		 * so we MUST write them to swap.
597 		 *
598 		 * XXX unfortunately this catches msync() system calls too
599 		 * for the moment.
600 		 */
601 		if (ap->a_ioflag & IO_SYNC) {
602 			bwrite(bp);
603 		} else if ((ap->a_ioflag & IO_ASYNC) ||
604 			 (uio->uio_segflg == UIO_NOCOPY)) {
605 			bawrite(bp);
606 		} else {
607 			buwrite(bp);
608 		}
609 
610 		if (bp->b_error) {
611 			kprintf("tmpfs_write bwrite error %d\n", bp->b_error);
612 			break;
613 		}
614 	}
615 
616 	if (got_mplock > 0)
617 		rel_mplock();
618 
619 	if (error) {
620 		if (extended)
621 			(void)tmpfs_reg_resize(vp, oldsize, trivial);
622 		return error;
623 	}
624 
625 	TMPFS_NODE_LOCK(node);
626 	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
627 	    (extended? TMPFS_NODE_CHANGED : 0);
628 
629 	if (node->tn_mode & (S_ISUID | S_ISGID)) {
630 		if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID, 0))
631 			node->tn_mode &= ~(S_ISUID | S_ISGID);
632 	}
633 	TMPFS_NODE_UNLOCK(node);
634 
635 	return(error);
636 }
637 
638 static int
639 tmpfs_advlock (struct vop_advlock_args *ap)
640 {
641 	struct tmpfs_node *node;
642 	struct vnode *vp = ap->a_vp;
643 
644 	node = VP_TO_TMPFS_NODE(vp);
645 
646 	return (lf_advlock(ap, &node->tn_advlock, node->tn_size));
647 }
648 
649 
650 static int
651 tmpfs_strategy(struct vop_strategy_args *ap)
652 {
653 	struct bio *bio = ap->a_bio;
654 	struct buf *bp = bio->bio_buf;
655 	struct vnode *vp = ap->a_vp;
656 	struct tmpfs_node *node;
657 	vm_object_t uobj;
658 
659 	if (vp->v_type != VREG) {
660 		bp->b_resid = bp->b_bcount;
661 		bp->b_flags |= B_ERROR | B_INVAL;
662 		bp->b_error = EINVAL;
663 		biodone(bio);
664 		return(0);
665 	}
666 
667 	node = VP_TO_TMPFS_NODE(vp);
668 
669 	uobj = node->tn_reg.tn_aobj;
670 
671 	/*
672 	 * Call swap_pager_strategy to read or write between the VM
673 	 * object and the buffer cache.
674 	 */
675 	swap_pager_strategy(uobj, bio);
676 
677 	return 0;
678 }
679 
680 static int
681 tmpfs_bmap(struct vop_bmap_args *ap)
682 {
683 	if (ap->a_doffsetp != NULL)
684 		*ap->a_doffsetp = ap->a_loffset;
685 	if (ap->a_runp != NULL)
686 		*ap->a_runp = 0;
687 	if (ap->a_runb != NULL)
688 		*ap->a_runb = 0;
689 
690 	return 0;
691 }
692 
693 /* --------------------------------------------------------------------- */
694 
695 static int
696 tmpfs_nremove(struct vop_nremove_args *v)
697 {
698 	struct vnode *dvp = v->a_dvp;
699 	struct namecache *ncp = v->a_nch->ncp;
700 	struct vnode *vp;
701 	int error;
702 	struct tmpfs_dirent *de;
703 	struct tmpfs_mount *tmp;
704 	struct tmpfs_node *dnode;
705 	struct tmpfs_node *node;
706 
707 	/*
708 	 * We have to acquire the vp from v->a_nch because
709 	 * we will likely unresolve the namecache entry, and
710 	 * a vrele is needed to trigger the tmpfs_inactive/tmpfs_reclaim
711 	 * sequence to recover space from the file.
712 	 */
713 	error = cache_vref(v->a_nch, v->a_cred, &vp);
714 	KKASSERT(error == 0);
715 
716 	if (vp->v_type == VDIR) {
717 		error = EISDIR;
718 		goto out;
719 	}
720 
721 	dnode = VP_TO_TMPFS_DIR(dvp);
722 	node = VP_TO_TMPFS_NODE(vp);
723 	tmp = VFS_TO_TMPFS(vp->v_mount);
724 	de = tmpfs_dir_lookup(dnode, node, ncp);
725 	if (de == NULL) {
726 		error = ENOENT;
727 		goto out;
728 	}
729 
730 	/* Files marked as immutable or append-only cannot be deleted. */
731 	if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
732 	    (dnode->tn_flags & APPEND)) {
733 		error = EPERM;
734 		goto out;
735 	}
736 
737 	/* Remove the entry from the directory; as it is a file, we do not
738 	 * have to change the number of hard links of the directory. */
739 	tmpfs_dir_detach(dnode, de);
740 
741 	/* Free the directory entry we just deleted.  Note that the node
742 	 * referred by it will not be removed until the vnode is really
743 	 * reclaimed. */
744 	tmpfs_free_dirent(tmp, de);
745 
746 	if (node->tn_links > 0) {
747 	        TMPFS_NODE_LOCK(node);
748 		node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
749 	                TMPFS_NODE_MODIFIED;
750 	        TMPFS_NODE_UNLOCK(node);
751 	}
752 
753 	cache_setunresolved(v->a_nch);
754 	cache_setvp(v->a_nch, NULL);
755 	/*cache_inval_vp(vp, CINV_DESTROY);*/
756 	error = 0;
757 
758 out:
759 	vrele(vp);
760 
761 	return error;
762 }
763 
764 /* --------------------------------------------------------------------- */
765 
766 static int
767 tmpfs_nlink(struct vop_nlink_args *v)
768 {
769 	struct vnode *dvp = v->a_dvp;
770 	struct vnode *vp = v->a_vp;
771 	struct namecache *ncp = v->a_nch->ncp;
772 	struct tmpfs_dirent *de;
773 	struct tmpfs_node *node;
774 	struct tmpfs_node *dnode;
775 	int error;
776 
777 	KKASSERT(dvp != vp); /* XXX When can this be false? */
778 
779 	node = VP_TO_TMPFS_NODE(vp);
780 	dnode = VP_TO_TMPFS_NODE(dvp);
781 
782 	/* XXX: Why aren't the following two tests done by the caller? */
783 
784 	/* Hard links of directories are forbidden. */
785 	if (vp->v_type == VDIR) {
786 		error = EPERM;
787 		goto out;
788 	}
789 
790 	/* Cannot create cross-device links. */
791 	if (dvp->v_mount != vp->v_mount) {
792 		error = EXDEV;
793 		goto out;
794 	}
795 
796 	/* Ensure that we do not overflow the maximum number of links imposed
797 	 * by the system. */
798 	KKASSERT(node->tn_links <= LINK_MAX);
799 	if (node->tn_links == LINK_MAX) {
800 		error = EMLINK;
801 		goto out;
802 	}
803 
804 	/* We cannot create links of files marked immutable or append-only. */
805 	if (node->tn_flags & (IMMUTABLE | APPEND)) {
806 		error = EPERM;
807 		goto out;
808 	}
809 
810 	/* Allocate a new directory entry to represent the node. */
811 	error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
812 	    ncp->nc_name, ncp->nc_nlen, &de);
813 	if (error != 0)
814 		goto out;
815 
816 	/* Insert the new directory entry into the appropriate directory. */
817 	tmpfs_dir_attach(dnode, de);
818 
819 	/* vp link count has changed, so update node times. */
820 
821 	TMPFS_NODE_LOCK(node);
822 	node->tn_status |= TMPFS_NODE_CHANGED;
823 	TMPFS_NODE_UNLOCK(node);
824 	tmpfs_update(vp);
825 
826 	cache_setunresolved(v->a_nch);
827 	cache_setvp(v->a_nch, vp);
828 	error = 0;
829 
830 out:
831 	return error;
832 }
833 
834 /* --------------------------------------------------------------------- */
835 
836 static int
837 tmpfs_nrename(struct vop_nrename_args *v)
838 {
839 	struct vnode *fdvp = v->a_fdvp;
840 	struct namecache *fncp = v->a_fnch->ncp;
841 	struct vnode *fvp = fncp->nc_vp;
842 	struct vnode *tdvp = v->a_tdvp;
843 	struct namecache *tncp = v->a_tnch->ncp;
844 	struct vnode *tvp = tncp->nc_vp;
845 	struct tmpfs_dirent *de;
846 	struct tmpfs_mount *tmp;
847 	struct tmpfs_node *fdnode;
848 	struct tmpfs_node *fnode;
849 	struct tmpfs_node *tnode;
850 	struct tmpfs_node *tdnode;
851 	char *newname;
852 	char *oldname;
853 	int error;
854 
855 	tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
856 
857 	/* Disallow cross-device renames.
858 	 * XXX Why isn't this done by the caller? */
859 	if (fvp->v_mount != tdvp->v_mount ||
860 	    (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
861 		error = EXDEV;
862 		goto out;
863 	}
864 
865 	tmp = VFS_TO_TMPFS(tdvp->v_mount);
866 	tdnode = VP_TO_TMPFS_DIR(tdvp);
867 
868 	/* If source and target are the same file, there is nothing to do. */
869 	if (fvp == tvp) {
870 		error = 0;
871 		goto out;
872 	}
873 
874 	fdnode = VP_TO_TMPFS_DIR(fdvp);
875 	fnode = VP_TO_TMPFS_NODE(fvp);
876 	de = tmpfs_dir_lookup(fdnode, fnode, fncp);
877 
878 	/* Avoid manipulating '.' and '..' entries. */
879 	if (de == NULL) {
880 		error = ENOENT;
881 		goto out_locked;
882 	}
883 	KKASSERT(de->td_node == fnode);
884 
885 	/*
886 	 * If replacing an entry in the target directory and that entry
887 	 * is a directory, it must be empty.
888 	 *
889 	 * Kern_rename gurantees the destination to be a directory
890 	 * if the source is one (it does?).
891 	 */
892 	if (tvp != NULL) {
893 		KKASSERT(tnode != NULL);
894 
895 		if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
896 		    (tdnode->tn_flags & (APPEND | IMMUTABLE))) {
897 			error = EPERM;
898 			goto out_locked;
899 		}
900 
901 		if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
902 			if (tnode->tn_size > 0) {
903 				error = ENOTEMPTY;
904 				goto out_locked;
905 			}
906 		} else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
907 			error = ENOTDIR;
908 			goto out_locked;
909 		} else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
910 			error = EISDIR;
911 			goto out_locked;
912 		} else {
913 			KKASSERT(fnode->tn_type != VDIR &&
914 				tnode->tn_type != VDIR);
915 		}
916 	}
917 
918 	if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
919 	    (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
920 		error = EPERM;
921 		goto out_locked;
922 	}
923 
924 	/*
925 	 * Ensure that we have enough memory to hold the new name, if it
926 	 * has to be changed.
927 	 */
928 	if (fncp->nc_nlen != tncp->nc_nlen ||
929 	    bcmp(fncp->nc_name, tncp->nc_name, fncp->nc_nlen) != 0) {
930 		newname = kmalloc(tncp->nc_nlen + 1, M_TMPFSNAME, M_WAITOK);
931 		bcopy(tncp->nc_name, newname, tncp->nc_nlen);
932 		newname[tncp->nc_nlen] = '\0';
933 	} else {
934 		newname = NULL;
935 	}
936 
937 	/*
938 	 * Unlink entry from source directory.  Note that the kernel has
939 	 * already checked for illegal recursion cases (renaming a directory
940 	 * into a subdirectory of itself).
941 	 */
942 	if (fdnode != tdnode)
943 		tmpfs_dir_detach(fdnode, de);
944 
945 	/*
946 	 * Handle any name change.  Swap with newname, we will
947 	 * deallocate it at the end.
948 	 */
949 	if (newname != NULL) {
950 #if 0
951 		TMPFS_NODE_LOCK(fnode);
952 		fnode->tn_status |= TMPFS_NODE_CHANGED;
953 		TMPFS_NODE_UNLOCK(fnode);
954 #endif
955 		oldname = de->td_name;
956 		de->td_name = newname;
957 		de->td_namelen = (uint16_t)tncp->nc_nlen;
958 		newname = oldname;
959 	}
960 
961 	/*
962 	 * Link entry to target directory.  If the entry
963 	 * represents a directory move the parent linkage
964 	 * as well.
965 	 */
966 	if (fdnode != tdnode) {
967 		if (de->td_node->tn_type == VDIR) {
968 			TMPFS_VALIDATE_DIR(fnode);
969 
970 			TMPFS_NODE_LOCK(tdnode);
971 			tdnode->tn_links++;
972 			tdnode->tn_status |= TMPFS_NODE_MODIFIED;
973 			TMPFS_NODE_UNLOCK(tdnode);
974 
975 			TMPFS_NODE_LOCK(fnode);
976 			fnode->tn_dir.tn_parent = tdnode;
977 			fnode->tn_status |= TMPFS_NODE_CHANGED;
978 			TMPFS_NODE_UNLOCK(fnode);
979 
980 			TMPFS_NODE_LOCK(fdnode);
981 			fdnode->tn_links--;
982 			fdnode->tn_status |= TMPFS_NODE_MODIFIED;
983 			TMPFS_NODE_UNLOCK(fdnode);
984 		}
985 		tmpfs_dir_attach(tdnode, de);
986 	} else {
987 		TMPFS_NODE_LOCK(tdnode);
988 		tdnode->tn_status |= TMPFS_NODE_MODIFIED;
989 		TMPFS_NODE_UNLOCK(tdnode);
990 	}
991 
992 	/*
993 	 * If we are overwriting an entry, we have to remove the old one
994 	 * from the target directory.
995 	 */
996 	if (tvp != NULL) {
997 		/* Remove the old entry from the target directory. */
998 		de = tmpfs_dir_lookup(tdnode, tnode, tncp);
999 		tmpfs_dir_detach(tdnode, de);
1000 
1001 		/*
1002 		 * Free the directory entry we just deleted.  Note that the
1003 		 * node referred by it will not be removed until the vnode is
1004 		 * really reclaimed.
1005 		 */
1006 		tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de);
1007 		/*cache_inval_vp(tvp, CINV_DESTROY);*/
1008 	}
1009 
1010 	/*
1011 	 * Finish up
1012 	 */
1013 	if (newname) {
1014 		kfree(newname, M_TMPFSNAME);
1015 		newname = NULL;
1016 	}
1017 	cache_rename(v->a_fnch, v->a_tnch);
1018 	error = 0;
1019 
1020 out_locked:
1021 	;
1022 
1023 out:
1024 	/* Release target nodes. */
1025 	/* XXX: I don't understand when tdvp can be the same as tvp, but
1026 	 * other code takes care of this... */
1027 	if (tdvp == tvp)
1028 		vrele(tdvp);
1029 
1030 	return error;
1031 }
1032 
1033 /* --------------------------------------------------------------------- */
1034 
1035 static int
1036 tmpfs_nmkdir(struct vop_nmkdir_args *v)
1037 {
1038 	struct vnode *dvp = v->a_dvp;
1039 	struct vnode **vpp = v->a_vpp;
1040 	struct namecache *ncp = v->a_nch->ncp;
1041 	struct vattr *vap = v->a_vap;
1042 	struct ucred *cred = v->a_cred;
1043 	int error;
1044 
1045 	KKASSERT(vap->va_type == VDIR);
1046 
1047 	error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, NULL);
1048 	if (error == 0) {
1049 		cache_setunresolved(v->a_nch);
1050 		cache_setvp(v->a_nch, *vpp);
1051 	}
1052 
1053 	return error;
1054 }
1055 
1056 /* --------------------------------------------------------------------- */
1057 
1058 static int
1059 tmpfs_nrmdir(struct vop_nrmdir_args *v)
1060 {
1061 	struct vnode *dvp = v->a_dvp;
1062 	struct namecache *ncp = v->a_nch->ncp;
1063 	struct vnode *vp;
1064 	struct tmpfs_dirent *de;
1065 	struct tmpfs_mount *tmp;
1066 	struct tmpfs_node *dnode;
1067 	struct tmpfs_node *node;
1068 	int error;
1069 
1070 	/*
1071 	 * We have to acquire the vp from v->a_nch because
1072 	 * we will likely unresolve the namecache entry, and
1073 	 * a vrele is needed to trigger the tmpfs_inactive/tmpfs_reclaim
1074 	 * sequence.
1075 	 */
1076 	error = cache_vref(v->a_nch, v->a_cred, &vp);
1077 	KKASSERT(error == 0);
1078 
1079 	/*
1080 	 * Prevalidate so we don't hit an assertion later
1081 	 */
1082 	if (vp->v_type != VDIR) {
1083 		error = ENOTDIR;
1084 		goto out;
1085 	}
1086 
1087 	tmp = VFS_TO_TMPFS(dvp->v_mount);
1088 	dnode = VP_TO_TMPFS_DIR(dvp);
1089 	node = VP_TO_TMPFS_DIR(vp);
1090 
1091 	/* Directories with more than two entries ('.' and '..') cannot be
1092 	 * removed. */
1093 	 if (node->tn_size > 0) {
1094 		 error = ENOTEMPTY;
1095 		 goto out;
1096 	 }
1097 
1098 	if ((dnode->tn_flags & APPEND)
1099 	    || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1100 		error = EPERM;
1101 		goto out;
1102 	}
1103 
1104 	/* This invariant holds only if we are not trying to remove "..".
1105 	  * We checked for that above so this is safe now. */
1106 	KKASSERT(node->tn_dir.tn_parent == dnode);
1107 
1108 	/* Get the directory entry associated with node (vp).  This was
1109 	 * filled by tmpfs_lookup while looking up the entry. */
1110 	de = tmpfs_dir_lookup(dnode, node, ncp);
1111 	KKASSERT(TMPFS_DIRENT_MATCHES(de,
1112 	    ncp->nc_name,
1113 	    ncp->nc_nlen));
1114 
1115 	/* Check flags to see if we are allowed to remove the directory. */
1116 	if ((dnode->tn_flags & APPEND) ||
1117 	    node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) {
1118 		error = EPERM;
1119 		goto out;
1120 	}
1121 
1122 
1123 	/* Detach the directory entry from the directory (dnode). */
1124 	tmpfs_dir_detach(dnode, de);
1125 
1126 	/* No vnode should be allocated for this entry from this point */
1127 	TMPFS_NODE_LOCK(node);
1128 	TMPFS_ASSERT_ELOCKED(node);
1129 	TMPFS_NODE_LOCK(dnode);
1130 	TMPFS_ASSERT_ELOCKED(dnode);
1131 
1132 #if 0
1133 	/* handled by tmpfs_free_node */
1134 	KKASSERT(node->tn_links > 0);
1135 	node->tn_links--;
1136 	node->tn_dir.tn_parent = NULL;
1137 #endif
1138 	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
1139 	    TMPFS_NODE_MODIFIED;
1140 
1141 #if 0
1142 	/* handled by tmpfs_free_node */
1143 	KKASSERT(dnode->tn_links > 0);
1144 	dnode->tn_links--;
1145 #endif
1146 	dnode->tn_status |= TMPFS_NODE_ACCESSED | \
1147 	    TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
1148 
1149 	TMPFS_NODE_UNLOCK(dnode);
1150 	TMPFS_NODE_UNLOCK(node);
1151 
1152 	/* Free the directory entry we just deleted.  Note that the node
1153 	 * referred by it will not be removed until the vnode is really
1154 	 * reclaimed. */
1155 	tmpfs_free_dirent(tmp, de);
1156 
1157 	/* Release the deleted vnode (will destroy the node, notify
1158 	 * interested parties and clean it from the cache). */
1159 
1160 	TMPFS_NODE_LOCK(dnode);
1161 	dnode->tn_status |= TMPFS_NODE_CHANGED;
1162 	TMPFS_NODE_UNLOCK(dnode);
1163 	tmpfs_update(dvp);
1164 
1165 	cache_setunresolved(v->a_nch);
1166 	cache_setvp(v->a_nch, NULL);
1167 	/*cache_inval_vp(vp, CINV_DESTROY);*/
1168 	error = 0;
1169 
1170 out:
1171 	vrele(vp);
1172 
1173 	return error;
1174 }
1175 
1176 /* --------------------------------------------------------------------- */
1177 
1178 static int
1179 tmpfs_nsymlink(struct vop_nsymlink_args *v)
1180 {
1181 	struct vnode *dvp = v->a_dvp;
1182 	struct vnode **vpp = v->a_vpp;
1183 	struct namecache *ncp = v->a_nch->ncp;
1184 	struct vattr *vap = v->a_vap;
1185 	struct ucred *cred = v->a_cred;
1186 	char *target = v->a_target;
1187 	int error;
1188 
1189 	vap->va_type = VLNK;
1190 	error = tmpfs_alloc_file(dvp, vpp, vap, ncp, cred, target);
1191 	if (error == 0) {
1192 		cache_setunresolved(v->a_nch);
1193 		cache_setvp(v->a_nch, *vpp);
1194 	}
1195 
1196 	return error;
1197 }
1198 
1199 /* --------------------------------------------------------------------- */
1200 
1201 static int
1202 tmpfs_readdir(struct vop_readdir_args *v)
1203 {
1204 	struct vnode *vp = v->a_vp;
1205 	struct uio *uio = v->a_uio;
1206 	int *eofflag = v->a_eofflag;
1207 	off_t **cookies = v->a_cookies;
1208 	int *ncookies = v->a_ncookies;
1209 	struct tmpfs_mount *tmp;
1210 	int error;
1211 	off_t startoff;
1212 	off_t cnt = 0;
1213 	struct tmpfs_node *node;
1214 
1215 	/* This operation only makes sense on directory nodes. */
1216 	if (vp->v_type != VDIR)
1217 		return ENOTDIR;
1218 
1219 	tmp = VFS_TO_TMPFS(vp->v_mount);
1220 	node = VP_TO_TMPFS_DIR(vp);
1221 	startoff = uio->uio_offset;
1222 
1223 	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
1224 		error = tmpfs_dir_getdotdent(node, uio);
1225 		if (error != 0)
1226 			goto outok;
1227 		cnt++;
1228 	}
1229 
1230 	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
1231 		error = tmpfs_dir_getdotdotdent(tmp, node, uio);
1232 		if (error != 0)
1233 			goto outok;
1234 		cnt++;
1235 	}
1236 
1237 	error = tmpfs_dir_getdents(node, uio, &cnt);
1238 
1239 outok:
1240 	KKASSERT(error >= -1);
1241 
1242 	if (error == -1)
1243 		error = 0;
1244 
1245 	if (eofflag != NULL)
1246 		*eofflag =
1247 		    (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
1248 
1249 	/* Update NFS-related variables. */
1250 	if (error == 0 && cookies != NULL && ncookies != NULL) {
1251 		off_t i;
1252 		off_t off = startoff;
1253 		struct tmpfs_dirent *de = NULL;
1254 
1255 		*ncookies = cnt;
1256 		*cookies = kmalloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);
1257 
1258 		for (i = 0; i < cnt; i++) {
1259 			KKASSERT(off != TMPFS_DIRCOOKIE_EOF);
1260 			if (off == TMPFS_DIRCOOKIE_DOT) {
1261 				off = TMPFS_DIRCOOKIE_DOTDOT;
1262 			} else {
1263 				if (off == TMPFS_DIRCOOKIE_DOTDOT) {
1264 					de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
1265 				} else if (de != NULL) {
1266 					de = TAILQ_NEXT(de, td_entries);
1267 				} else {
1268 					de = tmpfs_dir_lookupbycookie(node,
1269 					    off);
1270 					KKASSERT(de != NULL);
1271 					de = TAILQ_NEXT(de, td_entries);
1272 				}
1273 				if (de == NULL)
1274 					off = TMPFS_DIRCOOKIE_EOF;
1275 				else
1276 					off = tmpfs_dircookie(de);
1277 			}
1278 
1279 			(*cookies)[i] = off;
1280 		}
1281 		KKASSERT(uio->uio_offset == off);
1282 	}
1283 
1284 	return error;
1285 }
1286 
1287 /* --------------------------------------------------------------------- */
1288 
1289 static int
1290 tmpfs_readlink(struct vop_readlink_args *v)
1291 {
1292 	struct vnode *vp = v->a_vp;
1293 	struct uio *uio = v->a_uio;
1294 
1295 	int error;
1296 	struct tmpfs_node *node;
1297 
1298 	KKASSERT(uio->uio_offset == 0);
1299 	KKASSERT(vp->v_type == VLNK);
1300 
1301 	node = VP_TO_TMPFS_NODE(vp);
1302 
1303 	error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
1304 	    uio);
1305 	TMPFS_NODE_LOCK(node);
1306 	node->tn_status |= TMPFS_NODE_ACCESSED;
1307 	TMPFS_NODE_UNLOCK(node);
1308 
1309 	return error;
1310 }
1311 
1312 /* --------------------------------------------------------------------- */
1313 
1314 static int
1315 tmpfs_inactive(struct vop_inactive_args *v)
1316 {
1317 	struct vnode *vp = v->a_vp;
1318 
1319 	struct tmpfs_node *node;
1320 
1321 	node = VP_TO_TMPFS_NODE(vp);
1322 
1323 	/*
1324 	 * Get rid of unreferenced deleted vnodes sooner rather than
1325 	 * later so the data memory can be recovered immediately.
1326 	 *
1327 	 * We must truncate the vnode to prevent the normal reclamation
1328 	 * path from flushing the data for the removed file to disk.
1329 	 */
1330 	TMPFS_NODE_LOCK(node);
1331 	if ((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0 &&
1332 	    (node->tn_links == 0 ||
1333 	     (node->tn_links == 1 && node->tn_type == VDIR &&
1334 	      node->tn_dir.tn_parent)))
1335 	{
1336 		node->tn_vpstate = TMPFS_VNODE_DOOMED;
1337 		TMPFS_NODE_UNLOCK(node);
1338 		if (node->tn_type == VREG)
1339 			tmpfs_truncate(vp, 0);
1340 		vrecycle(vp);
1341 	} else {
1342 		TMPFS_NODE_UNLOCK(node);
1343 	}
1344 
1345 	return 0;
1346 }
1347 
1348 /* --------------------------------------------------------------------- */
1349 
1350 int
1351 tmpfs_reclaim(struct vop_reclaim_args *v)
1352 {
1353 	struct vnode *vp = v->a_vp;
1354 	struct tmpfs_mount *tmp;
1355 	struct tmpfs_node *node;
1356 
1357 	node = VP_TO_TMPFS_NODE(vp);
1358 	tmp = VFS_TO_TMPFS(vp->v_mount);
1359 
1360 	tmpfs_free_vp(vp);
1361 
1362 	/*
1363 	 * If the node referenced by this vnode was deleted by the
1364 	 * user, we must free its associated data structures now that
1365 	 * the vnode is being reclaimed.
1366 	 *
1367 	 * Directories have an extra link ref.
1368 	 */
1369 	TMPFS_NODE_LOCK(node);
1370 	if ((node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0 &&
1371 	    (node->tn_links == 0 ||
1372 	     (node->tn_links == 1 && node->tn_type == VDIR &&
1373 	      node->tn_dir.tn_parent)))
1374 	{
1375 		node->tn_vpstate = TMPFS_VNODE_DOOMED;
1376 		tmpfs_free_node(tmp, node);
1377 		/* eats the lock */
1378 	} else {
1379 		TMPFS_NODE_UNLOCK(node);
1380 	}
1381 
1382 	KKASSERT(vp->v_data == NULL);
1383 	return 0;
1384 }
1385 
1386 /* --------------------------------------------------------------------- */
1387 
1388 static int
1389 tmpfs_print(struct vop_print_args *v)
1390 {
1391 	struct vnode *vp = v->a_vp;
1392 
1393 	struct tmpfs_node *node;
1394 
1395 	node = VP_TO_TMPFS_NODE(vp);
1396 
1397 	kprintf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n",
1398 	    node, node->tn_flags, node->tn_links);
1399 	kprintf("\tmode 0%o, owner %d, group %d, size %ju, status 0x%x\n",
1400 	    node->tn_mode, node->tn_uid, node->tn_gid,
1401 	    (uintmax_t)node->tn_size, node->tn_status);
1402 
1403 	if (vp->v_type == VFIFO)
1404 		fifo_printinfo(vp);
1405 
1406 	kprintf("\n");
1407 
1408 	return 0;
1409 }
1410 
1411 /* --------------------------------------------------------------------- */
1412 
1413 static int
1414 tmpfs_pathconf(struct vop_pathconf_args *v)
1415 {
1416 	int name = v->a_name;
1417 	register_t *retval = v->a_retval;
1418 
1419 	int error;
1420 
1421 	error = 0;
1422 
1423 	switch (name) {
1424 	case _PC_LINK_MAX:
1425 		*retval = LINK_MAX;
1426 		break;
1427 
1428 	case _PC_NAME_MAX:
1429 		*retval = NAME_MAX;
1430 		break;
1431 
1432 	case _PC_PATH_MAX:
1433 		*retval = PATH_MAX;
1434 		break;
1435 
1436 	case _PC_PIPE_BUF:
1437 		*retval = PIPE_BUF;
1438 		break;
1439 
1440 	case _PC_CHOWN_RESTRICTED:
1441 		*retval = 1;
1442 		break;
1443 
1444 	case _PC_NO_TRUNC:
1445 		*retval = 1;
1446 		break;
1447 
1448 	case _PC_SYNC_IO:
1449 		*retval = 1;
1450 		break;
1451 
1452 	case _PC_FILESIZEBITS:
1453 		*retval = 0; /* XXX Don't know which value should I return. */
1454 		break;
1455 
1456 	default:
1457 		error = EINVAL;
1458 	}
1459 
1460 	return error;
1461 }
1462 
1463 /* --------------------------------------------------------------------- */
1464 
1465 /*
1466  * vnode operations vector used for files stored in a tmpfs file system.
1467  */
1468 struct vop_ops tmpfs_vnode_vops = {
1469 	.vop_default =			vop_defaultop,
1470 	.vop_getpages = 		vop_stdgetpages,
1471 	.vop_putpages = 		vop_stdputpages,
1472 	.vop_ncreate =			tmpfs_ncreate,
1473 	.vop_nresolve =			tmpfs_nresolve,
1474 	.vop_nlookupdotdot =		tmpfs_nlookupdotdot,
1475 	.vop_nmknod =			tmpfs_nmknod,
1476 	.vop_open =			tmpfs_open,
1477 	.vop_close =			tmpfs_close,
1478 	.vop_access =			tmpfs_access,
1479 	.vop_getattr =			tmpfs_getattr,
1480 	.vop_setattr =			tmpfs_setattr,
1481 	.vop_read =			tmpfs_read,
1482 	.vop_write =			tmpfs_write,
1483 	.vop_fsync =			tmpfs_fsync,
1484 	.vop_nremove =			tmpfs_nremove,
1485 	.vop_nlink =			tmpfs_nlink,
1486 	.vop_nrename =			tmpfs_nrename,
1487 	.vop_nmkdir =			tmpfs_nmkdir,
1488 	.vop_nrmdir =			tmpfs_nrmdir,
1489 	.vop_nsymlink =			tmpfs_nsymlink,
1490 	.vop_readdir =			tmpfs_readdir,
1491 	.vop_readlink =			tmpfs_readlink,
1492 	.vop_inactive =			tmpfs_inactive,
1493 	.vop_reclaim =			tmpfs_reclaim,
1494 	.vop_print =			tmpfs_print,
1495 	.vop_pathconf =			tmpfs_pathconf,
1496 	.vop_bmap =			tmpfs_bmap,
1497 	.vop_strategy =			tmpfs_strategy,
1498 	.vop_advlock =			tmpfs_advlock,
1499 };
1500