Home | History | Annotate | Line # | Download | only in tmpfs
tmpfs.h revision 1.41
      1 /*	$NetBSD: tmpfs.h,v 1.41 2011/05/24 20:17:49 rmind Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
      9  * 2005 program.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #ifndef _FS_TMPFS_TMPFS_H_
     34 #define _FS_TMPFS_TMPFS_H_
     35 
     36 #include <sys/dirent.h>
     37 #include <sys/mount.h>
     38 #include <sys/pool.h>
     39 #include <sys/queue.h>
     40 #include <sys/vnode.h>
     41 
     42 /*
     43  * Internal representation of a tmpfs directory entry.
     44  *
     45  * All fields are protected by vnode lock.
     46  */
     47 typedef struct tmpfs_dirent {
     48 	TAILQ_ENTRY(tmpfs_dirent)	td_entries;
     49 
     50 	/* Pointer to the inode this entry refers to. */
     51 	struct tmpfs_node *		td_node;
     52 
     53 	/* Name and its length. */
     54 	char *				td_name;
     55 	uint16_t			td_namelen;
     56 } tmpfs_dirent_t;
     57 
     58 TAILQ_HEAD(tmpfs_dir, tmpfs_dirent);
     59 
     60 #if defined(_KERNEL)
     61 
     62 /* Validate maximum td_namelen length. */
     63 CTASSERT(MAXNAMLEN < UINT16_MAX);
     64 
     65 #define	TMPFS_DIRCOOKIE_DOT	0
     66 #define	TMPFS_DIRCOOKIE_DOTDOT	1
     67 #define	TMPFS_DIRCOOKIE_EOF	2
     68 
     69 /*
     70  * Each entry in a directory has a cookie that identifies it.  Cookies
     71  * supersede offsets within directories, as tmpfs has no offsets as such.
     72  *
     73  * The '.', '..' and the end of directory markers have fixed cookies,
     74  * which cannot collide with the cookies generated by other entries.
     75  *
     76  * The cookies for the other entries are generated based on the memory
     77  * address of their representative meta-data structure.
     78  *
     79  * XXX: Truncating directory cookies to 31 bits now - workaround for
     80  * problem with Linux compat, see PR/32034.
     81  */
     82 static inline off_t
     83 tmpfs_dircookie(tmpfs_dirent_t *de)
     84 {
     85 	off_t cookie;
     86 
     87 	cookie = ((off_t)(uintptr_t)de >> 1) & 0x7FFFFFFF;
     88 	KASSERT(cookie != TMPFS_DIRCOOKIE_DOT);
     89 	KASSERT(cookie != TMPFS_DIRCOOKIE_DOTDOT);
     90 	KASSERT(cookie != TMPFS_DIRCOOKIE_EOF);
     91 
     92 	return cookie;
     93 }
     94 #endif
     95 
     96 /*
     97  * Internal representation of a tmpfs file system node -- inode.
     98  *
     99  * This structure is splitted in two parts: one holds attributes common
    100  * to all file types and the other holds data that is only applicable to
    101  * a particular type.
    102  *
    103  * All fields are protected by vnode lock.  The vnode association itself
    104  * is protected by tmpfs_node_t::tn_vlock.
    105  */
    106 typedef struct tmpfs_node {
    107 	LIST_ENTRY(tmpfs_node)	tn_entries;
    108 
    109 	/* The inode type: VBLK, VCHR, VDIR, VFIFO, VLNK, VREG or VSOCK. */
    110 	enum vtype		tn_type;
    111 
    112 	/* Inode identifier. */
    113 	ino_t			tn_id;
    114 
    115 	/* Inode status flags (for operations in delayed manner). */
    116 	int			tn_status;
    117 
    118 	/* The inode size. */
    119 	off_t			tn_size;
    120 
    121 	/* Generic node attributes. */
    122 	uid_t			tn_uid;
    123 	gid_t			tn_gid;
    124 	mode_t			tn_mode;
    125 	int			tn_flags;
    126 	nlink_t			tn_links;
    127 	struct timespec		tn_atime;
    128 	struct timespec		tn_mtime;
    129 	struct timespec		tn_ctime;
    130 	struct timespec		tn_birthtime;
    131 	unsigned long		tn_gen;
    132 
    133 	/* Head of byte-level lock list (used by tmpfs_advlock). */
    134 	struct lockf *		tn_lockf;
    135 
    136 	/*
    137 	 * Each inode has a corresponding vnode.  It is a bi-directional
    138 	 * association.  Whenever vnode is allocated, its v_data field is
    139 	 * set to the inode it reference, and tmpfs_node_t::tn_vnode is
    140 	 * set to point to the said vnode.
    141 	 *
    142 	 * Further attempts to allocate a vnode for this same node will
    143 	 * result in returning a new reference to the value stored in
    144 	 * tn_vnode.  It may be NULL when the node is unused (that is,
    145 	 * no vnode has been allocated or it has been reclaimed).
    146 	 */
    147 	kmutex_t		tn_vlock;
    148 	vnode_t *		tn_vnode;
    149 
    150 	union {
    151 		/* Type case: VBLK or VCHR. */
    152 		struct {
    153 			dev_t			tn_rdev;
    154 		} tn_dev;
    155 
    156 		/* Type case: VDIR. */
    157 		struct {
    158 			/* Parent directory (root inode points to itself). */
    159 			struct tmpfs_node *	tn_parent;
    160 
    161 			/* List of directory entries. */
    162 			struct tmpfs_dir	tn_dir;
    163 
    164 			/*
    165 			 * Number and pointer of the last directory entry
    166 			 * returned by the readdir(3) operation.
    167 			 */
    168 			off_t			tn_readdir_lastn;
    169 			struct tmpfs_dirent *	tn_readdir_lastp;
    170 		} tn_dir;
    171 
    172 		/* Type case: VLNK. */
    173 		struct tn_lnk {
    174 			/* The link's target. */
    175 			char *			tn_link;
    176 		} tn_lnk;
    177 
    178 		/* Type case: VREG. */
    179 		struct tn_reg {
    180 			/* Underlying UVM object to store contents. */
    181 			struct uvm_object *	tn_aobj;
    182 			size_t			tn_aobj_pages;
    183 		} tn_reg;
    184 	} tn_spec;
    185 } tmpfs_node_t;
    186 
    187 #if defined(_KERNEL)
    188 
    189 LIST_HEAD(tmpfs_node_list, tmpfs_node);
    190 
    191 /* Status flags. */
    192 #define	TMPFS_NODE_ACCESSED	0x01
    193 #define	TMPFS_NODE_MODIFIED	0x02
    194 #define	TMPFS_NODE_CHANGED	0x04
    195 
    196 #define	TMPFS_NODE_STATUSALL	\
    197     (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED)
    198 
    199 /* White-out inode indicator. */
    200 #define	TMPFS_NODE_WHITEOUT	((struct tmpfs_node *)-1)
    201 
    202 /*
    203  * Internal representation of a tmpfs mount point.
    204  */
    205 typedef struct tmpfs_mount {
    206 	/* Limit and number of bytes in use by the file system. */
    207 	uint64_t		tm_mem_limit;
    208 	uint64_t		tm_bytes_used;
    209 	kmutex_t		tm_acc_lock;
    210 
    211 	/* Pointer to the root inode. */
    212 	tmpfs_node_t *		tm_root;
    213 
    214 	/* Maximum number of possible nodes for this file system. */
    215 	unsigned int		tm_nodes_max;
    216 
    217 	/* Number of nodes currently allocated. */
    218 	unsigned int		tm_nodes_cnt;
    219 
    220 	/* List of inodes and the lock protecting it. */
    221 	kmutex_t		tm_lock;
    222 	struct tmpfs_node_list	tm_nodes;
    223 } tmpfs_mount_t;
    224 
    225 /*
    226  * This structure maps a file identifier to a tmpfs node.  Used by the
    227  * NFS code.
    228  */
    229 typedef struct tmpfs_fid {
    230 	uint16_t		tf_len;
    231 	uint16_t		tf_pad;
    232 	uint32_t		tf_gen;
    233 	ino_t			tf_id;
    234 } tmpfs_fid_t;
    235 
    236 /*
    237  * Prototypes for tmpfs_subr.c.
    238  */
    239 
    240 int	tmpfs_alloc_node(struct tmpfs_mount *, enum vtype,
    241 	    uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *,
    242 	    char *, dev_t, struct tmpfs_node **);
    243 void	tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *);
    244 int	tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *,
    245 	    const char *, uint16_t, struct tmpfs_dirent **);
    246 void	tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *,
    247 	    bool);
    248 int	tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, struct vnode **);
    249 void	tmpfs_free_vp(struct vnode *);
    250 int	tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *,
    251 	    struct componentname *, char *);
    252 void	tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *);
    253 void	tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *);
    254 struct tmpfs_dirent *	tmpfs_dir_lookup(struct tmpfs_node *node,
    255 			    struct componentname *cnp);
    256 int	tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *);
    257 int	tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *);
    258 struct tmpfs_dirent *	tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t);
    259 int	tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *);
    260 int	tmpfs_reg_resize(struct vnode *, off_t);
    261 int	tmpfs_chflags(struct vnode *, int, kauth_cred_t, struct lwp *);
    262 int	tmpfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *);
    263 int	tmpfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, struct lwp *);
    264 int	tmpfs_chsize(struct vnode *, u_quad_t, kauth_cred_t, struct lwp *);
    265 int	tmpfs_chtimes(struct vnode *, const struct timespec *,
    266     const struct timespec *, const struct timespec *, int, kauth_cred_t,
    267     struct lwp *);
    268 void	tmpfs_update(struct vnode *, const struct timespec *,
    269 	    const struct timespec *, const struct timespec *, int);
    270 int	tmpfs_truncate(struct vnode *, off_t);
    271 
    272 /*
    273  * Prototypes for tmpfs_mem.c.
    274  */
    275 
    276 void		tmpfs_mntmem_init(struct tmpfs_mount *, uint64_t);
    277 void		tmpfs_mntmem_destroy(struct tmpfs_mount *);
    278 
    279 size_t		tmpfs_mem_info(bool);
    280 uint64_t	tmpfs_bytes_max(struct tmpfs_mount *);
    281 size_t		tmpfs_pages_avail(struct tmpfs_mount *);
    282 bool		tmpfs_mem_incr(struct tmpfs_mount *, size_t);
    283 void		tmpfs_mem_decr(struct tmpfs_mount *, size_t);
    284 
    285 struct tmpfs_dirent *tmpfs_dirent_get(struct tmpfs_mount *);
    286 void		tmpfs_dirent_put(struct tmpfs_mount *, struct tmpfs_dirent *);
    287 
    288 struct tmpfs_node *tmpfs_node_get(struct tmpfs_mount *);
    289 void		tmpfs_node_put(struct tmpfs_mount *, struct tmpfs_node *);
    290 
    291 char *		tmpfs_strname_alloc(struct tmpfs_mount *, size_t);
    292 void		tmpfs_strname_free(struct tmpfs_mount *, char *, size_t);
    293 bool		tmpfs_strname_neqlen(struct componentname *, struct componentname *);
    294 
    295 /*
    296  * Ensures that the node pointed by 'node' is a directory and that its
    297  * contents are consistent with respect to directories.
    298  */
    299 #define TMPFS_VALIDATE_DIR(node) \
    300     KASSERT((node)->tn_type == VDIR); \
    301     KASSERT((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \
    302     KASSERT((node)->tn_spec.tn_dir.tn_readdir_lastp == NULL || \
    303         tmpfs_dircookie((node)->tn_spec.tn_dir.tn_readdir_lastp) == \
    304         (node)->tn_spec.tn_dir.tn_readdir_lastn);
    305 
    306 /*
    307  * Memory management stuff.
    308  */
    309 
    310 /* Amount of memory pages to reserve for the system. */
    311 #define	TMPFS_PAGES_RESERVED	(4 * 1024 * 1024 / PAGE_SIZE)
    312 
    313 /*
    314  * Routines to convert VFS structures to tmpfs internal ones.
    315  */
    316 
    317 static inline tmpfs_mount_t *
    318 VFS_TO_TMPFS(struct mount *mp)
    319 {
    320 	tmpfs_mount_t *tmp = mp->mnt_data;
    321 
    322 	KASSERT(tmp != NULL);
    323 	return tmp;
    324 }
    325 
    326 static inline tmpfs_node_t *
    327 VP_TO_TMPFS_DIR(vnode_t *vp)
    328 {
    329 	tmpfs_node_t *node = vp->v_data;
    330 
    331 	KASSERT(node != NULL);
    332 	TMPFS_VALIDATE_DIR(node);
    333 	return node;
    334 }
    335 
    336 #endif /* defined(_KERNEL) */
    337 
    338 static __inline tmpfs_node_t *
    339 VP_TO_TMPFS_NODE(struct vnode *vp)
    340 {
    341 	tmpfs_node_t *node = vp->v_data;
    342 #ifdef KASSERT
    343 	KASSERT(node != NULL);
    344 #endif
    345 	return node;
    346 }
    347 
    348 #endif /* _FS_TMPFS_TMPFS_H_ */
    349