1/* $NetBSD: tmpfs.h,v 1.44 2011/05/29 22:29:06 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#if !defined(_KERNEL) && !defined(_KMEMUSER) 37#error "not supposed to be exposed to userland" 38#endif 39 40#include <sys/dirent.h> 41#include <sys/mount.h> 42#include <sys/pool.h> 43#include <sys/queue.h> 44#include <sys/vnode.h> 45 46/* 47 * Internal representation of a tmpfs directory entry. 48 * 49 * All fields are protected by vnode lock. 50 */ 51typedef struct tmpfs_dirent { 52 TAILQ_ENTRY(tmpfs_dirent) td_entries; 53 54 /* Pointer to the inode this entry refers to. */ 55 struct tmpfs_node * td_node; 56 57 /* Name and its length. */ 58 char * td_name; 59 uint16_t td_namelen; 60} tmpfs_dirent_t; 61 62TAILQ_HEAD(tmpfs_dir, tmpfs_dirent); 63 64#if defined(_KERNEL) 65 66#define TMPFS_MAXNAMLEN 255 67/* Validate maximum td_namelen length. */ 68CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX); 69 70#define TMPFS_DIRCOOKIE_DOT 0 71#define TMPFS_DIRCOOKIE_DOTDOT 1 72#define TMPFS_DIRCOOKIE_EOF 2 73 74/* 75 * Each entry in a directory has a cookie that identifies it. Cookies 76 * supersede offsets within directories, as tmpfs has no offsets as such. 77 * 78 * The '.', '..' and the end of directory markers have fixed cookies, 79 * which cannot collide with the cookies generated by other entries. 80 * 81 * The cookies for the other entries are generated based on the memory 82 * address of their representative meta-data structure. 83 * 84 * XXX: Truncating directory cookies to 31 bits now - workaround for 85 * problem with Linux compat, see PR/32034. 86 */ 87static inline off_t 88tmpfs_dircookie(tmpfs_dirent_t *de) 89{ 90 off_t cookie; 91 92 cookie = ((off_t)(uintptr_t)de >> 1) & 0x7FFFFFFF; 93 KASSERT(cookie != TMPFS_DIRCOOKIE_DOT); 94 KASSERT(cookie != TMPFS_DIRCOOKIE_DOTDOT); 95 KASSERT(cookie != TMPFS_DIRCOOKIE_EOF); 96 97 return cookie; 98} 99#endif 100 101/* 102 * Internal representation of a tmpfs file system node -- inode. 103 * 104 * This structure is splitted in two parts: one holds attributes common 105 * to all file types and the other holds data that is only applicable to 106 * a particular type. 107 * 108 * All fields are protected by vnode lock. The vnode association itself 109 * is protected by tmpfs_node_t::tn_vlock. 110 */ 111typedef struct tmpfs_node { 112 LIST_ENTRY(tmpfs_node) tn_entries; 113 114 /* 115 * Each inode has a corresponding vnode. It is a bi-directional 116 * association. Whenever vnode is allocated, its v_data field is 117 * set to the inode it reference, and tmpfs_node_t::tn_vnode is 118 * set to point to the said vnode. 119 * 120 * Further attempts to allocate a vnode for this same node will 121 * result in returning a new reference to the value stored in 122 * tn_vnode. It may be NULL when the node is unused (that is, 123 * no vnode has been allocated or it has been reclaimed). 124 */ 125 kmutex_t tn_vlock; 126 vnode_t * tn_vnode; 127 128 /* Directory entry. Only a hint, since hard link can have multiple. */ 129 tmpfs_dirent_t * tn_dirent_hint; 130 131 /* The inode type: VBLK, VCHR, VDIR, VFIFO, VLNK, VREG or VSOCK. */ 132 enum vtype tn_type; 133 134 /* Inode identifier and generation number. */ 135 ino_t tn_id; 136 unsigned long tn_gen; 137 138 /* Inode status flags (for operations in delayed manner). */ 139 int tn_status; 140 141 /* The inode size. */ 142 off_t tn_size; 143 144 /* Generic node attributes. */ 145 uid_t tn_uid; 146 gid_t tn_gid; 147 mode_t tn_mode; 148 int tn_flags; 149 nlink_t tn_links; 150 struct timespec tn_atime; 151 struct timespec tn_mtime; 152 struct timespec tn_ctime; 153 struct timespec tn_birthtime; 154 155 /* Head of byte-level lock list (used by tmpfs_advlock). */ 156 struct lockf * tn_lockf; 157 158 union { 159 /* Type case: VBLK or VCHR. */ 160 struct { 161 dev_t tn_rdev; 162 } tn_dev; 163 164 /* Type case: VDIR. */ 165 struct { 166 /* Parent directory (root inode points to itself). */ 167 struct tmpfs_node * tn_parent; 168 169 /* List of directory entries. */ 170 struct tmpfs_dir tn_dir; 171 172 /* 173 * Number and pointer of the last directory entry 174 * returned by the readdir(3) operation. 175 */ 176 off_t tn_readdir_lastn; 177 struct tmpfs_dirent * tn_readdir_lastp; 178 } tn_dir; 179 180 /* Type case: VLNK. */ 181 struct tn_lnk { 182 /* The link's target. */ 183 char * tn_link; 184 } tn_lnk; 185 186 /* Type case: VREG. */ 187 struct tn_reg { 188 /* Underlying UVM object to store contents. */ 189 struct uvm_object * tn_aobj; 190 size_t tn_aobj_pages; 191 } tn_reg; 192 } tn_spec; 193} tmpfs_node_t; 194 195#if defined(_KERNEL) 196 197LIST_HEAD(tmpfs_node_list, tmpfs_node); 198 199/* Status flags. */ 200#define TMPFS_NODE_ACCESSED 0x01 201#define TMPFS_NODE_MODIFIED 0x02 202#define TMPFS_NODE_CHANGED 0x04 203 204#define TMPFS_NODE_STATUSALL \ 205 (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED) 206 207/* 208 * Bit indicating vnode reclamation. 209 * We abuse tmpfs_node_t::tn_gen for that. 210 */ 211#define TMPFS_NODE_GEN_MASK (~0UL >> 1) 212#define TMPFS_RECLAIMING_BIT (~TMPFS_NODE_GEN_MASK) 213 214#define TMPFS_NODE_RECLAIMING(node) \ 215 (((node)->tn_gen & TMPFS_RECLAIMING_BIT) != 0) 216 217#define TMPFS_NODE_GEN(node) \ 218 ((node)->tn_gen & TMPFS_NODE_GEN_MASK) 219 220/* White-out inode indicator. */ 221#define TMPFS_NODE_WHITEOUT ((tmpfs_node_t *)-1) 222 223/* 224 * Internal representation of a tmpfs mount point. 225 */ 226typedef struct tmpfs_mount { 227 /* Limit and number of bytes in use by the file system. */ 228 uint64_t tm_mem_limit; 229 uint64_t tm_bytes_used; 230 kmutex_t tm_acc_lock; 231 232 /* Pointer to the root inode. */ 233 tmpfs_node_t * tm_root; 234 235 /* Maximum number of possible nodes for this file system. */ 236 unsigned int tm_nodes_max; 237 238 /* Number of nodes currently allocated. */ 239 unsigned int tm_nodes_cnt; 240 241 /* List of inodes and the lock protecting it. */ 242 kmutex_t tm_lock; 243 struct tmpfs_node_list tm_nodes; 244} tmpfs_mount_t; 245 246/* 247 * This structure maps a file identifier to a tmpfs node. Used by the 248 * NFS code. 249 */ 250typedef struct tmpfs_fid { 251 uint16_t tf_len; 252 uint16_t tf_pad; 253 uint32_t tf_gen; 254 ino_t tf_id; 255} tmpfs_fid_t; 256 257/* 258 * Prototypes for tmpfs_subr.c. 259 */ 260 261int tmpfs_alloc_node(tmpfs_mount_t *, enum vtype, uid_t, gid_t, 262 mode_t, char *, dev_t, tmpfs_node_t **); 263void tmpfs_free_node(tmpfs_mount_t *, tmpfs_node_t *); 264 265int tmpfs_alloc_file(vnode_t *, vnode_t **, struct vattr *, 266 struct componentname *, char *); 267 268int tmpfs_vnode_get(struct mount *, tmpfs_node_t *, vnode_t **); 269 270int tmpfs_alloc_dirent(tmpfs_mount_t *, const char *, uint16_t, 271 tmpfs_dirent_t **); 272void tmpfs_free_dirent(tmpfs_mount_t *, tmpfs_dirent_t *); 273void tmpfs_dir_attach(vnode_t *, tmpfs_dirent_t *, tmpfs_node_t *); 274void tmpfs_dir_detach(vnode_t *, tmpfs_dirent_t *); 275 276tmpfs_dirent_t *tmpfs_dir_lookup(tmpfs_node_t *, struct componentname *); 277tmpfs_dirent_t *tmpfs_dir_cached(tmpfs_node_t *); 278 279int tmpfs_dir_getdotdent(tmpfs_node_t *, struct uio *); 280int tmpfs_dir_getdotdotdent(tmpfs_node_t *, struct uio *); 281tmpfs_dirent_t *tmpfs_dir_lookupbycookie(tmpfs_node_t *, off_t); 282int tmpfs_dir_getdents(tmpfs_node_t *, struct uio *, off_t *); 283 284int tmpfs_reg_resize(vnode_t *, off_t); 285int tmpfs_truncate(vnode_t *, off_t); 286 287int tmpfs_chflags(vnode_t *, int, kauth_cred_t, lwp_t *); 288int tmpfs_chmod(vnode_t *, mode_t, kauth_cred_t, lwp_t *); 289int tmpfs_chown(vnode_t *, uid_t, gid_t, kauth_cred_t, lwp_t *); 290int tmpfs_chsize(vnode_t *, u_quad_t, kauth_cred_t, lwp_t *); 291int tmpfs_chtimes(vnode_t *, const struct timespec *, 292 const struct timespec *, const struct timespec *, int, 293 kauth_cred_t, lwp_t *); 294void tmpfs_update(vnode_t *, const struct timespec *, 295 const struct timespec *, const struct timespec *, int); 296 297/* 298 * Prototypes for tmpfs_mem.c. 299 */ 300 301void tmpfs_mntmem_init(tmpfs_mount_t *, uint64_t); 302void tmpfs_mntmem_destroy(tmpfs_mount_t *); 303 304size_t tmpfs_mem_info(bool); 305uint64_t tmpfs_bytes_max(tmpfs_mount_t *); 306size_t tmpfs_pages_avail(tmpfs_mount_t *); 307bool tmpfs_mem_incr(tmpfs_mount_t *, size_t); 308void tmpfs_mem_decr(tmpfs_mount_t *, size_t); 309 310tmpfs_dirent_t *tmpfs_dirent_get(tmpfs_mount_t *); 311void tmpfs_dirent_put(tmpfs_mount_t *, tmpfs_dirent_t *); 312 313tmpfs_node_t * tmpfs_node_get(tmpfs_mount_t *); 314void tmpfs_node_put(tmpfs_mount_t *, tmpfs_node_t *); 315 316char * tmpfs_strname_alloc(tmpfs_mount_t *, size_t); 317void tmpfs_strname_free(tmpfs_mount_t *, char *, size_t); 318bool tmpfs_strname_neqlen(struct componentname *, struct componentname *); 319 320/* 321 * Ensures that the node pointed by 'node' is a directory and that its 322 * contents are consistent with respect to directories. 323 */ 324#define TMPFS_VALIDATE_DIR(node) \ 325 KASSERT((node)->tn_type == VDIR); \ 326 KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0); \ 327 KASSERT((node)->tn_spec.tn_dir.tn_readdir_lastp == NULL || \ 328 tmpfs_dircookie((node)->tn_spec.tn_dir.tn_readdir_lastp) == \ 329 (node)->tn_spec.tn_dir.tn_readdir_lastn); 330 331/* 332 * Memory management stuff. 333 */ 334 335/* Amount of memory pages to reserve for the system. */ 336#define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) 337 338/* 339 * Routines to convert VFS structures to tmpfs internal ones. 340 */ 341 342static inline tmpfs_mount_t * 343VFS_TO_TMPFS(struct mount *mp) 344{ 345 tmpfs_mount_t *tmp = mp->mnt_data; 346 347 KASSERT(tmp != NULL); 348 return tmp; 349} 350 351static inline tmpfs_node_t * 352VP_TO_TMPFS_DIR(vnode_t *vp) 353{ 354 tmpfs_node_t *node = vp->v_data; 355 356 KASSERT(node != NULL); 357 TMPFS_VALIDATE_DIR(node); 358 return node; 359} 360 361#endif /* defined(_KERNEL) */ 362 363static __inline tmpfs_node_t * 364VP_TO_TMPFS_NODE(vnode_t *vp) 365{ 366 tmpfs_node_t *node = vp->v_data; 367#ifdef KASSERT 368 KASSERT(node != NULL); 369#endif 370 return node; 371} 372 373#endif /* _FS_TMPFS_TMPFS_H_ */ 374