xref: /dflybsd-src/sys/vfs/tmpfs/tmpfs.h (revision e91c5b2636e1fdd0d9e5170f24e5e39987211a49)
17a2de9a4SMatthew Dillon /*	$NetBSD: tmpfs.h,v 1.26 2007/02/22 06:37:00 thorpej Exp $	*/
27a2de9a4SMatthew Dillon 
37a2de9a4SMatthew Dillon /*-
47a2de9a4SMatthew Dillon  * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
57a2de9a4SMatthew Dillon  * All rights reserved.
67a2de9a4SMatthew Dillon  *
77a2de9a4SMatthew Dillon  * This code is derived from software contributed to The NetBSD Foundation
87a2de9a4SMatthew Dillon  * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
97a2de9a4SMatthew Dillon  * 2005 program.
107a2de9a4SMatthew Dillon  *
117a2de9a4SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
127a2de9a4SMatthew Dillon  * modification, are permitted provided that the following conditions
137a2de9a4SMatthew Dillon  * are met:
147a2de9a4SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
157a2de9a4SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
167a2de9a4SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
177a2de9a4SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
187a2de9a4SMatthew Dillon  *    documentation and/or other materials provided with the distribution.
197a2de9a4SMatthew Dillon  *
207a2de9a4SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
217a2de9a4SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
227a2de9a4SMatthew Dillon  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
237a2de9a4SMatthew Dillon  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
247a2de9a4SMatthew Dillon  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
257a2de9a4SMatthew Dillon  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
267a2de9a4SMatthew Dillon  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
277a2de9a4SMatthew Dillon  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
287a2de9a4SMatthew Dillon  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
297a2de9a4SMatthew Dillon  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
307a2de9a4SMatthew Dillon  * POSSIBILITY OF SUCH DAMAGE.
317a2de9a4SMatthew Dillon  *
327a2de9a4SMatthew Dillon  * $FreeBSD: src/sys/fs/tmpfs/tmpfs.h,v 1.18 2009/10/11 07:03:56 delphij Exp $
337a2de9a4SMatthew Dillon  */
347a2de9a4SMatthew Dillon 
357a2de9a4SMatthew Dillon #ifndef _VFS_TMPFS_TMPFS_H_
367a2de9a4SMatthew Dillon #define _VFS_TMPFS_TMPFS_H_
377a2de9a4SMatthew Dillon 
387a2de9a4SMatthew Dillon /* ---------------------------------------------------------------------
397a2de9a4SMatthew Dillon  * KERNEL-SPECIFIC DEFINITIONS
407a2de9a4SMatthew Dillon  * --------------------------------------------------------------------- */
417a2de9a4SMatthew Dillon #include <sys/dirent.h>
427a2de9a4SMatthew Dillon #include <sys/mount.h>
4329ca4fd6SJohannes Hofmann #include <sys/tree.h>
447a2de9a4SMatthew Dillon #include <sys/vnode.h>
457a2de9a4SMatthew Dillon #include <sys/file.h>
467a2de9a4SMatthew Dillon #include <sys/lock.h>
477a2de9a4SMatthew Dillon #include <sys/lockf.h>
487a2de9a4SMatthew Dillon #include <sys/mutex.h>
497a2de9a4SMatthew Dillon 
507a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
517a2de9a4SMatthew Dillon #include <sys/malloc.h>
522d18109fSSascha Wildner #ifdef _KERNEL
537a2de9a4SMatthew Dillon #include <sys/systm.h>
542d18109fSSascha Wildner #endif
557a2de9a4SMatthew Dillon #include <sys/vmmeter.h>
567a2de9a4SMatthew Dillon #include <vm/swap_pager.h>
577a2de9a4SMatthew Dillon 
587ea34faaSzrj #ifdef MALLOC_DECLARE
597a2de9a4SMatthew Dillon MALLOC_DECLARE(M_TMPFSMNT);
607ea34faaSzrj #endif
617a2de9a4SMatthew Dillon 
627a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
637a2de9a4SMatthew Dillon 
647a2de9a4SMatthew Dillon /*
657a2de9a4SMatthew Dillon  * Internal representation of a tmpfs directory entry.
667a2de9a4SMatthew Dillon  */
677a2de9a4SMatthew Dillon struct tmpfs_dirent {
6829ca4fd6SJohannes Hofmann 	RB_ENTRY(tmpfs_dirent)	rb_node;
69f5f22af6SMatthew Dillon 	RB_ENTRY(tmpfs_dirent)	rb_cookienode;
707a2de9a4SMatthew Dillon 
717a2de9a4SMatthew Dillon 	/* Length of the name stored in this directory entry.  This avoids
727a2de9a4SMatthew Dillon 	 * the need to recalculate it every time the name is used. */
737a2de9a4SMatthew Dillon 	uint16_t		td_namelen;
747a2de9a4SMatthew Dillon 
757a2de9a4SMatthew Dillon 	/* The name of the entry, allocated from a string pool.  This
767a2de9a4SMatthew Dillon 	* string is not required to be zero-terminated; therefore, the
777a2de9a4SMatthew Dillon 	* td_namelen field must always be used when accessing its value. */
787a2de9a4SMatthew Dillon 	char 			*td_name;
797a2de9a4SMatthew Dillon 
807a2de9a4SMatthew Dillon 	/* Pointer to the node this entry refers to. */
817a2de9a4SMatthew Dillon 	struct tmpfs_node 	*td_node;
827a2de9a4SMatthew Dillon };
837a2de9a4SMatthew Dillon 
8429ca4fd6SJohannes Hofmann struct tmpfs_dirtree;
8529ca4fd6SJohannes Hofmann RB_HEAD(tmpfs_dirtree, tmpfs_dirent);
8629ca4fd6SJohannes Hofmann RB_PROTOTYPE(tmpfs_dirtree, tmpfs_dirent, rb_node,
8729ca4fd6SJohannes Hofmann 	tmpfs_dirtree_compare);
8829ca4fd6SJohannes Hofmann 
89f5f22af6SMatthew Dillon RB_HEAD(tmpfs_dirtree_cookie, tmpfs_dirent);
90f5f22af6SMatthew Dillon RB_PROTOTYPE(tmpfs_dirtree_cookie, tmpfs_dirent, rb_cookienode,
91f5f22af6SMatthew Dillon 	tmpfs_dirtree_cookie_compare);
9229ca4fd6SJohannes Hofmann 
93f5f22af6SMatthew Dillon 
94f5f22af6SMatthew Dillon /*
95f5f22af6SMatthew Dillon  * A directory in tmpfs holds a set of directory entries, which in
967a2de9a4SMatthew Dillon  * turn point to other files (which can be directories themselves).
977a2de9a4SMatthew Dillon  *
9829ca4fd6SJohannes Hofmann  * In tmpfs, this set is managed by a red-black tree, whose root is defined
9929ca4fd6SJohannes Hofmann  * by the struct tmpfs_dirtree type.
1007a2de9a4SMatthew Dillon  *
10129ca4fd6SJohannes Hofmann  * It is important to notice that directories do not have entries for . and
1027a2de9a4SMatthew Dillon  * .. as other file systems do.  These can be generated when requested
1037a2de9a4SMatthew Dillon  * based on information available by other means, such as the pointer to
1047a2de9a4SMatthew Dillon  * the node itself in the former case or the pointer to the parent directory
1057a2de9a4SMatthew Dillon  * in the latter case.  This is done to simplify tmpfs's code and, more
106f5f22af6SMatthew Dillon  * importantly, to remove redundancy.
107f5f22af6SMatthew Dillon  *
108f5f22af6SMatthew Dillon  * Each entry in a directory has a cookie that identifies it.  Cookies
1097a2de9a4SMatthew Dillon  * supersede offsets within directories because, given how tmpfs stores
1107a2de9a4SMatthew Dillon  * directories in memory, there is no such thing as an offset.  (Emulating
1117a2de9a4SMatthew Dillon  * a real offset could be very difficult.)
1127a2de9a4SMatthew Dillon  *
1137a2de9a4SMatthew Dillon  * The '.', '..' and the end of directory markers have fixed cookies which
1147a2de9a4SMatthew Dillon  * cannot collide with the cookies generated by other entries.  The cookies
1157a2de9a4SMatthew Dillon  * for the other entries are generated based on the memory address on which
1167a2de9a4SMatthew Dillon  * stores their information is stored.
1177a2de9a4SMatthew Dillon  *
118f5f22af6SMatthew Dillon  * DragonFly binaries use 64-bit cookies.  We mask-off the signed bit to
119f5f22af6SMatthew Dillon  * ensure that cookie 'offsets' are positive.
120f5f22af6SMatthew Dillon  */
1217a2de9a4SMatthew Dillon #ifdef _KERNEL
122f5f22af6SMatthew Dillon 
1235b09d16cSTomohiro Kusumi #define	TMPFS_ROOTINO	((ino_t)2)
124de8da6a3STomohiro Kusumi 
1257a2de9a4SMatthew Dillon #define	TMPFS_DIRCOOKIE_DOT	0
1267a2de9a4SMatthew Dillon #define	TMPFS_DIRCOOKIE_DOTDOT	1
127*e91c5b26SMatthew Dillon #define	TMPFS_DIRCOOKIE_EOF	((off_t)0x7FFFFFFFFFFFFFFFLLU)
128f5f22af6SMatthew Dillon 
1297a2de9a4SMatthew Dillon static __inline
1307a2de9a4SMatthew Dillon off_t
tmpfs_dircookie(struct tmpfs_dirent * de)1317a2de9a4SMatthew Dillon tmpfs_dircookie(struct tmpfs_dirent *de)
1327a2de9a4SMatthew Dillon {
133*e91c5b26SMatthew Dillon 	return ((off_t)((uintptr_t)de >> 1) & 0x7FFFFFFFFFFFFFFFLLU);
134*e91c5b26SMatthew Dillon }
135*e91c5b26SMatthew Dillon 
136*e91c5b26SMatthew Dillon /*
137*e91c5b26SMatthew Dillon  * WARNING!  Caller should never try to actually access a tmpfs dirent
138*e91c5b26SMatthew Dillon  *	     structure from a cookiedir() conversion.  It is used strictly
139*e91c5b26SMatthew Dillon  *	     for RBTREE operations.
140*e91c5b26SMatthew Dillon  */
141*e91c5b26SMatthew Dillon static __inline
142*e91c5b26SMatthew Dillon void *
tmpfs_cookiedir(off_t off)143*e91c5b26SMatthew Dillon tmpfs_cookiedir(off_t off)
144*e91c5b26SMatthew Dillon {
145*e91c5b26SMatthew Dillon 	return ((void *)((uintptr_t)off << 1));
1467a2de9a4SMatthew Dillon }
147f5f22af6SMatthew Dillon 
148525d1416STomohiro Kusumi #endif  /* _KERNEL */
1497a2de9a4SMatthew Dillon 
1507a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
1517a2de9a4SMatthew Dillon 
1527a2de9a4SMatthew Dillon /*
1537a2de9a4SMatthew Dillon  * Internal representation of a tmpfs file system node.
1547a2de9a4SMatthew Dillon  *
1557a2de9a4SMatthew Dillon  * This structure is splitted in two parts: one holds attributes common
1567a2de9a4SMatthew Dillon  * to all file types and the other holds data that is only applicable to
1577a2de9a4SMatthew Dillon  * a particular type.  The code must be careful to only access those
1587a2de9a4SMatthew Dillon  * attributes that are actually allowed by the node's type.
1597a2de9a4SMatthew Dillon  */
1607a2de9a4SMatthew Dillon struct tmpfs_node {
1617a2de9a4SMatthew Dillon 	/* Doubly-linked list entry which links all existing nodes for a
1627a2de9a4SMatthew Dillon 	 * single file system.  This is provided to ease the removal of
1637a2de9a4SMatthew Dillon 	 * all nodes during the unmount operation. */
1647a2de9a4SMatthew Dillon 	LIST_ENTRY(tmpfs_node)	tn_entries;
1657a2de9a4SMatthew Dillon 
1667a2de9a4SMatthew Dillon 	/* The node's type.  Any of 'VBLK', 'VCHR', 'VDIR', 'VFIFO',
1677a2de9a4SMatthew Dillon 	 * 'VLNK', 'VREG' and 'VSOCK' is allowed.  The usage of vnode
1687a2de9a4SMatthew Dillon 	 * types instead of a custom enumeration is to make things simpler
1697a2de9a4SMatthew Dillon 	 * and faster, as we do not need to convert between two types. */
1707a2de9a4SMatthew Dillon 	enum vtype		tn_type;
1717a2de9a4SMatthew Dillon 
1727a2de9a4SMatthew Dillon 	/* Node identifier. */
1737a2de9a4SMatthew Dillon 	ino_t			tn_id;
1747a2de9a4SMatthew Dillon 
1757a2de9a4SMatthew Dillon 	/* Node's internal status.  This is used by several file system
1767a2de9a4SMatthew Dillon 	 * operations to do modifications to the node in a delayed
1777a2de9a4SMatthew Dillon 	 * fashion. */
1789cd86db5SMatthew Dillon 	int			tn_blksize;	/* small file optimization */
1797a2de9a4SMatthew Dillon 	int			tn_status;
1807a2de9a4SMatthew Dillon #define	TMPFS_NODE_ACCESSED	(1 << 1)
1817a2de9a4SMatthew Dillon #define	TMPFS_NODE_MODIFIED	(1 << 2)
1827a2de9a4SMatthew Dillon #define	TMPFS_NODE_CHANGED	(1 << 3)
1837a2de9a4SMatthew Dillon 
1847a2de9a4SMatthew Dillon 	/* The node size.  It does not necessarily match the real amount
1857a2de9a4SMatthew Dillon 	 * of memory consumed by it. */
1867a2de9a4SMatthew Dillon 	off_t			tn_size;
1877a2de9a4SMatthew Dillon 
1887a2de9a4SMatthew Dillon 	/* Generic node attributes. */
1897a2de9a4SMatthew Dillon 	uid_t			tn_uid;
1907a2de9a4SMatthew Dillon 	gid_t			tn_gid;
1917a2de9a4SMatthew Dillon 	mode_t			tn_mode;
192513a5bc4Szrj 	u_int			tn_flags;
1934d22d8eeSMatthew Dillon 	nlink_t			tn_links;	/* atomic ops req */
194fa4a12c4SMatthew Dillon 	long			tn_atime;
195fa4a12c4SMatthew Dillon 	long			tn_atimensec;
196fa4a12c4SMatthew Dillon 	long			tn_mtime;
197fa4a12c4SMatthew Dillon 	long			tn_mtimensec;
198fa4a12c4SMatthew Dillon 	long			tn_ctime;
199fa4a12c4SMatthew Dillon 	long			tn_ctimensec;
2007a2de9a4SMatthew Dillon 	unsigned long		tn_gen;
2017a2de9a4SMatthew Dillon 	struct lockf		tn_advlock;
2027a2de9a4SMatthew Dillon 
2037a2de9a4SMatthew Dillon 	/* As there is a single vnode for each active file within the
2047a2de9a4SMatthew Dillon 	 * system, care has to be taken to avoid allocating more than one
2057a2de9a4SMatthew Dillon 	 * vnode per file.  In order to do this, a bidirectional association
2067a2de9a4SMatthew Dillon 	 * is kept between vnodes and nodes.
2077a2de9a4SMatthew Dillon 	 *
2087a2de9a4SMatthew Dillon 	 * Whenever a vnode is allocated, its v_data field is updated to
2097a2de9a4SMatthew Dillon 	 * point to the node it references.  At the same time, the node's
2107a2de9a4SMatthew Dillon 	 * tn_vnode field is modified to point to the new vnode representing
2117a2de9a4SMatthew Dillon 	 * it.  Further attempts to allocate a vnode for this same node will
2127a2de9a4SMatthew Dillon 	 * result in returning a new reference to the value stored in
2137a2de9a4SMatthew Dillon 	 * tn_vnode.
2147a2de9a4SMatthew Dillon 	 *
2157a2de9a4SMatthew Dillon 	 * May be NULL when the node is unused (that is, no vnode has been
2167a2de9a4SMatthew Dillon 	 * allocated for it or it has been reclaimed). */
2177a2de9a4SMatthew Dillon 	struct vnode *		tn_vnode;
2187a2de9a4SMatthew Dillon 
219a44ecf5cSMatthew Dillon 	/* interlock to protect structure */
2207a2de9a4SMatthew Dillon 	struct lock		tn_interlock;
2217a2de9a4SMatthew Dillon 
222a44ecf5cSMatthew Dillon 	/*
223a44ecf5cSMatthew Dillon 	 * tmpfs vnode state, may specify an allocation in-progress.
2247a2de9a4SMatthew Dillon 	 */
2257a2de9a4SMatthew Dillon 	int		tn_vpstate;
2267a2de9a4SMatthew Dillon 
2277a2de9a4SMatthew Dillon 	/* misc data field for different tn_type node */
2287a2de9a4SMatthew Dillon 	union {
2297a2de9a4SMatthew Dillon 		/* Valid when tn_type == VBLK || tn_type == VCHR. */
2307a2de9a4SMatthew Dillon 		dev_t			tn_rdev; /*int32_t ?*/
2317a2de9a4SMatthew Dillon 
2327a2de9a4SMatthew Dillon 		/* Valid when tn_type == VDIR. */
2337a2de9a4SMatthew Dillon 		struct tn_dir {
234f5f22af6SMatthew Dillon 			/*
235f5f22af6SMatthew Dillon 			 * Pointer to the parent directory.  The root
2367a2de9a4SMatthew Dillon 			 * directory has a pointer to itself in this field;
237f5f22af6SMatthew Dillon 			 * this property identifies the root node.
238f5f22af6SMatthew Dillon 			 */
2397a2de9a4SMatthew Dillon 			struct tmpfs_node *	tn_parent;
2407a2de9a4SMatthew Dillon 
241f5f22af6SMatthew Dillon 			/*
242f5f22af6SMatthew Dillon 			 * Directory entries are indexed by name and also
243f5f22af6SMatthew Dillon 			 * indexed by cookie.
244f5f22af6SMatthew Dillon 			 */
24529ca4fd6SJohannes Hofmann 			struct tmpfs_dirtree		tn_dirtree;
246f5f22af6SMatthew Dillon 			struct tmpfs_dirtree_cookie	tn_cookietree;
2477a2de9a4SMatthew Dillon 		} tn_dir;
2487a2de9a4SMatthew Dillon 
2497a2de9a4SMatthew Dillon 		/* Valid when tn_type == VLNK. */
2507a2de9a4SMatthew Dillon 		/* The link's target, allocated from a string pool. */
2517a2de9a4SMatthew Dillon 		char *			tn_link;
2527a2de9a4SMatthew Dillon 
253a1b829f2SMatthew Dillon 		/*
254a1b829f2SMatthew Dillon 		 * Valid when tn_type == VREG.
255a1b829f2SMatthew Dillon 		 *
256a1b829f2SMatthew Dillon 		 * aobj is used as backing store for the vnode object.  It
257a1b829f2SMatthew Dillon 		 * typically only contains swap assignments, but we also use
258a1b829f2SMatthew Dillon 		 * it to save the vnode object's vm_page's when the vnode
259a1b829f2SMatthew Dillon 		 * becomes inactive.
260a1b829f2SMatthew Dillon 		 */
2617a2de9a4SMatthew Dillon 		struct tn_reg {
2627a2de9a4SMatthew Dillon 			vm_object_t		tn_aobj;
2637a2de9a4SMatthew Dillon 			size_t			tn_aobj_pages;
264a1b829f2SMatthew Dillon 			int			tn_pages_in_aobj;
2657a2de9a4SMatthew Dillon 		} tn_reg;
2667a2de9a4SMatthew Dillon 
2677a2de9a4SMatthew Dillon 		/* Valid when tn_type = VFIFO */
2687a2de9a4SMatthew Dillon 		struct tn_fifo {
2697a2de9a4SMatthew Dillon 			int (*tn_fo_read)  (struct file *fp, struct uio *uio,
2707a2de9a4SMatthew Dillon 			        struct ucred *cred, int flags);
2717a2de9a4SMatthew Dillon 			int (*tn_fo_write) (struct file *fp, struct uio *uio,
2727a2de9a4SMatthew Dillon 			        struct ucred *cred, int flags);
2737a2de9a4SMatthew Dillon 		} tn_fifo;
2747a2de9a4SMatthew Dillon 	} tn_spec;
2757a2de9a4SMatthew Dillon };
2762d18109fSSascha Wildner 
277d743c0f3STomohiro Kusumi /* Only userspace needs this */
2782d18109fSSascha Wildner #define VTOI(vp)	((struct tmpfs_node *)(vp)->v_data)
2792d18109fSSascha Wildner 
2802d18109fSSascha Wildner #ifdef _KERNEL
2817a2de9a4SMatthew Dillon LIST_HEAD(tmpfs_node_list, tmpfs_node);
2827a2de9a4SMatthew Dillon 
2837a2de9a4SMatthew Dillon #define tn_rdev tn_spec.tn_rdev
2847a2de9a4SMatthew Dillon #define tn_dir tn_spec.tn_dir
2857a2de9a4SMatthew Dillon #define tn_link tn_spec.tn_link
2867a2de9a4SMatthew Dillon #define tn_reg tn_spec.tn_reg
2877a2de9a4SMatthew Dillon #define tn_fifo tn_spec.tn_fifo
2887a2de9a4SMatthew Dillon 
2897a2de9a4SMatthew Dillon #define TMPFS_NODE_LOCK(node) lockmgr(&(node)->tn_interlock, LK_EXCLUSIVE|LK_RETRY)
290ff837cd5SMatthew Dillon #define TMPFS_NODE_LOCK_SH(node) lockmgr(&(node)->tn_interlock, LK_SHARED|LK_RETRY)
2917a2de9a4SMatthew Dillon #define TMPFS_NODE_UNLOCK(node) lockmgr(&(node)->tn_interlock, LK_RELEASE)
2927a2de9a4SMatthew Dillon #define TMPFS_NODE_MTX(node) (&(node)->tn_interlock)
2937a2de9a4SMatthew Dillon 
2947a2de9a4SMatthew Dillon #ifdef INVARIANTS
2957a2de9a4SMatthew Dillon #define TMPFS_ASSERT_LOCKED(node) do {					\
2967a2de9a4SMatthew Dillon 		KKASSERT(node != NULL);					\
2977a2de9a4SMatthew Dillon 		KKASSERT(node->tn_vnode != NULL);			\
2987a2de9a4SMatthew Dillon 		if (!vn_islocked(node->tn_vnode) &&			\
2997a2de9a4SMatthew Dillon 		    (lockstatus(TMPFS_NODE_MTX(node), curthread) == LK_EXCLUSIVE ))		\
3007a2de9a4SMatthew Dillon 			panic("tmpfs: node is not locked: %p", node);	\
3017a2de9a4SMatthew Dillon 	} while (0)
3027a2de9a4SMatthew Dillon #define TMPFS_ASSERT_ELOCKED(node) do {					\
3037a2de9a4SMatthew Dillon 		KKASSERT((node) != NULL);				\
3047a2de9a4SMatthew Dillon 		KKASSERT(lockstatus(TMPFS_NODE_MTX(node), curthread) == LK_EXCLUSIVE);		\
3057a2de9a4SMatthew Dillon 	} while (0)
3067a2de9a4SMatthew Dillon #else
3077a2de9a4SMatthew Dillon #define TMPFS_ASSERT_LOCKED(node) (void)0
3087a2de9a4SMatthew Dillon #define TMPFS_ASSERT_ELOCKED(node) (void)0
309525d1416STomohiro Kusumi #endif  /* INVARIANTS */
3107a2de9a4SMatthew Dillon 
311a44ecf5cSMatthew Dillon #define TMPFS_VNODE_DOOMED	0x0001
3127a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
3137a2de9a4SMatthew Dillon 
3147a2de9a4SMatthew Dillon /*
3157a2de9a4SMatthew Dillon  * Internal representation of a tmpfs mount point.
3167a2de9a4SMatthew Dillon  */
3177a2de9a4SMatthew Dillon struct tmpfs_mount {
318aa1adbf0SMatthew Dillon 	struct mount		*tm_mount;
319aa1adbf0SMatthew Dillon 
3207a2de9a4SMatthew Dillon 	/* Maximum number of memory pages available for use by the file
3217a2de9a4SMatthew Dillon 	 * system, set during mount time.  This variable must never be
3227a2de9a4SMatthew Dillon 	 * used directly as it may be bigger than the current amount of
3237a2de9a4SMatthew Dillon 	 * free memory; in the extreme case, it will hold the SIZE_MAX
3247a2de9a4SMatthew Dillon 	 * value.  Instead, use the TMPFS_PAGES_MAX macro. */
325b37a7c00SMatthew Dillon 	long			tm_pages_max;
3267a2de9a4SMatthew Dillon 
3277a2de9a4SMatthew Dillon 	/* Number of pages in use by the file system.  Cannot be bigger
3287a2de9a4SMatthew Dillon 	 * than the value returned by TMPFS_PAGES_MAX in any case. */
329b37a7c00SMatthew Dillon 	long			tm_pages_used;
3307a2de9a4SMatthew Dillon 
3317a2de9a4SMatthew Dillon 	/* Pointer to the node representing the root directory of this
3327a2de9a4SMatthew Dillon 	 * file system. */
3337a2de9a4SMatthew Dillon 	struct tmpfs_node *	tm_root;
3347a2de9a4SMatthew Dillon 
3357a2de9a4SMatthew Dillon 	/* Maximum number of possible nodes for this file system; set
3367a2de9a4SMatthew Dillon 	 * during mount time.  We need a hard limit on the maximum number
3377a2de9a4SMatthew Dillon 	 * of nodes to avoid allocating too much of them; their objects
3387a2de9a4SMatthew Dillon 	 * cannot be released until the file system is unmounted.
3397a2de9a4SMatthew Dillon 	 * Otherwise, we could easily run out of memory by creating lots
3407a2de9a4SMatthew Dillon 	 * of empty files and then simply removing them. */
3417a2de9a4SMatthew Dillon 	ino_t			tm_nodes_max;
3427a2de9a4SMatthew Dillon 
3437a2de9a4SMatthew Dillon 	/* Number of nodes currently that are in use. */
3447a2de9a4SMatthew Dillon 	ino_t			tm_nodes_inuse;
3457a2de9a4SMatthew Dillon 
3467a2de9a4SMatthew Dillon 	/* maximum representable file size */
3477a2de9a4SMatthew Dillon 	u_int64_t		tm_maxfilesize;
3487a2de9a4SMatthew Dillon 
3497a2de9a4SMatthew Dillon 	/* Nodes are organized in two different lists.  The used list
3507a2de9a4SMatthew Dillon 	 * contains all nodes that are currently used by the file system;
3517a2de9a4SMatthew Dillon 	 * i.e., they refer to existing files.  The available list contains
3527a2de9a4SMatthew Dillon 	 * all nodes that are currently available for use by new files.
3537a2de9a4SMatthew Dillon 	 * Nodes must be kept in this list (instead of deleting them)
3547a2de9a4SMatthew Dillon 	 * because we need to keep track of their generation number (tn_gen
3557a2de9a4SMatthew Dillon 	 * field).
3567a2de9a4SMatthew Dillon 	 *
3577a2de9a4SMatthew Dillon 	 * Note that nodes are lazily allocated: if the available list is
3587a2de9a4SMatthew Dillon 	 * empty and we have enough space to create more nodes, they will be
3597a2de9a4SMatthew Dillon 	 * created and inserted in the used list.  Once these are released,
3607a2de9a4SMatthew Dillon 	 * they will go into the available list, remaining alive until the
3617a2de9a4SMatthew Dillon 	 * file system is unmounted. */
3627a2de9a4SMatthew Dillon 	struct tmpfs_node_list	tm_nodes_used;
3637a2de9a4SMatthew Dillon 
364d00cd01cSVenkatesh Srinivas 	/* Per-mount malloc zones for tmpfs nodes, names, and dirents */
365e9dbfea1SMatthew Dillon 	struct malloc_type	*tm_node_zone_obj;
366e9dbfea1SMatthew Dillon 	struct malloc_type	*tm_dirent_zone_obj;
367d00cd01cSVenkatesh Srinivas 	struct malloc_type	*tm_name_zone;
3688e771504SVenkatesh Srinivas 
369d6d9df16STomohiro Kusumi 	ino_t			tm_ino;
3709fc94b5fSMatthew Dillon 	int			tm_flags;
37166fa44e7SVenkatesh Srinivas 
37266fa44e7SVenkatesh Srinivas 	struct netexport	tm_export;
373aa1adbf0SMatthew Dillon 
374aa1adbf0SMatthew Dillon 	struct mount		*tm_mnt;
3757a2de9a4SMatthew Dillon };
3769fc94b5fSMatthew Dillon 
377aa1adbf0SMatthew Dillon #define TMPFS_LOCK(tm) lwkt_gettoken(&(tm)->tm_mount->mnt_token)
378aa1adbf0SMatthew Dillon #define TMPFS_UNLOCK(tm) lwkt_reltoken(&(tm)->tm_mount->mnt_token)
3797a2de9a4SMatthew Dillon 
3807a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
3817a2de9a4SMatthew Dillon 
3827a2de9a4SMatthew Dillon /*
3837a2de9a4SMatthew Dillon  * This structure maps a file identifier to a tmpfs node.  Used by the
3847a2de9a4SMatthew Dillon  * NFS code.
3857a2de9a4SMatthew Dillon  */
3867a2de9a4SMatthew Dillon struct tmpfs_fid {
3877a2de9a4SMatthew Dillon 	uint16_t		tf_len;
3887a2de9a4SMatthew Dillon 	uint16_t		tf_pad;
3897a2de9a4SMatthew Dillon 	ino_t			tf_id;
3907a2de9a4SMatthew Dillon 	unsigned long		tf_gen;
391513b5023SMatthew Dillon } __packed;
3927a2de9a4SMatthew Dillon 
3937a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
3947a2de9a4SMatthew Dillon 
3957a2de9a4SMatthew Dillon /*
3967a2de9a4SMatthew Dillon  * Prototypes for tmpfs_subr.c.
3977a2de9a4SMatthew Dillon  */
3987a2de9a4SMatthew Dillon 
3997a2de9a4SMatthew Dillon int	tmpfs_alloc_node(struct tmpfs_mount *, enum vtype,
4006e0c5aabSMatthew Dillon 	    uid_t uid, gid_t gid, mode_t mode, char *, int, int,
4016e0c5aabSMatthew Dillon 	    struct tmpfs_node **);
4027a2de9a4SMatthew Dillon void	tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *);
4037a2de9a4SMatthew Dillon int	tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *,
4047a2de9a4SMatthew Dillon 	    const char *, uint16_t, struct tmpfs_dirent **);
4050786baf1SMatthew Dillon void	tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *);
406d89a0e31SMatthew Dillon int	tmpfs_alloc_vp(struct mount *, struct tmpfs_node *,
407d89a0e31SMatthew Dillon 	    struct tmpfs_node *, int, struct vnode **);
4087a2de9a4SMatthew Dillon int	tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *,
4097a2de9a4SMatthew Dillon 	    struct namecache *, struct ucred *, char *);
410307bf766SMatthew Dillon void	tmpfs_dir_attach_locked(struct tmpfs_node *, struct tmpfs_dirent *);
411307bf766SMatthew Dillon void	tmpfs_dir_detach_locked(struct tmpfs_node *, struct tmpfs_dirent *);
4127a2de9a4SMatthew Dillon struct tmpfs_dirent *	tmpfs_dir_lookup(struct tmpfs_node *node,
4137a2de9a4SMatthew Dillon 			    struct tmpfs_node *f,
4147a2de9a4SMatthew Dillon 			    struct namecache *ncp);
4157a2de9a4SMatthew Dillon int	tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *);
41622d3b394SMatthew Dillon int	tmpfs_dir_getdotdotdent(struct tmpfs_mount *,
41722d3b394SMatthew Dillon 			    struct tmpfs_node *, struct uio *);
418*e91c5b26SMatthew Dillon struct tmpfs_dirent *	tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t,
419*e91c5b26SMatthew Dillon 			    int);
4207a2de9a4SMatthew Dillon int	tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *);
4217a2de9a4SMatthew Dillon int	tmpfs_reg_resize(struct vnode *, off_t, int);
422513a5bc4Szrj int	tmpfs_chflags(struct vnode *, u_long, struct ucred *);
4237a2de9a4SMatthew Dillon int	tmpfs_chmod(struct vnode *, mode_t, struct ucred *);
4247a2de9a4SMatthew Dillon int	tmpfs_chown(struct vnode *, uid_t, gid_t, struct ucred *);
4257a2de9a4SMatthew Dillon int	tmpfs_chsize(struct vnode *, u_quad_t, struct ucred *);
4267a2de9a4SMatthew Dillon int	tmpfs_chtimes(struct vnode *, struct timespec *, struct timespec *,
4277a2de9a4SMatthew Dillon 	    int, struct ucred *);
4287a2de9a4SMatthew Dillon void	tmpfs_itimes(struct vnode *, const struct timespec *,
4297a2de9a4SMatthew Dillon 	    const struct timespec *);
4307a2de9a4SMatthew Dillon 
431e9dbfea1SMatthew Dillon void	tmpfs_node_init(struct tmpfs_node *node);
432e9dbfea1SMatthew Dillon void	tmpfs_node_uninit(struct tmpfs_node *node);
4337a2de9a4SMatthew Dillon void	tmpfs_update(struct vnode *);
4347a2de9a4SMatthew Dillon int	tmpfs_truncate(struct vnode *, off_t);
4354c154053SMatthew Dillon void	tmpfs_lock4(struct tmpfs_node *node1, struct tmpfs_node *node2,
4364c154053SMatthew Dillon 		struct tmpfs_node *node3, struct tmpfs_node *node4);
4374c154053SMatthew Dillon void	tmpfs_unlock4(struct tmpfs_node *node1, struct tmpfs_node *node2,
4384c154053SMatthew Dillon 		struct tmpfs_node *node3, struct tmpfs_node *node4);
4397a2de9a4SMatthew Dillon 
4407a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
4417a2de9a4SMatthew Dillon 
4427a2de9a4SMatthew Dillon /*
4437a2de9a4SMatthew Dillon  * Convenience macros to simplify some logical expressions.
4447a2de9a4SMatthew Dillon  */
4457a2de9a4SMatthew Dillon #define IMPLIES(a, b) (!(a) || (b))
4467a2de9a4SMatthew Dillon #define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a))
4477a2de9a4SMatthew Dillon 
4487a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
4497a2de9a4SMatthew Dillon 
4507a2de9a4SMatthew Dillon /*
4517a2de9a4SMatthew Dillon  * Checks that the directory entry pointed by 'de' matches the name 'name'
4527a2de9a4SMatthew Dillon  * with a length of 'len'.
4537a2de9a4SMatthew Dillon  */
4547a2de9a4SMatthew Dillon #define TMPFS_DIRENT_MATCHES(de, name, len) \
4557a2de9a4SMatthew Dillon     (de->td_namelen == (uint16_t)len && \
4567a2de9a4SMatthew Dillon     bcmp((de)->td_name, (name), (de)->td_namelen) == 0)
4577a2de9a4SMatthew Dillon 
4587a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
4597a2de9a4SMatthew Dillon 
4607a2de9a4SMatthew Dillon /*
4617a2de9a4SMatthew Dillon  * Ensures that the node pointed by 'node' is a directory and that its
4627a2de9a4SMatthew Dillon  * contents are consistent with respect to directories.
4637a2de9a4SMatthew Dillon  */
464f5f22af6SMatthew Dillon #define TMPFS_VALIDATE_DIR(node) do {	\
4657a2de9a4SMatthew Dillon     KKASSERT((node)->tn_type == VDIR);	\
4667a2de9a4SMatthew Dillon     KKASSERT((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \
467f5f22af6SMatthew Dillon } while(0)
4687a2de9a4SMatthew Dillon 
4697a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
4707a2de9a4SMatthew Dillon 
4717a2de9a4SMatthew Dillon /*
4727a2de9a4SMatthew Dillon  * Macros/functions to convert from generic data structures to tmpfs
473d743c0f3STomohiro Kusumi  * specific ones.  Kernel code use VP_TO_TMPFS_NODE() instead of VTOI().
4747a2de9a4SMatthew Dillon  */
4757a2de9a4SMatthew Dillon 
4767a2de9a4SMatthew Dillon static inline
4777a2de9a4SMatthew Dillon struct tmpfs_mount *
VFS_TO_TMPFS(struct mount * mp)4787a2de9a4SMatthew Dillon VFS_TO_TMPFS(struct mount *mp)
4797a2de9a4SMatthew Dillon {
4807a2de9a4SMatthew Dillon 	struct tmpfs_mount *tmp;
4817a2de9a4SMatthew Dillon 
4827a2de9a4SMatthew Dillon 	KKASSERT((mp) != NULL && (mp)->mnt_data != NULL);
4837a2de9a4SMatthew Dillon 	tmp = (struct tmpfs_mount *)(mp)->mnt_data;
4847a2de9a4SMatthew Dillon 	return tmp;
4857a2de9a4SMatthew Dillon }
4867a2de9a4SMatthew Dillon 
4877a2de9a4SMatthew Dillon static inline
4887a2de9a4SMatthew Dillon struct tmpfs_node *
VP_TO_TMPFS_NODE(struct vnode * vp)4897a2de9a4SMatthew Dillon VP_TO_TMPFS_NODE(struct vnode *vp)
4907a2de9a4SMatthew Dillon {
4917a2de9a4SMatthew Dillon 	struct tmpfs_node *node;
4927a2de9a4SMatthew Dillon 
4937a2de9a4SMatthew Dillon 	KKASSERT((vp) != NULL && (vp)->v_data != NULL);
4947a2de9a4SMatthew Dillon 	node = (struct tmpfs_node *)vp->v_data;
4957a2de9a4SMatthew Dillon 	return node;
4967a2de9a4SMatthew Dillon }
4977a2de9a4SMatthew Dillon 
4987a2de9a4SMatthew Dillon static inline
4997a2de9a4SMatthew Dillon struct tmpfs_node *
VP_TO_TMPFS_DIR(struct vnode * vp)5007a2de9a4SMatthew Dillon VP_TO_TMPFS_DIR(struct vnode *vp)
5017a2de9a4SMatthew Dillon {
5027a2de9a4SMatthew Dillon 	struct tmpfs_node *node;
5037a2de9a4SMatthew Dillon 
5047a2de9a4SMatthew Dillon 	node = VP_TO_TMPFS_NODE(vp);
5057a2de9a4SMatthew Dillon 	TMPFS_VALIDATE_DIR(node);
5067a2de9a4SMatthew Dillon 	return node;
5077a2de9a4SMatthew Dillon }
5087a2de9a4SMatthew Dillon 
5097a2de9a4SMatthew Dillon /* --------------------------------------------------------------------- */
5107a2de9a4SMatthew Dillon /*
5117a2de9a4SMatthew Dillon  * buffer cache size
5127a2de9a4SMatthew Dillon  */
5133c54bb74SMatthew Dillon #define TMPFS_BLKSIZE	16384			/* buffer cache size*/
5143c54bb74SMatthew Dillon #define TMPFS_BLKMASK	(TMPFS_BLKSIZE - 1)
5153c54bb74SMatthew Dillon #define TMPFS_BLKMASK64	((off_t)(TMPFS_BLKSIZE - 1))
5162d18109fSSascha Wildner #endif /* _KERNEL */
5177a2de9a4SMatthew Dillon 
5187a2de9a4SMatthew Dillon #endif /* _VFS_TMPFS_TMPFS_H_ */
519