1 /* $OpenBSD: tmpfs.h,v 1.5 2013/12/14 18:01:52 espie Exp $ */ 2 /* $NetBSD: tmpfs.h,v 1.45 2011/09/27 01:10:43 christos Exp $ */ 3 4 /* 5 * Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code 10 * 2005 program. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #ifndef _TMPFS_TMPFS_H_ 35 #define _TMPFS_TMPFS_H_ 36 37 #if !defined(_KERNEL) && !defined(_KMEMUSER) 38 #error "not supposed to be exposed to userland" 39 #endif 40 41 #include <sys/dirent.h> 42 #include <sys/mount.h> 43 #include <sys/pool.h> 44 #include <sys/queue.h> 45 #include <sys/stdint.h> 46 #include <sys/rwlock.h> 47 48 /* 49 * Internal representation of a tmpfs directory entry. 50 * 51 * All fields are protected by vnode lock. 52 */ 53 typedef struct tmpfs_dirent { 54 TAILQ_ENTRY(tmpfs_dirent) td_entries; 55 56 /* Pointer to the inode this entry refers to. */ 57 struct tmpfs_node * td_node; 58 59 /* Sequence number, see tmpfs_dir_getseq(). */ 60 uint64_t td_seq; 61 62 /* Name and its length. */ 63 char * td_name; 64 uint16_t td_namelen; 65 } tmpfs_dirent_t; 66 67 TAILQ_HEAD(tmpfs_dir, tmpfs_dirent); 68 69 /* 70 * Internal representation of a tmpfs file system node -- inode. 71 * 72 * This structure is split in two parts: one holds attributes common 73 * to all file types and the other holds data that is only applicable to 74 * a particular type. 75 * 76 * All fields are protected by vnode lock. The vnode association itself 77 * is protected by tmpfs_node_t::tn_nlock. 78 */ 79 typedef struct tmpfs_node { 80 LIST_ENTRY(tmpfs_node) tn_entries; 81 82 /* 83 * Each inode has a corresponding vnode. It is a bi-directional 84 * association. Whenever vnode is allocated, its v_data field is 85 * set to the inode it reference, and tmpfs_node_t::tn_vnode is 86 * set to point to the said vnode. 87 * 88 * Further attempts to allocate a vnode for this same node will 89 * result in returning a new reference to the value stored in 90 * tn_vnode. It may be NULL when the node is unused (that is, 91 * no vnode has been allocated or it has been reclaimed). 92 */ 93 struct rwlock tn_nlock; /* node lock */ 94 struct lock tn_vlock; /* vnode lock */ 95 struct vnode * tn_vnode; 96 97 /* Directory entry. Only a hint, since hard link can have multiple. */ 98 tmpfs_dirent_t * tn_dirent_hint; 99 100 /* The inode type: VBLK, VCHR, VDIR, VFIFO, VLNK, VREG or VSOCK. */ 101 enum vtype tn_type; 102 103 /* Inode identifier and generation number. */ 104 ino_t tn_id; 105 unsigned long tn_gen; 106 107 /* The inode size. */ 108 off_t tn_size; 109 110 /* Generic node attributes. */ 111 uid_t tn_uid; 112 gid_t tn_gid; 113 mode_t tn_mode; 114 int tn_flags; 115 nlink_t tn_links; 116 struct timespec tn_atime; 117 struct timespec tn_mtime; 118 struct timespec tn_ctime; 119 struct timespec tn_birthtime; 120 121 /* Head of byte-level lock list (used by tmpfs_advlock). */ 122 struct lockf * tn_lockf; 123 124 union { 125 /* Type case: VBLK or VCHR. */ 126 struct { 127 dev_t tn_rdev; 128 } tn_dev; 129 130 /* Type case: VDIR. */ 131 struct { 132 /* Parent directory (root inode points to itself). */ 133 struct tmpfs_node * tn_parent; 134 135 /* List of directory entries. */ 136 struct tmpfs_dir tn_dir; 137 138 /* Last given sequence number. */ 139 uint64_t tn_next_seq; 140 141 /* 142 * Pointer of the last directory entry returned 143 * by the readdir(3) operation. 144 */ 145 struct tmpfs_dirent * tn_readdir_lastp; 146 } tn_dir; 147 148 /* Type case: VLNK. */ 149 struct tn_lnk { 150 /* The link's target. */ 151 char * tn_link; 152 } tn_lnk; 153 154 /* Type case: VREG. */ 155 struct tn_reg { 156 /* Underlying UVM object to store contents. */ 157 struct uvm_object * tn_aobj; 158 size_t tn_aobj_pages; 159 vaddr_t tn_aobj_pgptr; 160 voff_t tn_aobj_pgnum; 161 } tn_reg; 162 } tn_spec; 163 164 #define tn_uobj tn_spec.tn_reg.tn_aobj 165 #define tn_pgptr tn_spec.tn_reg.tn_aobj_pgptr 166 #define tn_pgnum tn_spec.tn_reg.tn_aobj_pgnum 167 168 } tmpfs_node_t; 169 170 #if defined(_KERNEL) 171 172 LIST_HEAD(tmpfs_node_list, tmpfs_node); 173 174 175 #define TMPFS_MAXNAMLEN 255 176 /* Validate maximum td_namelen length. */ 177 /* CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX); */ 178 179 /* 180 * Reserved values for the virtual entries (the first must be 0) and EOF. 181 * The start/end of the incremental range, see tmpfs_dir_getseq(). 182 */ 183 #define TMPFS_DIRSEQ_DOT 0 184 #define TMPFS_DIRSEQ_DOTDOT 1 185 #define TMPFS_DIRSEQ_EOF 2 186 187 #define TMPFS_DIRSEQ_START 3 /* inclusive */ 188 #define TMPFS_DIRSEQ_END UINT64_MAX /* exclusive */ 189 190 /* Mark to indicate that the number is not set. */ 191 #define TMPFS_DIRSEQ_NONE UINT64_MAX 192 193 /* Can we still append entries to a directory? */ 194 #define TMPFS_DIRSEQ_FULL(dnode) \ 195 ((dnode)->tn_spec.tn_dir.tn_next_seq == TMPFS_DIRSEQ_END) 196 197 /* Status flags. */ 198 #define TMPFS_NODE_ACCESSED 0x01 199 #define TMPFS_NODE_MODIFIED 0x02 200 #define TMPFS_NODE_CHANGED 0x04 201 202 #define TMPFS_NODE_STATUSALL \ 203 (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED) 204 205 /* 206 * Bit indicating vnode reclamation. 207 * We abuse tmpfs_node_t::tn_gen for that. 208 */ 209 #define TMPFS_NODE_GEN_MASK (~0UL >> 1) 210 #define TMPFS_RECLAIMING_BIT (~TMPFS_NODE_GEN_MASK) 211 212 #define TMPFS_NODE_RECLAIMING(node) \ 213 (((node)->tn_gen & TMPFS_RECLAIMING_BIT) != 0) 214 215 #define TMPFS_NODE_GEN(node) \ 216 ((node)->tn_gen & TMPFS_NODE_GEN_MASK) 217 218 /* 219 * Internal representation of a tmpfs mount point. 220 */ 221 typedef struct tmpfs_mount { 222 /* Limit and number of bytes in use by the file system. */ 223 uint64_t tm_mem_limit; 224 uint64_t tm_bytes_used; 225 /* Highest allocated inode number. */ 226 uint64_t tm_highest_inode; 227 struct rwlock tm_acc_lock; 228 229 /* Pointer to the root inode. */ 230 tmpfs_node_t * tm_root; 231 232 /* Maximum number of possible nodes for this file system. */ 233 unsigned int tm_nodes_max; 234 235 /* Number of nodes currently allocated. */ 236 unsigned int tm_nodes_cnt; 237 238 /* List of inodes and the lock protecting it. */ 239 struct rwlock tm_lock; 240 struct tmpfs_node_list tm_nodes; 241 } tmpfs_mount_t; 242 243 /* 244 * This structure maps a file identifier to a tmpfs node. Used by the 245 * NFS code. 246 */ 247 typedef struct tmpfs_fid { 248 uint16_t tf_len; 249 uint16_t tf_pad; 250 uint32_t tf_gen; 251 ino_t tf_id; 252 } tmpfs_fid_t; 253 254 /* 255 * Prototypes for tmpfs_subr.c. 256 */ 257 258 int tmpfs_alloc_node(tmpfs_mount_t *, enum vtype, uid_t, gid_t, 259 mode_t, char *, dev_t, tmpfs_node_t **); 260 void tmpfs_free_node(tmpfs_mount_t *, tmpfs_node_t *); 261 262 int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *, 263 struct componentname *, char *); 264 265 int tmpfs_vnode_get(struct mount *, tmpfs_node_t *, struct vnode **); 266 267 int tmpfs_alloc_dirent(tmpfs_mount_t *, const char *, uint16_t, 268 tmpfs_dirent_t **); 269 void tmpfs_free_dirent(tmpfs_mount_t *, tmpfs_dirent_t *); 270 void tmpfs_dir_attach(tmpfs_node_t *, tmpfs_dirent_t *, 271 tmpfs_node_t *); 272 void tmpfs_dir_detach(tmpfs_node_t *, tmpfs_dirent_t *); 273 274 tmpfs_dirent_t *tmpfs_dir_lookup(tmpfs_node_t *, struct componentname *); 275 tmpfs_dirent_t *tmpfs_dir_cached(tmpfs_node_t *); 276 277 uint64_t tmpfs_dir_getseq(tmpfs_node_t *, tmpfs_dirent_t *); 278 tmpfs_dirent_t *tmpfs_dir_lookupbyseq(tmpfs_node_t *, off_t); 279 int tmpfs_dir_getdents(tmpfs_node_t *, struct uio *); 280 281 int tmpfs_reg_resize(struct vnode *, off_t); 282 int tmpfs_truncate(struct vnode *, off_t); 283 284 int tmpfs_chflags(struct vnode *, int, struct ucred *, struct proc *); 285 int tmpfs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *); 286 int tmpfs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *); 287 int tmpfs_chsize(struct vnode *, u_quad_t, struct ucred *, struct proc *); 288 int tmpfs_chtimes(struct vnode *, const struct timespec *, 289 const struct timespec *, int, struct ucred *, 290 struct proc *); 291 void tmpfs_update(tmpfs_node_t *, int); 292 int tmpfs_zeropg(tmpfs_node_t *, voff_t, vaddr_t); 293 int tmpfs_uio_cached(tmpfs_node_t *); 294 int tmpfs_uiomove(tmpfs_node_t *, struct uio *, vsize_t); 295 void tmpfs_uio_uncache(tmpfs_node_t *); 296 void tmpfs_uio_cache(tmpfs_node_t *, voff_t, vaddr_t); 297 vaddr_t tmpfs_uio_lookup(tmpfs_node_t *, voff_t); 298 299 /* 300 * Prototypes for tmpfs_mem.c. 301 */ 302 303 void tmpfs_mntmem_init(tmpfs_mount_t *, uint64_t); 304 void tmpfs_mntmem_destroy(tmpfs_mount_t *); 305 306 size_t tmpfs_mem_info(int); 307 uint64_t tmpfs_bytes_max(tmpfs_mount_t *); 308 uint64_t tmpfs_pages_avail(tmpfs_mount_t *); 309 int tmpfs_mem_incr(tmpfs_mount_t *, size_t); 310 void tmpfs_mem_decr(tmpfs_mount_t *, size_t); 311 312 tmpfs_dirent_t *tmpfs_dirent_get(tmpfs_mount_t *); 313 void tmpfs_dirent_put(tmpfs_mount_t *, tmpfs_dirent_t *); 314 315 tmpfs_node_t * tmpfs_node_get(tmpfs_mount_t *); 316 void tmpfs_node_put(tmpfs_mount_t *, tmpfs_node_t *); 317 318 char * tmpfs_strname_alloc(tmpfs_mount_t *, size_t); 319 void tmpfs_strname_free(tmpfs_mount_t *, char *, size_t); 320 int tmpfs_strname_neqlen(struct componentname *, struct componentname *); 321 322 /* 323 * Ensures that the node pointed by 'node' is a directory and that its 324 * contents are consistent with respect to directories. 325 */ 326 #define TMPFS_VALIDATE_DIR(node) \ 327 KASSERT((node)->tn_vnode == NULL || VOP_ISLOCKED((node)->tn_vnode)); \ 328 KASSERT((node)->tn_type == VDIR); \ 329 KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0); 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 342 static inline tmpfs_mount_t * 343 VFS_TO_TMPFS(struct mount *mp) 344 { 345 tmpfs_mount_t *tmp = mp->mnt_data; 346 347 KASSERT(tmp != NULL); 348 return tmp; 349 } 350 351 static inline tmpfs_node_t * 352 VP_TO_TMPFS_DIR(struct vnode *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 363 static __inline tmpfs_node_t * 364 VP_TO_TMPFS_NODE(struct vnode *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 /* _TMPFS_TMPFS_H_ */ 374