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