tmpfs_vfsops.c revision 263943
1170808Sdelphij/*	$NetBSD: tmpfs_vfsops.c,v 1.10 2005/12/11 12:24:29 christos Exp $	*/
2170808Sdelphij
3182739Sdelphij/*-
4170808Sdelphij * Copyright (c) 2005 The NetBSD Foundation, Inc.
5170808Sdelphij * All rights reserved.
6170808Sdelphij *
7170808Sdelphij * This code is derived from software contributed to The NetBSD Foundation
8170808Sdelphij * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9170808Sdelphij * 2005 program.
10170808Sdelphij *
11170808Sdelphij * Redistribution and use in source and binary forms, with or without
12170808Sdelphij * modification, are permitted provided that the following conditions
13170808Sdelphij * are met:
14170808Sdelphij * 1. Redistributions of source code must retain the above copyright
15170808Sdelphij *    notice, this list of conditions and the following disclaimer.
16170808Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
17170808Sdelphij *    notice, this list of conditions and the following disclaimer in the
18170808Sdelphij *    documentation and/or other materials provided with the distribution.
19170808Sdelphij *
20170808Sdelphij * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21170808Sdelphij * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22170808Sdelphij * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23170808Sdelphij * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24170808Sdelphij * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25170808Sdelphij * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26170808Sdelphij * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27170808Sdelphij * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28170808Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29170808Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30170808Sdelphij * POSSIBILITY OF SUCH DAMAGE.
31170808Sdelphij */
32170808Sdelphij
33170808Sdelphij/*
34170808Sdelphij * Efficient memory file system.
35170808Sdelphij *
36170808Sdelphij * tmpfs is a file system that uses NetBSD's virtual memory sub-system
37170808Sdelphij * (the well-known UVM) to store file data and metadata in an efficient
38170808Sdelphij * way.  This means that it does not follow the structure of an on-disk
39170808Sdelphij * file system because it simply does not need to.  Instead, it uses
40170808Sdelphij * memory-specific data structures and algorithms to automatically
41170808Sdelphij * allocate and release resources.
42170808Sdelphij */
43170808Sdelphij#include <sys/cdefs.h>
44170808Sdelphij__FBSDID("$FreeBSD: stable/10/sys/fs/tmpfs/tmpfs_vfsops.c 263943 2014-03-30 16:51:12Z bdrewery $");
45170808Sdelphij
46170808Sdelphij#include <sys/param.h>
47171308Sdelphij#include <sys/limits.h>
48170808Sdelphij#include <sys/lock.h>
49170808Sdelphij#include <sys/mutex.h>
50254741Sdelphij#include <sys/proc.h>
51254741Sdelphij#include <sys/jail.h>
52170808Sdelphij#include <sys/kernel.h>
53170808Sdelphij#include <sys/stat.h>
54170808Sdelphij#include <sys/systm.h>
55170808Sdelphij#include <sys/sysctl.h>
56170808Sdelphij
57170808Sdelphij#include <vm/vm.h>
58170808Sdelphij#include <vm/vm_object.h>
59170808Sdelphij#include <vm/vm_param.h>
60170808Sdelphij
61170808Sdelphij#include <fs/tmpfs/tmpfs.h>
62170808Sdelphij
63170808Sdelphij/*
64171070Sdelphij * Default permission for root node
65170808Sdelphij */
66170808Sdelphij#define TMPFS_DEFAULT_ROOT_MODE	(S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
67170808Sdelphij
68170808SdelphijMALLOC_DEFINE(M_TMPFSMNT, "tmpfs mount", "tmpfs mount structures");
69171087SdelphijMALLOC_DEFINE(M_TMPFSNAME, "tmpfs name", "tmpfs file names");
70170808Sdelphij
71170808Sdelphij/* --------------------------------------------------------------------- */
72170808Sdelphij
73191990Sattiliostatic int	tmpfs_mount(struct mount *);
74191990Sattiliostatic int	tmpfs_unmount(struct mount *, int);
75191990Sattiliostatic int	tmpfs_root(struct mount *, int flags, struct vnode **);
76222167Srmacklemstatic int	tmpfs_fhtovp(struct mount *, struct fid *, int,
77222167Srmacklem		    struct vnode **);
78191990Sattiliostatic int	tmpfs_statfs(struct mount *, struct statfs *);
79170808Sdelphij
80170808Sdelphij/* --------------------------------------------------------------------- */
81170808Sdelphij
82170808Sdelphijstatic const char *tmpfs_opts[] = {
83203164Sjh	"from", "size", "maxfilesize", "inodes", "uid", "gid", "mode", "export",
84253573Snwhitehorn	"union", NULL
85170808Sdelphij};
86170808Sdelphij
87234346Sjhstatic const char *tmpfs_updateopts[] = {
88234346Sjh	"from", "export", NULL
89234346Sjh};
90234346Sjh
91170808Sdelphij/* --------------------------------------------------------------------- */
92170808Sdelphij
93171029Sdelphijstatic int
94171029Sdelphijtmpfs_node_ctor(void *mem, int size, void *arg, int flags)
95171029Sdelphij{
96171029Sdelphij	struct tmpfs_node *node = (struct tmpfs_node *)mem;
97171070Sdelphij
98171362Sdelphij	node->tn_gen++;
99171029Sdelphij	node->tn_size = 0;
100171029Sdelphij	node->tn_status = 0;
101171029Sdelphij	node->tn_flags = 0;
102171029Sdelphij	node->tn_links = 0;
103171029Sdelphij	node->tn_vnode = NULL;
104171029Sdelphij	node->tn_vpstate = 0;
105170808Sdelphij
106171029Sdelphij	return (0);
107171029Sdelphij}
108171029Sdelphij
109171029Sdelphijstatic void
110171029Sdelphijtmpfs_node_dtor(void *mem, int size, void *arg)
111171029Sdelphij{
112171029Sdelphij	struct tmpfs_node *node = (struct tmpfs_node *)mem;
113171029Sdelphij	node->tn_type = VNON;
114171029Sdelphij}
115171029Sdelphij
116171070Sdelphijstatic int
117171029Sdelphijtmpfs_node_init(void *mem, int size, int flags)
118171029Sdelphij{
119171029Sdelphij	struct tmpfs_node *node = (struct tmpfs_node *)mem;
120171029Sdelphij	node->tn_id = 0;
121171029Sdelphij
122171029Sdelphij	mtx_init(&node->tn_interlock, "tmpfs node interlock", NULL, MTX_DEF);
123171362Sdelphij	node->tn_gen = arc4random();
124171070Sdelphij
125171029Sdelphij	return (0);
126171029Sdelphij}
127171029Sdelphij
128171029Sdelphijstatic void
129171029Sdelphijtmpfs_node_fini(void *mem, int size)
130171029Sdelphij{
131171029Sdelphij	struct tmpfs_node *node = (struct tmpfs_node *)mem;
132171070Sdelphij
133171029Sdelphij	mtx_destroy(&node->tn_interlock);
134171029Sdelphij}
135171029Sdelphij
136170808Sdelphijstatic int
137191990Sattiliotmpfs_mount(struct mount *mp)
138170808Sdelphij{
139234000Sgleb	const size_t nodes_per_page = howmany(PAGE_SIZE,
140234000Sgleb	    sizeof(struct tmpfs_dirent) + sizeof(struct tmpfs_node));
141170808Sdelphij	struct tmpfs_mount *tmp;
142170808Sdelphij	struct tmpfs_node *root;
143254741Sdelphij	struct thread *td = curthread;
144170808Sdelphij	int error;
145171308Sdelphij	/* Size counters. */
146233999Sgleb	u_quad_t pages;
147233999Sgleb	off_t nodes_max, size_max, maxfilesize;
148170808Sdelphij
149171308Sdelphij	/* Root node attributes. */
150202187Sjh	uid_t root_uid;
151202187Sjh	gid_t root_gid;
152202187Sjh	mode_t root_mode;
153171308Sdelphij
154202187Sjh	struct vattr va;
155171308Sdelphij
156254741Sdelphij	if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_TMPFS))
157254741Sdelphij		return (EPERM);
158254741Sdelphij
159170808Sdelphij	if (vfs_filteropt(mp->mnt_optnew, tmpfs_opts))
160170808Sdelphij		return (EINVAL);
161170808Sdelphij
162170808Sdelphij	if (mp->mnt_flag & MNT_UPDATE) {
163234346Sjh		/* Only support update mounts for certain options. */
164234346Sjh		if (vfs_filteropt(mp->mnt_optnew, tmpfs_updateopts) != 0)
165234346Sjh			return (EOPNOTSUPP);
166234346Sjh		if (vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0) !=
167234346Sjh		    ((struct tmpfs_mount *)mp->mnt_data)->tm_ronly)
168234346Sjh			return (EOPNOTSUPP);
169234346Sjh		return (0);
170170808Sdelphij	}
171170808Sdelphij
172175202Sattilio	vn_lock(mp->mnt_vnodecovered, LK_SHARED | LK_RETRY);
173182371Sattilio	error = VOP_GETATTR(mp->mnt_vnodecovered, &va, mp->mnt_cred);
174175294Sattilio	VOP_UNLOCK(mp->mnt_vnodecovered, 0);
175171308Sdelphij	if (error)
176171308Sdelphij		return (error);
177170808Sdelphij
178171308Sdelphij	if (mp->mnt_cred->cr_ruid != 0 ||
179171308Sdelphij	    vfs_scanopt(mp->mnt_optnew, "gid", "%d", &root_gid) != 1)
180171308Sdelphij		root_gid = va.va_gid;
181171308Sdelphij	if (mp->mnt_cred->cr_ruid != 0 ||
182171308Sdelphij	    vfs_scanopt(mp->mnt_optnew, "uid", "%d", &root_uid) != 1)
183171308Sdelphij		root_uid = va.va_uid;
184171308Sdelphij	if (mp->mnt_cred->cr_ruid != 0 ||
185173570Sdelphij	    vfs_scanopt(mp->mnt_optnew, "mode", "%ho", &root_mode) != 1)
186171308Sdelphij		root_mode = va.va_mode;
187233999Sgleb	if (vfs_getopt_size(mp->mnt_optnew, "inodes", &nodes_max) != 0)
188171308Sdelphij		nodes_max = 0;
189233999Sgleb	if (vfs_getopt_size(mp->mnt_optnew, "size", &size_max) != 0)
190171308Sdelphij		size_max = 0;
191233999Sgleb	if (vfs_getopt_size(mp->mnt_optnew, "maxfilesize", &maxfilesize) != 0)
192203164Sjh		maxfilesize = 0;
193170808Sdelphij
194170808Sdelphij	/* Do not allow mounts if we do not have enough memory to preserve
195170808Sdelphij	 * the minimum reserved pages. */
196233998Sgleb	if (tmpfs_mem_avail() < TMPFS_PAGES_MINRESERVED)
197170808Sdelphij		return ENOSPC;
198170808Sdelphij
199170808Sdelphij	/* Get the maximum number of memory pages this file system is
200170808Sdelphij	 * allowed to use, based on the maximum size the user passed in
201170808Sdelphij	 * the mount structure.  A value of zero is treated as if the
202170808Sdelphij	 * maximum available space was requested. */
203263943Sbdrewery	if (size_max == 0 || size_max > OFF_MAX - PAGE_SIZE ||
204233999Sgleb	    (SIZE_MAX < OFF_MAX && size_max / PAGE_SIZE >= SIZE_MAX))
205170808Sdelphij		pages = SIZE_MAX;
206263943Sbdrewery	else {
207263943Sbdrewery		size_max = roundup(size_max, PAGE_SIZE);
208171308Sdelphij		pages = howmany(size_max, PAGE_SIZE);
209263943Sbdrewery	}
210170808Sdelphij	MPASS(pages > 0);
211170808Sdelphij
212202708Sjh	if (nodes_max <= 3) {
213234000Sgleb		if (pages < INT_MAX / nodes_per_page)
214234000Sgleb			nodes_max = pages * nodes_per_page;
215202708Sjh		else
216234000Sgleb			nodes_max = INT_MAX;
217233999Sgleb	}
218234000Sgleb	if (nodes_max > INT_MAX)
219234000Sgleb		nodes_max = INT_MAX;
220233999Sgleb	MPASS(nodes_max >= 3);
221170808Sdelphij
222170808Sdelphij	/* Allocate the tmpfs mount structure and fill it. */
223170808Sdelphij	tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount),
224170808Sdelphij	    M_TMPFSMNT, M_WAITOK | M_ZERO);
225171070Sdelphij
226170808Sdelphij	mtx_init(&tmp->allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF);
227233999Sgleb	tmp->tm_nodes_max = nodes_max;
228170808Sdelphij	tmp->tm_nodes_inuse = 0;
229233999Sgleb	tmp->tm_maxfilesize = maxfilesize > 0 ? maxfilesize : OFF_MAX;
230170808Sdelphij	LIST_INIT(&tmp->tm_nodes_used);
231171070Sdelphij
232170808Sdelphij	tmp->tm_pages_max = pages;
233170808Sdelphij	tmp->tm_pages_used = 0;
234171362Sdelphij	tmp->tm_ino_unr = new_unrhdr(2, INT_MAX, &tmp->allnode_lock);
235173724Sdelphij	tmp->tm_dirent_pool = uma_zcreate("TMPFS dirent",
236173724Sdelphij	    sizeof(struct tmpfs_dirent),
237173724Sdelphij	    NULL, NULL, NULL, NULL,
238173724Sdelphij	    UMA_ALIGN_PTR, 0);
239173724Sdelphij	tmp->tm_node_pool = uma_zcreate("TMPFS node",
240173724Sdelphij	    sizeof(struct tmpfs_node),
241173724Sdelphij	    tmpfs_node_ctor, tmpfs_node_dtor,
242173724Sdelphij	    tmpfs_node_init, tmpfs_node_fini,
243173724Sdelphij	    UMA_ALIGN_PTR, 0);
244234346Sjh	tmp->tm_ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
245170808Sdelphij
246170808Sdelphij	/* Allocate the root node. */
247171308Sdelphij	error = tmpfs_alloc_node(tmp, VDIR, root_uid,
248171308Sdelphij	    root_gid, root_mode & ALLPERMS, NULL, NULL,
249191990Sattilio	    VNOVAL, &root);
250170808Sdelphij
251170808Sdelphij	if (error != 0 || root == NULL) {
252171029Sdelphij	    uma_zdestroy(tmp->tm_node_pool);
253171029Sdelphij	    uma_zdestroy(tmp->tm_dirent_pool);
254171362Sdelphij	    delete_unrhdr(tmp->tm_ino_unr);
255170808Sdelphij	    free(tmp, M_TMPFSMNT);
256170808Sdelphij	    return error;
257170808Sdelphij	}
258241011Smdf	KASSERT(root->tn_id == 2,
259241011Smdf	    ("tmpfs root with invalid ino: %ju", (uintmax_t)root->tn_id));
260170808Sdelphij	tmp->tm_root = root;
261170808Sdelphij
262170808Sdelphij	MNT_ILOCK(mp);
263170808Sdelphij	mp->mnt_flag |= MNT_LOCAL;
264170808Sdelphij	MNT_IUNLOCK(mp);
265171070Sdelphij
266170808Sdelphij	mp->mnt_data = tmp;
267170808Sdelphij	mp->mnt_stat.f_namemax = MAXNAMLEN;
268170808Sdelphij	vfs_getnewfsid(mp);
269170808Sdelphij	vfs_mountedfrom(mp, "tmpfs");
270170808Sdelphij
271170808Sdelphij	return 0;
272170808Sdelphij}
273170808Sdelphij
274170808Sdelphij/* --------------------------------------------------------------------- */
275170808Sdelphij
276170808Sdelphij/* ARGSUSED2 */
277170808Sdelphijstatic int
278191990Sattiliotmpfs_unmount(struct mount *mp, int mntflags)
279170808Sdelphij{
280170808Sdelphij	int error;
281170808Sdelphij	int flags = 0;
282170808Sdelphij	struct tmpfs_mount *tmp;
283170808Sdelphij	struct tmpfs_node *node;
284170808Sdelphij
285170808Sdelphij	/* Handle forced unmounts. */
286170808Sdelphij	if (mntflags & MNT_FORCE)
287170808Sdelphij		flags |= FORCECLOSE;
288170808Sdelphij
289170808Sdelphij	/* Finalize all pending I/O. */
290191990Sattilio	error = vflush(mp, 0, flags, curthread);
291170808Sdelphij	if (error != 0)
292170808Sdelphij		return error;
293170808Sdelphij
294170808Sdelphij	tmp = VFS_TO_TMPFS(mp);
295171070Sdelphij
296170808Sdelphij	/* Free all associated data.  The loop iterates over the linked list
297170808Sdelphij	 * we have containing all used nodes.  For each of them that is
298170808Sdelphij	 * a directory, we free all its directory entries.  Note that after
299170808Sdelphij	 * freeing a node, it will automatically go to the available list,
300170808Sdelphij	 * so we will later have to iterate over it to release its items. */
301170808Sdelphij	node = LIST_FIRST(&tmp->tm_nodes_used);
302170808Sdelphij	while (node != NULL) {
303170808Sdelphij		struct tmpfs_node *next;
304170808Sdelphij
305245115Sgleb		if (node->tn_type == VDIR)
306245115Sgleb			tmpfs_dir_destroy(tmp, node);
307170808Sdelphij
308170808Sdelphij		next = LIST_NEXT(node, tn_entries);
309170808Sdelphij		tmpfs_free_node(tmp, node);
310170808Sdelphij		node = next;
311170808Sdelphij	}
312170808Sdelphij
313171029Sdelphij	uma_zdestroy(tmp->tm_dirent_pool);
314171029Sdelphij	uma_zdestroy(tmp->tm_node_pool);
315171362Sdelphij	delete_unrhdr(tmp->tm_ino_unr);
316170808Sdelphij
317170808Sdelphij	mtx_destroy(&tmp->allnode_lock);
318170808Sdelphij	MPASS(tmp->tm_pages_used == 0);
319171308Sdelphij	MPASS(tmp->tm_nodes_inuse == 0);
320170808Sdelphij
321170808Sdelphij	/* Throw away the tmpfs_mount structure. */
322170808Sdelphij	free(mp->mnt_data, M_TMPFSMNT);
323170808Sdelphij	mp->mnt_data = NULL;
324171070Sdelphij
325170808Sdelphij	MNT_ILOCK(mp);
326170808Sdelphij	mp->mnt_flag &= ~MNT_LOCAL;
327170808Sdelphij	MNT_IUNLOCK(mp);
328170808Sdelphij	return 0;
329170808Sdelphij}
330170808Sdelphij
331170808Sdelphij/* --------------------------------------------------------------------- */
332170808Sdelphij
333170808Sdelphijstatic int
334191990Sattiliotmpfs_root(struct mount *mp, int flags, struct vnode **vpp)
335170808Sdelphij{
336170808Sdelphij	int error;
337191990Sattilio	error = tmpfs_alloc_vp(mp, VFS_TO_TMPFS(mp)->tm_root, flags, vpp);
338170808Sdelphij
339170808Sdelphij	if (!error)
340171029Sdelphij		(*vpp)->v_vflag |= VV_ROOT;
341170808Sdelphij
342170808Sdelphij	return error;
343170808Sdelphij}
344170808Sdelphij
345170808Sdelphij/* --------------------------------------------------------------------- */
346170808Sdelphij
347170808Sdelphijstatic int
348222167Srmacklemtmpfs_fhtovp(struct mount *mp, struct fid *fhp, int flags,
349222167Srmacklem    struct vnode **vpp)
350170808Sdelphij{
351170808Sdelphij	boolean_t found;
352170808Sdelphij	struct tmpfs_fid *tfhp;
353170808Sdelphij	struct tmpfs_mount *tmp;
354170808Sdelphij	struct tmpfs_node *node;
355170808Sdelphij
356170808Sdelphij	tmp = VFS_TO_TMPFS(mp);
357170808Sdelphij
358170808Sdelphij	tfhp = (struct tmpfs_fid *)fhp;
359170808Sdelphij	if (tfhp->tf_len != sizeof(struct tmpfs_fid))
360170808Sdelphij		return EINVAL;
361170808Sdelphij
362170808Sdelphij	if (tfhp->tf_id >= tmp->tm_nodes_max)
363170808Sdelphij		return EINVAL;
364170808Sdelphij
365170808Sdelphij	found = FALSE;
366170808Sdelphij
367170808Sdelphij	TMPFS_LOCK(tmp);
368170808Sdelphij	LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) {
369170808Sdelphij		if (node->tn_id == tfhp->tf_id &&
370170808Sdelphij		    node->tn_gen == tfhp->tf_gen) {
371170808Sdelphij			found = TRUE;
372170808Sdelphij			break;
373170808Sdelphij		}
374170808Sdelphij	}
375170808Sdelphij	TMPFS_UNLOCK(tmp);
376170808Sdelphij
377171799Sdelphij	if (found)
378191990Sattilio		return (tmpfs_alloc_vp(mp, node, LK_EXCLUSIVE, vpp));
379171799Sdelphij
380171799Sdelphij	return (EINVAL);
381170808Sdelphij}
382170808Sdelphij
383170808Sdelphij/* --------------------------------------------------------------------- */
384170808Sdelphij
385170808Sdelphij/* ARGSUSED2 */
386170808Sdelphijstatic int
387191990Sattiliotmpfs_statfs(struct mount *mp, struct statfs *sbp)
388170808Sdelphij{
389170808Sdelphij	struct tmpfs_mount *tmp;
390233998Sgleb	size_t used;
391170808Sdelphij
392170808Sdelphij	tmp = VFS_TO_TMPFS(mp);
393170808Sdelphij
394171070Sdelphij	sbp->f_iosize = PAGE_SIZE;
395170808Sdelphij	sbp->f_bsize = PAGE_SIZE;
396170808Sdelphij
397233998Sgleb	used = tmpfs_pages_used(tmp);
398233998Sgleb	if (tmp->tm_pages_max != SIZE_MAX)
399233998Sgleb		 sbp->f_blocks = tmp->tm_pages_max;
400233998Sgleb	else
401233998Sgleb		 sbp->f_blocks = used + tmpfs_mem_avail();
402233998Sgleb	if (sbp->f_blocks <= used)
403233998Sgleb		sbp->f_bavail = 0;
404233998Sgleb	else
405233998Sgleb		sbp->f_bavail = sbp->f_blocks - used;
406233998Sgleb	sbp->f_bfree = sbp->f_bavail;
407233998Sgleb	used = tmp->tm_nodes_inuse;
408233998Sgleb	sbp->f_files = tmp->tm_nodes_max;
409233998Sgleb	if (sbp->f_files <= used)
410233998Sgleb		sbp->f_ffree = 0;
411233998Sgleb	else
412233998Sgleb		sbp->f_ffree = sbp->f_files - used;
413170808Sdelphij	/* sbp->f_owner = tmp->tn_uid; */
414170808Sdelphij
415170808Sdelphij	return 0;
416170808Sdelphij}
417170808Sdelphij
418170808Sdelphij/* --------------------------------------------------------------------- */
419170808Sdelphij
420170808Sdelphij/*
421170808Sdelphij * tmpfs vfs operations.
422170808Sdelphij */
423170808Sdelphij
424170808Sdelphijstruct vfsops tmpfs_vfsops = {
425170808Sdelphij	.vfs_mount =			tmpfs_mount,
426170808Sdelphij	.vfs_unmount =			tmpfs_unmount,
427170808Sdelphij	.vfs_root =			tmpfs_root,
428170808Sdelphij	.vfs_statfs =			tmpfs_statfs,
429170808Sdelphij	.vfs_fhtovp =			tmpfs_fhtovp,
430170808Sdelphij};
431254741SdelphijVFS_SET(tmpfs_vfsops, tmpfs, VFCF_JAIL);
432