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