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