tmpfs_vnops.c revision 267816
1168404Spjd/*	$NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $	*/
2168404Spjd
3168404Spjd/*-
4168404Spjd * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5168404Spjd * All rights reserved.
6168404Spjd *
7168404Spjd * This code is derived from software contributed to The NetBSD Foundation
8168404Spjd * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9168404Spjd * 2005 program.
10168404Spjd *
11168404Spjd * Redistribution and use in source and binary forms, with or without
12168404Spjd * modification, are permitted provided that the following conditions
13168404Spjd * are met:
14168404Spjd * 1. Redistributions of source code must retain the above copyright
15168404Spjd *    notice, this list of conditions and the following disclaimer.
16168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
17168404Spjd *    notice, this list of conditions and the following disclaimer in the
18168404Spjd *    documentation and/or other materials provided with the distribution.
19168404Spjd *
20168404Spjd * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21168404Spjd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22168404Spjd * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23168404Spjd * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24168404Spjd * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25168404Spjd * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26168404Spjd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27168404Spjd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28168404Spjd * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29168404Spjd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30168404Spjd * POSSIBILITY OF SUCH DAMAGE.
31168404Spjd */
32168404Spjd
33185029Spjd/*
34168404Spjd * tmpfs vnode interface.
35168404Spjd */
36168404Spjd#include <sys/cdefs.h>
37168404Spjd__FBSDID("$FreeBSD: stable/10/sys/fs/tmpfs/tmpfs_vnops.c 267816 2014-06-24 08:21:43Z kib $");
38168404Spjd
39168404Spjd#include <sys/param.h>
40168404Spjd#include <sys/fcntl.h>
41168404Spjd#include <sys/lockf.h>
42168404Spjd#include <sys/lock.h>
43168404Spjd#include <sys/namei.h>
44168404Spjd#include <sys/priv.h>
45168404Spjd#include <sys/proc.h>
46168404Spjd#include <sys/rwlock.h>
47168404Spjd#include <sys/sched.h>
48196943Spjd#include <sys/sf_buf.h>
49168404Spjd#include <sys/stat.h>
50196943Spjd#include <sys/systm.h>
51196943Spjd#include <sys/sysctl.h>
52196943Spjd#include <sys/unistd.h>
53168404Spjd#include <sys/vnode.h>
54196943Spjd
55196943Spjd#include <vm/vm.h>
56196943Spjd#include <vm/vm_param.h>
57196943Spjd#include <vm/vm_object.h>
58196943Spjd#include <vm/vm_page.h>
59196943Spjd#include <vm/vm_pager.h>
60196943Spjd
61196943Spjd#include <fs/tmpfs/tmpfs_vnops.h>
62196943Spjd#include <fs/tmpfs/tmpfs.h>
63196943Spjd
64196943SpjdSYSCTL_DECL(_vfs_tmpfs);
65168404Spjd
66168404Spjdstatic volatile int tmpfs_rename_restarts;
67196943SpjdSYSCTL_INT(_vfs_tmpfs, OID_AUTO, rename_restarts, CTLFLAG_RD,
68196943Spjd    __DEVOLATILE(int *, &tmpfs_rename_restarts), 0,
69168404Spjd    "Times rename had to restart due to lock contention");
70168404Spjd
71168404Spjd/* --------------------------------------------------------------------- */
72168404Spjd
73189290Sjamiestatic int
74189290Sjamietmpfs_lookup(struct vop_cachedlookup_args *v)
75168404Spjd{
76168404Spjd	struct vnode *dvp = v->a_dvp;
77168404Spjd	struct vnode **vpp = v->a_vpp;
78168404Spjd	struct componentname *cnp = v->a_cnp;
79168404Spjd
80168404Spjd	int error;
81168404Spjd	struct tmpfs_dirent *de;
82168404Spjd	struct tmpfs_node *dnode;
83196943Spjd
84196943Spjd	dnode = VP_TO_TMPFS_DIR(dvp);
85168404Spjd	*vpp = NULLVP;
86196943Spjd
87196943Spjd	/* Check accessibility of requested node as a first step. */
88168404Spjd	error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_thread);
89168404Spjd	if (error != 0)
90168404Spjd		goto out;
91168404Spjd
92168404Spjd	/* We cannot be requesting the parent directory of the root node. */
93196943Spjd	MPASS(IMPLIES(dnode->tn_type == VDIR &&
94168404Spjd	    dnode->tn_dir.tn_parent == dnode,
95196943Spjd	    !(cnp->cn_flags & ISDOTDOT)));
96196943Spjd
97189290Sjamie	TMPFS_ASSERT_LOCKED(dnode);
98196943Spjd	if (dnode->tn_dir.tn_parent == NULL) {
99196943Spjd		error = ENOENT;
100168404Spjd		goto out;
101168404Spjd	}
102168404Spjd	if (cnp->cn_flags & ISDOTDOT) {
103168404Spjd		int ltype = 0;
104168404Spjd
105180652Spjd		ltype = VOP_ISLOCKED(dvp);
106168404Spjd		vhold(dvp);
107168404Spjd		VOP_UNLOCK(dvp, 0);
108168404Spjd		/* Allocate a new vnode on the matching entry. */
109168404Spjd		error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent,
110168404Spjd		    cnp->cn_lkflags, vpp);
111168404Spjd
112168404Spjd		vn_lock(dvp, ltype | LK_RETRY);
113168404Spjd		vdrop(dvp);
114168404Spjd	} else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
115197201Spjd		VREF(dvp);
116168404Spjd		*vpp = dvp;
117168404Spjd		error = 0;
118219089Spjd	} else {
119168404Spjd		de = tmpfs_dir_lookup(dnode, NULL, cnp);
120219089Spjd		if (de != NULL && de->td_node == NULL)
121185029Spjd			cnp->cn_flags |= ISWHITEOUT;
122168404Spjd		if (de == NULL || de->td_node == NULL) {
123168404Spjd			/* The entry was not found in the directory.
124302735Savg			 * This is OK if we are creating or renaming an
125302735Savg			 * entry and are working on the last component of
126302735Savg			 * the path name. */
127302735Savg			if ((cnp->cn_flags & ISLASTCN) &&
128302735Savg			    (cnp->cn_nameiop == CREATE || \
129302735Savg			    cnp->cn_nameiop == RENAME ||
130168404Spjd			    (cnp->cn_nameiop == DELETE &&
131168404Spjd			    cnp->cn_flags & DOWHITEOUT &&
132168404Spjd			    cnp->cn_flags & ISWHITEOUT))) {
133168404Spjd				error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
134168404Spjd				    cnp->cn_thread);
135168404Spjd				if (error != 0)
136302735Savg					goto out;
137302735Savg
138302735Savg				/* Keep the component name in the buffer for
139302735Savg				 * future uses. */
140302735Savg				cnp->cn_flags |= SAVENAME;
141197201Spjd
142197201Spjd				error = EJUSTRETURN;
143197201Spjd			} else
144197201Spjd				error = ENOENT;
145302735Savg		} else {
146302735Savg			struct tmpfs_node *tnode;
147302735Savg
148302735Savg			/* The entry was found, so get its associated
149302735Savg			 * tmpfs_node. */
150302735Savg			tnode = de->td_node;
151168404Spjd
152168404Spjd			/* If we are not at the last path component and
153302735Savg			 * found a non-directory or non-link entry (which
154302735Savg			 * may itself be pointing to a directory), raise
155302735Savg			 * an error. */
156302735Savg			if ((tnode->tn_type != VDIR &&
157197201Spjd			    tnode->tn_type != VLNK) &&
158168404Spjd			    !(cnp->cn_flags & ISLASTCN)) {
159168404Spjd				error = ENOTDIR;
160168404Spjd				goto out;
161219089Spjd			}
162219089Spjd
163168404Spjd			/* If we are deleting or renaming the entry, keep
164219089Spjd			 * track of its tmpfs_dirent so that it can be
165168404Spjd			 * easily deleted later. */
166168404Spjd			if ((cnp->cn_flags & ISLASTCN) &&
167168404Spjd			    (cnp->cn_nameiop == DELETE ||
168168404Spjd			    cnp->cn_nameiop == RENAME)) {
169168404Spjd				error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred,
170168404Spjd				    cnp->cn_thread);
171168404Spjd				if (error != 0)
172168404Spjd					goto out;
173168404Spjd
174219089Spjd				/* Allocate a new vnode on the matching entry. */
175168840Spjd				error = tmpfs_alloc_vp(dvp->v_mount, tnode,
176197201Spjd						cnp->cn_lkflags, vpp);
177197201Spjd				if (error != 0)
178197201Spjd					goto out;
179197201Spjd
180222518Spjd				if ((dnode->tn_mode & S_ISTXT) &&
181222518Spjd				  VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, cnp->cn_thread) &&
182222518Spjd				  VOP_ACCESS(*vpp, VADMIN, cnp->cn_cred, cnp->cn_thread)) {
183222518Spjd					error = EPERM;
184222518Spjd					vput(*vpp);
185197201Spjd					*vpp = NULL;
186197201Spjd					goto out;
187197201Spjd				}
188197201Spjd				cnp->cn_flags |= SAVENAME;
189197201Spjd			} else {
190185029Spjd				error = tmpfs_alloc_vp(dvp->v_mount, tnode,
191185029Spjd						cnp->cn_lkflags, vpp);
192185029Spjd			}
193185029Spjd		}
194185029Spjd	}
195191990Sattilio
196185029Spjd	/* Store the result of this lookup in the cache.  Avoid this if the
197168404Spjd	 * request was for creation, as it does not improve timings on
198219089Spjd	 * emprical tests. */
199315844Savg	if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE)
200315844Savg		cache_enter(dvp, *vpp, cnp);
201315844Savg
202315844Savgout:
203315844Savg	/* If there were no errors, *vpp cannot be null and it must be
204315844Savg	 * locked. */
205315844Savg	MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp)));
206242572Savg
207242572Savg	return error;
208242572Savg}
209315844Savg
210219089Spjd/* --------------------------------------------------------------------- */
211297021Smav
212324295Savgstatic int
213219089Spjdtmpfs_create(struct vop_create_args *v)
214219089Spjd{
215168404Spjd	struct vnode *dvp = v->a_dvp;
216219089Spjd	struct vnode **vpp = v->a_vpp;
217219089Spjd	struct componentname *cnp = v->a_cnp;
218219089Spjd	struct vattr *vap = v->a_vap;
219219089Spjd
220219089Spjd	MPASS(vap->va_type == VREG || vap->va_type == VSOCK);
221219089Spjd
222168404Spjd	return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
223168404Spjd}
224168404Spjd/* --------------------------------------------------------------------- */
225168404Spjd
226168404Spjdstatic int
227219089Spjdtmpfs_mknod(struct vop_mknod_args *v)
228175202Sattilio{
229168824Spjd	struct vnode *dvp = v->a_dvp;
230168824Spjd	struct vnode **vpp = v->a_vpp;
231168824Spjd	struct componentname *cnp = v->a_cnp;
232197201Spjd	struct vattr *vap = v->a_vap;
233197201Spjd
234197201Spjd	if (vap->va_type != VBLK && vap->va_type != VCHR &&
235168404Spjd	    vap->va_type != VFIFO)
236219089Spjd		return EINVAL;
237219089Spjd
238219089Spjd	return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
239219089Spjd}
240219089Spjd
241219089Spjd/* --------------------------------------------------------------------- */
242219089Spjd
243219089Spjdstatic int
244302724Savgtmpfs_open(struct vop_open_args *v)
245219089Spjd{
246219089Spjd	struct vnode *vp = v->a_vp;
247219089Spjd	int mode = v->a_mode;
248168404Spjd
249	int error;
250	struct tmpfs_node *node;
251
252	MPASS(VOP_ISLOCKED(vp));
253
254	node = VP_TO_TMPFS_NODE(vp);
255
256	/* The file is still active but all its names have been removed
257	 * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
258	 * it is about to die. */
259	if (node->tn_links < 1)
260		return (ENOENT);
261
262	/* If the file is marked append-only, deny write requests. */
263	if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
264		error = EPERM;
265	else {
266		error = 0;
267		/* For regular files, the call below is nop. */
268		vnode_create_vobject(vp, node->tn_size, v->a_td);
269	}
270
271	MPASS(VOP_ISLOCKED(vp));
272	return error;
273}
274
275/* --------------------------------------------------------------------- */
276
277static int
278tmpfs_close(struct vop_close_args *v)
279{
280	struct vnode *vp = v->a_vp;
281
282	/* Update node times. */
283	tmpfs_update(vp);
284
285	return (0);
286}
287
288/* --------------------------------------------------------------------- */
289
290int
291tmpfs_access(struct vop_access_args *v)
292{
293	struct vnode *vp = v->a_vp;
294	accmode_t accmode = v->a_accmode;
295	struct ucred *cred = v->a_cred;
296
297	int error;
298	struct tmpfs_node *node;
299
300	MPASS(VOP_ISLOCKED(vp));
301
302	node = VP_TO_TMPFS_NODE(vp);
303
304	switch (vp->v_type) {
305	case VDIR:
306		/* FALLTHROUGH */
307	case VLNK:
308		/* FALLTHROUGH */
309	case VREG:
310		if (accmode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) {
311			error = EROFS;
312			goto out;
313		}
314		break;
315
316	case VBLK:
317		/* FALLTHROUGH */
318	case VCHR:
319		/* FALLTHROUGH */
320	case VSOCK:
321		/* FALLTHROUGH */
322	case VFIFO:
323		break;
324
325	default:
326		error = EINVAL;
327		goto out;
328	}
329
330	if (accmode & VWRITE && node->tn_flags & IMMUTABLE) {
331		error = EPERM;
332		goto out;
333	}
334
335	error = vaccess(vp->v_type, node->tn_mode, node->tn_uid,
336	    node->tn_gid, accmode, cred, NULL);
337
338out:
339	MPASS(VOP_ISLOCKED(vp));
340
341	return error;
342}
343
344/* --------------------------------------------------------------------- */
345
346int
347tmpfs_getattr(struct vop_getattr_args *v)
348{
349	struct vnode *vp = v->a_vp;
350	struct vattr *vap = v->a_vap;
351
352	struct tmpfs_node *node;
353
354	node = VP_TO_TMPFS_NODE(vp);
355
356	tmpfs_update(vp);
357
358	vap->va_type = vp->v_type;
359	vap->va_mode = node->tn_mode;
360	vap->va_nlink = node->tn_links;
361	vap->va_uid = node->tn_uid;
362	vap->va_gid = node->tn_gid;
363	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
364	vap->va_fileid = node->tn_id;
365	vap->va_size = node->tn_size;
366	vap->va_blocksize = PAGE_SIZE;
367	vap->va_atime = node->tn_atime;
368	vap->va_mtime = node->tn_mtime;
369	vap->va_ctime = node->tn_ctime;
370	vap->va_birthtime = node->tn_birthtime;
371	vap->va_gen = node->tn_gen;
372	vap->va_flags = node->tn_flags;
373	vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ?
374		node->tn_rdev : NODEV;
375	vap->va_bytes = round_page(node->tn_size);
376	vap->va_filerev = 0;
377
378	return 0;
379}
380
381int
382tmpfs_setattr(struct vop_setattr_args *v)
383{
384	struct vnode *vp = v->a_vp;
385	struct vattr *vap = v->a_vap;
386	struct ucred *cred = v->a_cred;
387	struct thread *td = curthread;
388
389	int error;
390
391	MPASS(VOP_ISLOCKED(vp));
392
393	error = 0;
394
395	/* Abort if any unsettable attribute is given. */
396	if (vap->va_type != VNON ||
397	    vap->va_nlink != VNOVAL ||
398	    vap->va_fsid != VNOVAL ||
399	    vap->va_fileid != VNOVAL ||
400	    vap->va_blocksize != VNOVAL ||
401	    vap->va_gen != VNOVAL ||
402	    vap->va_rdev != VNOVAL ||
403	    vap->va_bytes != VNOVAL)
404		error = EINVAL;
405
406	if (error == 0 && (vap->va_flags != VNOVAL))
407		error = tmpfs_chflags(vp, vap->va_flags, cred, td);
408
409	if (error == 0 && (vap->va_size != VNOVAL))
410		error = tmpfs_chsize(vp, vap->va_size, cred, td);
411
412	if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
413		error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, td);
414
415	if (error == 0 && (vap->va_mode != (mode_t)VNOVAL))
416		error = tmpfs_chmod(vp, vap->va_mode, cred, td);
417
418	if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL &&
419	    vap->va_atime.tv_nsec != VNOVAL) ||
420	    (vap->va_mtime.tv_sec != VNOVAL &&
421	    vap->va_mtime.tv_nsec != VNOVAL) ||
422	    (vap->va_birthtime.tv_sec != VNOVAL &&
423	    vap->va_birthtime.tv_nsec != VNOVAL)))
424		error = tmpfs_chtimes(vp, vap, cred, td);
425
426	/* Update the node times.  We give preference to the error codes
427	 * generated by this function rather than the ones that may arise
428	 * from tmpfs_update. */
429	tmpfs_update(vp);
430
431	MPASS(VOP_ISLOCKED(vp));
432
433	return error;
434}
435
436static int
437tmpfs_read(struct vop_read_args *v)
438{
439	struct vnode *vp;
440	struct uio *uio;
441	struct tmpfs_node *node;
442
443	vp = v->a_vp;
444	if (vp->v_type != VREG)
445		return (EISDIR);
446	uio = v->a_uio;
447	if (uio->uio_offset < 0)
448		return (EINVAL);
449	node = VP_TO_TMPFS_NODE(vp);
450	node->tn_status |= TMPFS_NODE_ACCESSED;
451	return (uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio));
452}
453
454static int
455tmpfs_write(struct vop_write_args *v)
456{
457	struct vnode *vp;
458	struct uio *uio;
459	struct tmpfs_node *node;
460	off_t oldsize;
461	int error, ioflag;
462	boolean_t extended;
463
464	vp = v->a_vp;
465	uio = v->a_uio;
466	ioflag = v->a_ioflag;
467	error = 0;
468	node = VP_TO_TMPFS_NODE(vp);
469	oldsize = node->tn_size;
470
471	if (uio->uio_offset < 0 || vp->v_type != VREG)
472		return (EINVAL);
473	if (uio->uio_resid == 0)
474		return (0);
475	if (ioflag & IO_APPEND)
476		uio->uio_offset = node->tn_size;
477	if (uio->uio_offset + uio->uio_resid >
478	  VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize)
479		return (EFBIG);
480	if (vn_rlimit_fsize(vp, uio, uio->uio_td))
481		return (EFBIG);
482	extended = uio->uio_offset + uio->uio_resid > node->tn_size;
483	if (extended) {
484		error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid,
485		    FALSE);
486		if (error != 0)
487			goto out;
488	}
489
490	error = uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio);
491	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
492	    (extended ? TMPFS_NODE_CHANGED : 0);
493	if (node->tn_mode & (S_ISUID | S_ISGID)) {
494		if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0))
495			node->tn_mode &= ~(S_ISUID | S_ISGID);
496	}
497	if (error != 0)
498		(void)tmpfs_reg_resize(vp, oldsize, TRUE);
499
500out:
501	MPASS(IMPLIES(error == 0, uio->uio_resid == 0));
502	MPASS(IMPLIES(error != 0, oldsize == node->tn_size));
503
504	return (error);
505}
506
507/* --------------------------------------------------------------------- */
508
509static int
510tmpfs_fsync(struct vop_fsync_args *v)
511{
512	struct vnode *vp = v->a_vp;
513
514	MPASS(VOP_ISLOCKED(vp));
515
516	tmpfs_update(vp);
517
518	return 0;
519}
520
521/* --------------------------------------------------------------------- */
522
523static int
524tmpfs_remove(struct vop_remove_args *v)
525{
526	struct vnode *dvp = v->a_dvp;
527	struct vnode *vp = v->a_vp;
528
529	int error;
530	struct tmpfs_dirent *de;
531	struct tmpfs_mount *tmp;
532	struct tmpfs_node *dnode;
533	struct tmpfs_node *node;
534
535	MPASS(VOP_ISLOCKED(dvp));
536	MPASS(VOP_ISLOCKED(vp));
537
538	if (vp->v_type == VDIR) {
539		error = EISDIR;
540		goto out;
541	}
542
543	dnode = VP_TO_TMPFS_DIR(dvp);
544	node = VP_TO_TMPFS_NODE(vp);
545	tmp = VFS_TO_TMPFS(vp->v_mount);
546	de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
547	MPASS(de != NULL);
548
549	/* Files marked as immutable or append-only cannot be deleted. */
550	if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) ||
551	    (dnode->tn_flags & APPEND)) {
552		error = EPERM;
553		goto out;
554	}
555
556	/* Remove the entry from the directory; as it is a file, we do not
557	 * have to change the number of hard links of the directory. */
558	tmpfs_dir_detach(dvp, de);
559	if (v->a_cnp->cn_flags & DOWHITEOUT)
560		tmpfs_dir_whiteout_add(dvp, v->a_cnp);
561
562	/* Free the directory entry we just deleted.  Note that the node
563	 * referred by it will not be removed until the vnode is really
564	 * reclaimed. */
565	tmpfs_free_dirent(tmp, de);
566
567	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED;
568	error = 0;
569
570out:
571
572	return error;
573}
574
575/* --------------------------------------------------------------------- */
576
577static int
578tmpfs_link(struct vop_link_args *v)
579{
580	struct vnode *dvp = v->a_tdvp;
581	struct vnode *vp = v->a_vp;
582	struct componentname *cnp = v->a_cnp;
583
584	int error;
585	struct tmpfs_dirent *de;
586	struct tmpfs_node *node;
587
588	MPASS(VOP_ISLOCKED(dvp));
589	MPASS(cnp->cn_flags & HASBUF);
590	MPASS(dvp != vp); /* XXX When can this be false? */
591
592	node = VP_TO_TMPFS_NODE(vp);
593
594	/* XXX: Why aren't the following two tests done by the caller? */
595
596	/* Hard links of directories are forbidden. */
597	if (vp->v_type == VDIR) {
598		error = EPERM;
599		goto out;
600	}
601
602	/* Cannot create cross-device links. */
603	if (dvp->v_mount != vp->v_mount) {
604		error = EXDEV;
605		goto out;
606	}
607
608	/* Ensure that we do not overflow the maximum number of links imposed
609	 * by the system. */
610	MPASS(node->tn_links <= LINK_MAX);
611	if (node->tn_links == LINK_MAX) {
612		error = EMLINK;
613		goto out;
614	}
615
616	/* We cannot create links of files marked immutable or append-only. */
617	if (node->tn_flags & (IMMUTABLE | APPEND)) {
618		error = EPERM;
619		goto out;
620	}
621
622	/* Allocate a new directory entry to represent the node. */
623	error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node,
624	    cnp->cn_nameptr, cnp->cn_namelen, &de);
625	if (error != 0)
626		goto out;
627
628	/* Insert the new directory entry into the appropriate directory. */
629	if (cnp->cn_flags & ISWHITEOUT)
630		tmpfs_dir_whiteout_remove(dvp, cnp);
631	tmpfs_dir_attach(dvp, de);
632
633	/* vp link count has changed, so update node times. */
634	node->tn_status |= TMPFS_NODE_CHANGED;
635	tmpfs_update(vp);
636
637	error = 0;
638
639out:
640	return error;
641}
642
643/* --------------------------------------------------------------------- */
644
645/*
646 * We acquire all but fdvp locks using non-blocking acquisitions.  If we
647 * fail to acquire any lock in the path we will drop all held locks,
648 * acquire the new lock in a blocking fashion, and then release it and
649 * restart the rename.  This acquire/release step ensures that we do not
650 * spin on a lock waiting for release.  On error release all vnode locks
651 * and decrement references the way tmpfs_rename() would do.
652 */
653static int
654tmpfs_rename_relock(struct vnode *fdvp, struct vnode **fvpp,
655    struct vnode *tdvp, struct vnode **tvpp,
656    struct componentname *fcnp, struct componentname *tcnp)
657{
658	struct vnode *nvp;
659	struct mount *mp;
660	struct tmpfs_dirent *de;
661	int error, restarts = 0;
662
663	VOP_UNLOCK(tdvp, 0);
664	if (*tvpp != NULL && *tvpp != tdvp)
665		VOP_UNLOCK(*tvpp, 0);
666	mp = fdvp->v_mount;
667
668relock:
669	restarts += 1;
670	error = vn_lock(fdvp, LK_EXCLUSIVE);
671	if (error)
672		goto releout;
673	if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
674		VOP_UNLOCK(fdvp, 0);
675		error = vn_lock(tdvp, LK_EXCLUSIVE);
676		if (error)
677			goto releout;
678		VOP_UNLOCK(tdvp, 0);
679		goto relock;
680	}
681	/*
682	 * Re-resolve fvp to be certain it still exists and fetch the
683	 * correct vnode.
684	 */
685	de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(fdvp), NULL, fcnp);
686	if (de == NULL) {
687		VOP_UNLOCK(fdvp, 0);
688		VOP_UNLOCK(tdvp, 0);
689		if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
690		    (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
691			error = EINVAL;
692		else
693			error = ENOENT;
694		goto releout;
695	}
696	error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE | LK_NOWAIT, &nvp);
697	if (error != 0) {
698		VOP_UNLOCK(fdvp, 0);
699		VOP_UNLOCK(tdvp, 0);
700		if (error != EBUSY)
701			goto releout;
702		error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE, &nvp);
703		if (error != 0)
704			goto releout;
705		VOP_UNLOCK(nvp, 0);
706		/*
707		 * Concurrent rename race.
708		 */
709		if (nvp == tdvp) {
710			vrele(nvp);
711			error = EINVAL;
712			goto releout;
713		}
714		vrele(*fvpp);
715		*fvpp = nvp;
716		goto relock;
717	}
718	vrele(*fvpp);
719	*fvpp = nvp;
720	VOP_UNLOCK(*fvpp, 0);
721	/*
722	 * Re-resolve tvp and acquire the vnode lock if present.
723	 */
724	de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(tdvp), NULL, tcnp);
725	/*
726	 * If tvp disappeared we just carry on.
727	 */
728	if (de == NULL && *tvpp != NULL) {
729		vrele(*tvpp);
730		*tvpp = NULL;
731	}
732	/*
733	 * Get the tvp ino if the lookup succeeded.  We may have to restart
734	 * if the non-blocking acquire fails.
735	 */
736	if (de != NULL) {
737		nvp = NULL;
738		error = tmpfs_alloc_vp(mp, de->td_node,
739		    LK_EXCLUSIVE | LK_NOWAIT, &nvp);
740		if (*tvpp != NULL)
741			vrele(*tvpp);
742		*tvpp = nvp;
743		if (error != 0) {
744			VOP_UNLOCK(fdvp, 0);
745			VOP_UNLOCK(tdvp, 0);
746			if (error != EBUSY)
747				goto releout;
748			error = tmpfs_alloc_vp(mp, de->td_node, LK_EXCLUSIVE,
749			    &nvp);
750			if (error != 0)
751				goto releout;
752			VOP_UNLOCK(nvp, 0);
753			/*
754			 * fdvp contains fvp, thus tvp (=fdvp) is not empty.
755			 */
756			if (nvp == fdvp) {
757				error = ENOTEMPTY;
758				goto releout;
759			}
760			goto relock;
761		}
762	}
763	tmpfs_rename_restarts += restarts;
764
765	return (0);
766
767releout:
768	vrele(fdvp);
769	vrele(*fvpp);
770	vrele(tdvp);
771	if (*tvpp != NULL)
772		vrele(*tvpp);
773	tmpfs_rename_restarts += restarts;
774
775	return (error);
776}
777
778static int
779tmpfs_rename(struct vop_rename_args *v)
780{
781	struct vnode *fdvp = v->a_fdvp;
782	struct vnode *fvp = v->a_fvp;
783	struct componentname *fcnp = v->a_fcnp;
784	struct vnode *tdvp = v->a_tdvp;
785	struct vnode *tvp = v->a_tvp;
786	struct componentname *tcnp = v->a_tcnp;
787	struct mount *mp = NULL;
788
789	char *newname;
790	int error;
791	struct tmpfs_dirent *de;
792	struct tmpfs_mount *tmp;
793	struct tmpfs_node *fdnode;
794	struct tmpfs_node *fnode;
795	struct tmpfs_node *tnode;
796	struct tmpfs_node *tdnode;
797
798	MPASS(VOP_ISLOCKED(tdvp));
799	MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp)));
800	MPASS(fcnp->cn_flags & HASBUF);
801	MPASS(tcnp->cn_flags & HASBUF);
802
803	/* Disallow cross-device renames.
804	 * XXX Why isn't this done by the caller? */
805	if (fvp->v_mount != tdvp->v_mount ||
806	    (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
807		error = EXDEV;
808		goto out;
809	}
810
811	/* If source and target are the same file, there is nothing to do. */
812	if (fvp == tvp) {
813		error = 0;
814		goto out;
815	}
816
817	/* If we need to move the directory between entries, lock the
818	 * source so that we can safely operate on it. */
819	if (fdvp != tdvp && fdvp != tvp) {
820		if (vn_lock(fdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
821			mp = tdvp->v_mount;
822			error = vfs_busy(mp, 0);
823			if (error != 0) {
824				mp = NULL;
825				goto out;
826			}
827			error = tmpfs_rename_relock(fdvp, &fvp, tdvp, &tvp,
828			    fcnp, tcnp);
829			if (error != 0) {
830				vfs_unbusy(mp);
831				return (error);
832			}
833			ASSERT_VOP_ELOCKED(fdvp,
834			    "tmpfs_rename: fdvp not locked");
835			ASSERT_VOP_ELOCKED(tdvp,
836			    "tmpfs_rename: tdvp not locked");
837			if (tvp != NULL)
838				ASSERT_VOP_ELOCKED(tvp,
839				    "tmpfs_rename: tvp not locked");
840			if (fvp == tvp) {
841				error = 0;
842				goto out_locked;
843			}
844		}
845	}
846
847	tmp = VFS_TO_TMPFS(tdvp->v_mount);
848	tdnode = VP_TO_TMPFS_DIR(tdvp);
849	tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp);
850	fdnode = VP_TO_TMPFS_DIR(fdvp);
851	fnode = VP_TO_TMPFS_NODE(fvp);
852	de = tmpfs_dir_lookup(fdnode, fnode, fcnp);
853
854	/* Entry can disappear before we lock fdvp,
855	 * also avoid manipulating '.' and '..' entries. */
856	if (de == NULL) {
857		if ((fcnp->cn_flags & ISDOTDOT) != 0 ||
858		    (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.'))
859			error = EINVAL;
860		else
861			error = ENOENT;
862		goto out_locked;
863	}
864	MPASS(de->td_node == fnode);
865
866	/* If re-naming a directory to another preexisting directory
867	 * ensure that the target directory is empty so that its
868	 * removal causes no side effects.
869	 * Kern_rename gurantees the destination to be a directory
870	 * if the source is one. */
871	if (tvp != NULL) {
872		MPASS(tnode != NULL);
873
874		if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
875		    (tdnode->tn_flags & (APPEND | IMMUTABLE))) {
876			error = EPERM;
877			goto out_locked;
878		}
879
880		if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) {
881			if (tnode->tn_size > 0) {
882				error = ENOTEMPTY;
883				goto out_locked;
884			}
885		} else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) {
886			error = ENOTDIR;
887			goto out_locked;
888		} else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) {
889			error = EISDIR;
890			goto out_locked;
891		} else {
892			MPASS(fnode->tn_type != VDIR &&
893				tnode->tn_type != VDIR);
894		}
895	}
896
897	if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))
898	    || (fdnode->tn_flags & (APPEND | IMMUTABLE))) {
899		error = EPERM;
900		goto out_locked;
901	}
902
903	/* Ensure that we have enough memory to hold the new name, if it
904	 * has to be changed. */
905	if (fcnp->cn_namelen != tcnp->cn_namelen ||
906	    bcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) {
907		newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK);
908	} else
909		newname = NULL;
910
911	/* If the node is being moved to another directory, we have to do
912	 * the move. */
913	if (fdnode != tdnode) {
914		/* In case we are moving a directory, we have to adjust its
915		 * parent to point to the new parent. */
916		if (de->td_node->tn_type == VDIR) {
917			struct tmpfs_node *n;
918
919			/* Ensure the target directory is not a child of the
920			 * directory being moved.  Otherwise, we'd end up
921			 * with stale nodes. */
922			n = tdnode;
923			/* TMPFS_LOCK garanties that no nodes are freed while
924			 * traversing the list. Nodes can only be marked as
925			 * removed: tn_parent == NULL. */
926			TMPFS_LOCK(tmp);
927			TMPFS_NODE_LOCK(n);
928			while (n != n->tn_dir.tn_parent) {
929				struct tmpfs_node *parent;
930
931				if (n == fnode) {
932					TMPFS_NODE_UNLOCK(n);
933					TMPFS_UNLOCK(tmp);
934					error = EINVAL;
935					if (newname != NULL)
936						    free(newname, M_TMPFSNAME);
937					goto out_locked;
938				}
939				parent = n->tn_dir.tn_parent;
940				TMPFS_NODE_UNLOCK(n);
941				if (parent == NULL) {
942					n = NULL;
943					break;
944				}
945				TMPFS_NODE_LOCK(parent);
946				if (parent->tn_dir.tn_parent == NULL) {
947					TMPFS_NODE_UNLOCK(parent);
948					n = NULL;
949					break;
950				}
951				n = parent;
952			}
953			TMPFS_UNLOCK(tmp);
954			if (n == NULL) {
955				error = EINVAL;
956				if (newname != NULL)
957					    free(newname, M_TMPFSNAME);
958				goto out_locked;
959			}
960			TMPFS_NODE_UNLOCK(n);
961
962			/* Adjust the parent pointer. */
963			TMPFS_VALIDATE_DIR(fnode);
964			TMPFS_NODE_LOCK(de->td_node);
965			de->td_node->tn_dir.tn_parent = tdnode;
966			TMPFS_NODE_UNLOCK(de->td_node);
967
968			/* As a result of changing the target of the '..'
969			 * entry, the link count of the source and target
970			 * directories has to be adjusted. */
971			TMPFS_NODE_LOCK(tdnode);
972			TMPFS_ASSERT_LOCKED(tdnode);
973			tdnode->tn_links++;
974			TMPFS_NODE_UNLOCK(tdnode);
975
976			TMPFS_NODE_LOCK(fdnode);
977			TMPFS_ASSERT_LOCKED(fdnode);
978			fdnode->tn_links--;
979			TMPFS_NODE_UNLOCK(fdnode);
980		}
981	}
982
983	/* Do the move: just remove the entry from the source directory
984	 * and insert it into the target one. */
985	tmpfs_dir_detach(fdvp, de);
986
987	if (fcnp->cn_flags & DOWHITEOUT)
988		tmpfs_dir_whiteout_add(fdvp, fcnp);
989	if (tcnp->cn_flags & ISWHITEOUT)
990		tmpfs_dir_whiteout_remove(tdvp, tcnp);
991
992	/* If the name has changed, we need to make it effective by changing
993	 * it in the directory entry. */
994	if (newname != NULL) {
995		MPASS(tcnp->cn_namelen <= MAXNAMLEN);
996
997		free(de->ud.td_name, M_TMPFSNAME);
998		de->ud.td_name = newname;
999		tmpfs_dirent_init(de, tcnp->cn_nameptr, tcnp->cn_namelen);
1000
1001		fnode->tn_status |= TMPFS_NODE_CHANGED;
1002		tdnode->tn_status |= TMPFS_NODE_MODIFIED;
1003	}
1004
1005	/* If we are overwriting an entry, we have to remove the old one
1006	 * from the target directory. */
1007	if (tvp != NULL) {
1008		struct tmpfs_dirent *tde;
1009
1010		/* Remove the old entry from the target directory. */
1011		tde = tmpfs_dir_lookup(tdnode, tnode, tcnp);
1012		tmpfs_dir_detach(tdvp, tde);
1013
1014		/* Free the directory entry we just deleted.  Note that the
1015		 * node referred by it will not be removed until the vnode is
1016		 * really reclaimed. */
1017		tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), tde);
1018	}
1019
1020	tmpfs_dir_attach(tdvp, de);
1021
1022	cache_purge(fvp);
1023	if (tvp != NULL)
1024		cache_purge(tvp);
1025	cache_purge_negative(tdvp);
1026
1027	error = 0;
1028
1029out_locked:
1030	if (fdvp != tdvp && fdvp != tvp)
1031		VOP_UNLOCK(fdvp, 0);
1032
1033out:
1034	/* Release target nodes. */
1035	/* XXX: I don't understand when tdvp can be the same as tvp, but
1036	 * other code takes care of this... */
1037	if (tdvp == tvp)
1038		vrele(tdvp);
1039	else
1040		vput(tdvp);
1041	if (tvp != NULL)
1042		vput(tvp);
1043
1044	/* Release source nodes. */
1045	vrele(fdvp);
1046	vrele(fvp);
1047
1048	if (mp != NULL)
1049		vfs_unbusy(mp);
1050
1051	return error;
1052}
1053
1054/* --------------------------------------------------------------------- */
1055
1056static int
1057tmpfs_mkdir(struct vop_mkdir_args *v)
1058{
1059	struct vnode *dvp = v->a_dvp;
1060	struct vnode **vpp = v->a_vpp;
1061	struct componentname *cnp = v->a_cnp;
1062	struct vattr *vap = v->a_vap;
1063
1064	MPASS(vap->va_type == VDIR);
1065
1066	return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
1067}
1068
1069/* --------------------------------------------------------------------- */
1070
1071static int
1072tmpfs_rmdir(struct vop_rmdir_args *v)
1073{
1074	struct vnode *dvp = v->a_dvp;
1075	struct vnode *vp = v->a_vp;
1076
1077	int error;
1078	struct tmpfs_dirent *de;
1079	struct tmpfs_mount *tmp;
1080	struct tmpfs_node *dnode;
1081	struct tmpfs_node *node;
1082
1083	MPASS(VOP_ISLOCKED(dvp));
1084	MPASS(VOP_ISLOCKED(vp));
1085
1086	tmp = VFS_TO_TMPFS(dvp->v_mount);
1087	dnode = VP_TO_TMPFS_DIR(dvp);
1088	node = VP_TO_TMPFS_DIR(vp);
1089
1090	/* Directories with more than two entries ('.' and '..') cannot be
1091	 * removed. */
1092	 if (node->tn_size > 0) {
1093		 error = ENOTEMPTY;
1094		 goto out;
1095	 }
1096
1097	if ((dnode->tn_flags & APPEND)
1098	    || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1099		error = EPERM;
1100		goto out;
1101	}
1102
1103	/* This invariant holds only if we are not trying to remove "..".
1104	  * We checked for that above so this is safe now. */
1105	MPASS(node->tn_dir.tn_parent == dnode);
1106
1107	/* Get the directory entry associated with node (vp).  This was
1108	 * filled by tmpfs_lookup while looking up the entry. */
1109	de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
1110	MPASS(TMPFS_DIRENT_MATCHES(de,
1111	    v->a_cnp->cn_nameptr,
1112	    v->a_cnp->cn_namelen));
1113
1114	/* Check flags to see if we are allowed to remove the directory. */
1115	if (dnode->tn_flags & APPEND
1116		|| node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) {
1117		error = EPERM;
1118		goto out;
1119	}
1120
1121
1122	/* Detach the directory entry from the directory (dnode). */
1123	tmpfs_dir_detach(dvp, de);
1124	if (v->a_cnp->cn_flags & DOWHITEOUT)
1125		tmpfs_dir_whiteout_add(dvp, v->a_cnp);
1126
1127	/* No vnode should be allocated for this entry from this point */
1128	TMPFS_NODE_LOCK(node);
1129	TMPFS_ASSERT_ELOCKED(node);
1130	node->tn_links--;
1131	node->tn_dir.tn_parent = NULL;
1132	node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
1133	    TMPFS_NODE_MODIFIED;
1134
1135	TMPFS_NODE_UNLOCK(node);
1136
1137	TMPFS_NODE_LOCK(dnode);
1138	TMPFS_ASSERT_ELOCKED(dnode);
1139	dnode->tn_links--;
1140	dnode->tn_status |= TMPFS_NODE_ACCESSED | \
1141	    TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
1142	TMPFS_NODE_UNLOCK(dnode);
1143
1144	cache_purge(dvp);
1145	cache_purge(vp);
1146
1147	/* Free the directory entry we just deleted.  Note that the node
1148	 * referred by it will not be removed until the vnode is really
1149	 * reclaimed. */
1150	tmpfs_free_dirent(tmp, de);
1151
1152	/* Release the deleted vnode (will destroy the node, notify
1153	 * interested parties and clean it from the cache). */
1154
1155	dnode->tn_status |= TMPFS_NODE_CHANGED;
1156	tmpfs_update(dvp);
1157
1158	error = 0;
1159
1160out:
1161	return error;
1162}
1163
1164/* --------------------------------------------------------------------- */
1165
1166static int
1167tmpfs_symlink(struct vop_symlink_args *v)
1168{
1169	struct vnode *dvp = v->a_dvp;
1170	struct vnode **vpp = v->a_vpp;
1171	struct componentname *cnp = v->a_cnp;
1172	struct vattr *vap = v->a_vap;
1173	char *target = v->a_target;
1174
1175#ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */
1176	MPASS(vap->va_type == VLNK);
1177#else
1178	vap->va_type = VLNK;
1179#endif
1180
1181	return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
1182}
1183
1184/* --------------------------------------------------------------------- */
1185
1186static int
1187tmpfs_readdir(struct vop_readdir_args *v)
1188{
1189	struct vnode *vp = v->a_vp;
1190	struct uio *uio = v->a_uio;
1191	int *eofflag = v->a_eofflag;
1192	u_long **cookies = v->a_cookies;
1193	int *ncookies = v->a_ncookies;
1194
1195	int error;
1196	ssize_t startresid;
1197	int maxcookies;
1198	struct tmpfs_node *node;
1199
1200	/* This operation only makes sense on directory nodes. */
1201	if (vp->v_type != VDIR)
1202		return ENOTDIR;
1203
1204	maxcookies = 0;
1205	node = VP_TO_TMPFS_DIR(vp);
1206
1207	startresid = uio->uio_resid;
1208
1209	/* Allocate cookies for NFS and compat modules. */
1210	if (cookies != NULL && ncookies != NULL) {
1211		maxcookies = howmany(node->tn_size,
1212		    sizeof(struct tmpfs_dirent)) + 2;
1213		*cookies = malloc(maxcookies * sizeof(**cookies), M_TEMP,
1214		    M_WAITOK);
1215		*ncookies = 0;
1216	}
1217
1218	if (cookies == NULL)
1219		error = tmpfs_dir_getdents(node, uio, 0, NULL, NULL);
1220	else
1221		error = tmpfs_dir_getdents(node, uio, maxcookies, *cookies,
1222		    ncookies);
1223
1224	/* Buffer was filled without hitting EOF. */
1225	if (error == EJUSTRETURN)
1226		error = (uio->uio_resid != startresid) ? 0 : EINVAL;
1227
1228	if (error != 0 && cookies != NULL)
1229		free(*cookies, M_TEMP);
1230
1231	if (eofflag != NULL)
1232		*eofflag =
1233		    (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
1234
1235	return error;
1236}
1237
1238/* --------------------------------------------------------------------- */
1239
1240static int
1241tmpfs_readlink(struct vop_readlink_args *v)
1242{
1243	struct vnode *vp = v->a_vp;
1244	struct uio *uio = v->a_uio;
1245
1246	int error;
1247	struct tmpfs_node *node;
1248
1249	MPASS(uio->uio_offset == 0);
1250	MPASS(vp->v_type == VLNK);
1251
1252	node = VP_TO_TMPFS_NODE(vp);
1253
1254	error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
1255	    uio);
1256	node->tn_status |= TMPFS_NODE_ACCESSED;
1257
1258	return error;
1259}
1260
1261/* --------------------------------------------------------------------- */
1262
1263static int
1264tmpfs_inactive(struct vop_inactive_args *v)
1265{
1266	struct vnode *vp = v->a_vp;
1267
1268	struct tmpfs_node *node;
1269
1270	node = VP_TO_TMPFS_NODE(vp);
1271
1272	if (node->tn_links == 0)
1273		vrecycle(vp);
1274
1275	return 0;
1276}
1277
1278/* --------------------------------------------------------------------- */
1279
1280int
1281tmpfs_reclaim(struct vop_reclaim_args *v)
1282{
1283	struct vnode *vp = v->a_vp;
1284
1285	struct tmpfs_mount *tmp;
1286	struct tmpfs_node *node;
1287
1288	node = VP_TO_TMPFS_NODE(vp);
1289	tmp = VFS_TO_TMPFS(vp->v_mount);
1290
1291	if (vp->v_type == VREG)
1292		tmpfs_destroy_vobject(vp, node->tn_reg.tn_aobj);
1293	else
1294		vnode_destroy_vobject(vp);
1295	vp->v_object = NULL;
1296	cache_purge(vp);
1297
1298	TMPFS_NODE_LOCK(node);
1299	TMPFS_ASSERT_ELOCKED(node);
1300	tmpfs_free_vp(vp);
1301
1302	/* If the node referenced by this vnode was deleted by the user,
1303	 * we must free its associated data structures (now that the vnode
1304	 * is being reclaimed). */
1305	if (node->tn_links == 0 &&
1306	    (node->tn_vpstate & TMPFS_VNODE_ALLOCATING) == 0) {
1307		node->tn_vpstate = TMPFS_VNODE_DOOMED;
1308		TMPFS_NODE_UNLOCK(node);
1309		tmpfs_free_node(tmp, node);
1310	} else
1311		TMPFS_NODE_UNLOCK(node);
1312
1313	MPASS(vp->v_data == NULL);
1314	return 0;
1315}
1316
1317/* --------------------------------------------------------------------- */
1318
1319static int
1320tmpfs_print(struct vop_print_args *v)
1321{
1322	struct vnode *vp = 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%lx, links %d\n",
1329	    node, node->tn_flags, node->tn_links);
1330	printf("\tmode 0%o, owner %d, group %d, size %jd, status 0x%x\n",
1331	    node->tn_mode, node->tn_uid, node->tn_gid,
1332	    (intmax_t)node->tn_size, node->tn_status);
1333
1334	if (vp->v_type == VFIFO)
1335		fifo_printinfo(vp);
1336
1337	printf("\n");
1338
1339	return 0;
1340}
1341
1342/* --------------------------------------------------------------------- */
1343
1344static int
1345tmpfs_pathconf(struct vop_pathconf_args *v)
1346{
1347	int name = v->a_name;
1348	register_t *retval = v->a_retval;
1349
1350	int error;
1351
1352	error = 0;
1353
1354	switch (name) {
1355	case _PC_LINK_MAX:
1356		*retval = LINK_MAX;
1357		break;
1358
1359	case _PC_NAME_MAX:
1360		*retval = NAME_MAX;
1361		break;
1362
1363	case _PC_PATH_MAX:
1364		*retval = PATH_MAX;
1365		break;
1366
1367	case _PC_PIPE_BUF:
1368		*retval = PIPE_BUF;
1369		break;
1370
1371	case _PC_CHOWN_RESTRICTED:
1372		*retval = 1;
1373		break;
1374
1375	case _PC_NO_TRUNC:
1376		*retval = 1;
1377		break;
1378
1379	case _PC_SYNC_IO:
1380		*retval = 1;
1381		break;
1382
1383	case _PC_FILESIZEBITS:
1384		*retval = 0; /* XXX Don't know which value should I return. */
1385		break;
1386
1387	default:
1388		error = EINVAL;
1389	}
1390
1391	return error;
1392}
1393
1394static int
1395tmpfs_vptofh(struct vop_vptofh_args *ap)
1396{
1397	struct tmpfs_fid *tfhp;
1398	struct tmpfs_node *node;
1399
1400	tfhp = (struct tmpfs_fid *)ap->a_fhp;
1401	node = VP_TO_TMPFS_NODE(ap->a_vp);
1402
1403	tfhp->tf_len = sizeof(struct tmpfs_fid);
1404	tfhp->tf_id = node->tn_id;
1405	tfhp->tf_gen = node->tn_gen;
1406
1407	return (0);
1408}
1409
1410static int
1411tmpfs_whiteout(struct vop_whiteout_args *ap)
1412{
1413	struct vnode *dvp = ap->a_dvp;
1414	struct componentname *cnp = ap->a_cnp;
1415	struct tmpfs_dirent *de;
1416
1417	switch (ap->a_flags) {
1418	case LOOKUP:
1419		return (0);
1420	case CREATE:
1421		de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp);
1422		if (de != NULL)
1423			return (de->td_node == NULL ? 0 : EEXIST);
1424		return (tmpfs_dir_whiteout_add(dvp, cnp));
1425	case DELETE:
1426		tmpfs_dir_whiteout_remove(dvp, cnp);
1427		return (0);
1428	default:
1429		panic("tmpfs_whiteout: unknown op");
1430	}
1431}
1432
1433/* --------------------------------------------------------------------- */
1434
1435/*
1436 * vnode operations vector used for files stored in a tmpfs file system.
1437 */
1438struct vop_vector tmpfs_vnodeop_entries = {
1439	.vop_default =			&default_vnodeops,
1440	.vop_lookup =			vfs_cache_lookup,
1441	.vop_cachedlookup =		tmpfs_lookup,
1442	.vop_create =			tmpfs_create,
1443	.vop_mknod =			tmpfs_mknod,
1444	.vop_open =			tmpfs_open,
1445	.vop_close =			tmpfs_close,
1446	.vop_access =			tmpfs_access,
1447	.vop_getattr =			tmpfs_getattr,
1448	.vop_setattr =			tmpfs_setattr,
1449	.vop_read =			tmpfs_read,
1450	.vop_write =			tmpfs_write,
1451	.vop_fsync =			tmpfs_fsync,
1452	.vop_remove =			tmpfs_remove,
1453	.vop_link =			tmpfs_link,
1454	.vop_rename =			tmpfs_rename,
1455	.vop_mkdir =			tmpfs_mkdir,
1456	.vop_rmdir =			tmpfs_rmdir,
1457	.vop_symlink =			tmpfs_symlink,
1458	.vop_readdir =			tmpfs_readdir,
1459	.vop_readlink =			tmpfs_readlink,
1460	.vop_inactive =			tmpfs_inactive,
1461	.vop_reclaim =			tmpfs_reclaim,
1462	.vop_print =			tmpfs_print,
1463	.vop_pathconf =			tmpfs_pathconf,
1464	.vop_vptofh =			tmpfs_vptofh,
1465	.vop_whiteout =			tmpfs_whiteout,
1466	.vop_bmap =			VOP_EOPNOTSUPP,
1467};
1468
1469