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