1 /* $OpenBSD: tmpfs.h,v 1.8 2016/06/19 11:54:33 natano 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 #include <sys/lock.h> 48 49 #include <uvm/uvm_extern.h> 50 51 /* 52 * Internal representation of a tmpfs directory entry. 53 * 54 * All fields are protected by vnode lock. 55 */ 56 typedef struct tmpfs_dirent { 57 TAILQ_ENTRY(tmpfs_dirent) td_entries; 58 59 /* Pointer to the inode this entry refers to. */ 60 struct tmpfs_node * td_node; 61 62 /* Sequence number, see tmpfs_dir_getseq(). */ 63 uint64_t td_seq; 64 65 /* Name and its length. */ 66 char * td_name; 67 uint16_t td_namelen; 68 } tmpfs_dirent_t; 69 70 TAILQ_HEAD(tmpfs_dir, tmpfs_dirent); 71 72 /* 73 * Internal representation of a tmpfs file system node -- inode. 74 * 75 * This structure is split in two parts: one holds attributes common 76 * to all file types and the other holds data that is only applicable to 77 * a particular type. 78 * 79 * All fields are protected by vnode lock. The vnode association itself 80 * is protected by tmpfs_node_t::tn_nlock. 81 */ 82 typedef struct tmpfs_node { 83 LIST_ENTRY(tmpfs_node) tn_entries; 84 85 /* 86 * Each inode has a corresponding vnode. It is a bi-directional 87 * association. Whenever vnode is allocated, its v_data field is 88 * set to the inode it reference, and tmpfs_node_t::tn_vnode is 89 * set to point to the said vnode. 90 * 91 * Further attempts to allocate a vnode for this same node will 92 * result in returning a new reference to the value stored in 93 * tn_vnode. It may be NULL when the node is unused (that is, 94 * no vnode has been allocated or it has been reclaimed). 95 */ 96 struct rwlock tn_nlock; /* node lock */ 97 struct rrwlock tn_vlock; /* vnode lock */ 98 struct vnode * tn_vnode; 99 100 /* Directory entry. Only a hint, since hard link can have multiple. */ 101 tmpfs_dirent_t * tn_dirent_hint; 102 103 /* The inode type: VBLK, VCHR, VDIR, VFIFO, VLNK, VREG or VSOCK. */ 104 enum vtype tn_type; 105 106 /* Inode identifier and generation number. */ 107 ino_t tn_id; 108 unsigned long tn_gen; 109 110 /* The inode size. */ 111 off_t tn_size; 112 113 /* Generic node attributes. */ 114 uid_t tn_uid; 115 gid_t tn_gid; 116 mode_t tn_mode; 117 int tn_flags; 118 nlink_t tn_links; 119 struct timespec tn_atime; 120 struct timespec tn_mtime; 121 struct timespec tn_ctime; 122 struct timespec tn_birthtime; 123 124 /* Head of byte-level lock list (used by tmpfs_advlock). */ 125 struct lockf * tn_lockf; 126 127 union { 128 /* Type case: VBLK or VCHR. */ 129 struct { 130 dev_t tn_rdev; 131 } tn_dev; 132 133 /* Type case: VDIR. */ 134 struct { 135 /* Parent directory (root inode points to itself). */ 136 struct tmpfs_node * tn_parent; 137 138 /* List of directory entries. */ 139 struct tmpfs_dir tn_dir; 140 141 /* Last given sequence number. */ 142 uint64_t tn_next_seq; 143 144 /* 145 * Pointer of the last directory entry returned 146 * by the readdir(3) operation. 147 */ 148 struct tmpfs_dirent * tn_readdir_lastp; 149 } tn_dir; 150 151 /* Type case: VLNK. */ 152 struct tn_lnk { 153 /* The link's target. */ 154 char * tn_link; 155 } tn_lnk; 156 157 /* Type case: VREG. */ 158 struct tn_reg { 159 /* Underlying UVM object to store contents. */ 160 struct uvm_object * tn_aobj; 161 size_t tn_aobj_pages; 162 vaddr_t tn_aobj_pgptr; 163 voff_t tn_aobj_pgnum; 164 } tn_reg; 165 } tn_spec; 166 167 #define tn_uobj tn_spec.tn_reg.tn_aobj 168 #define tn_pgptr tn_spec.tn_reg.tn_aobj_pgptr 169 #define tn_pgnum tn_spec.tn_reg.tn_aobj_pgnum 170 171 } tmpfs_node_t; 172 173 #if defined(_KERNEL) 174 175 LIST_HEAD(tmpfs_node_list, tmpfs_node); 176 177 178 #define TMPFS_MAXNAMLEN 255 179 /* Validate maximum td_namelen length. */ 180 /* CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX); */ 181 182 /* 183 * Reserved values for the virtual entries (the first must be 0) and EOF. 184 * The start/end of the incremental range, see tmpfs_dir_getseq(). 185 */ 186 #define TMPFS_DIRSEQ_DOT 0 187 #define TMPFS_DIRSEQ_DOTDOT 1 188 #define TMPFS_DIRSEQ_EOF 2 189 190 #define TMPFS_DIRSEQ_START 3 /* inclusive */ 191 #define TMPFS_DIRSEQ_END UINT64_MAX /* exclusive */ 192 193 /* Mark to indicate that the number is not set. */ 194 #define TMPFS_DIRSEQ_NONE UINT64_MAX 195 196 /* Can we still append entries to a directory? */ 197 #define TMPFS_DIRSEQ_FULL(dnode) \ 198 ((dnode)->tn_spec.tn_dir.tn_next_seq == TMPFS_DIRSEQ_END) 199 200 /* Status flags. */ 201 #define TMPFS_NODE_ACCESSED 0x01 202 #define TMPFS_NODE_MODIFIED 0x02 203 #define TMPFS_NODE_CHANGED 0x04 204 205 #define TMPFS_NODE_STATUSALL \ 206 (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED) 207 208 /* 209 * Bit indicating vnode reclamation. 210 * We abuse tmpfs_node_t::tn_gen for that. 211 */ 212 #define TMPFS_NODE_GEN_MASK (~0UL >> 1) 213 #define TMPFS_RECLAIMING_BIT (~TMPFS_NODE_GEN_MASK) 214 215 #define TMPFS_NODE_RECLAIMING(node) \ 216 (((node)->tn_gen & TMPFS_RECLAIMING_BIT) != 0) 217 218 #define TMPFS_NODE_GEN(node) \ 219 ((node)->tn_gen & TMPFS_NODE_GEN_MASK) 220 221 /* 222 * Internal representation of a tmpfs mount point. 223 */ 224 typedef struct tmpfs_mount { 225 /* Limit and number of bytes in use by the file system. */ 226 uint64_t tm_mem_limit; 227 uint64_t tm_bytes_used; 228 /* Highest allocated inode number. */ 229 uint64_t tm_highest_inode; 230 struct rwlock 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 struct rwlock 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 */ 250 typedef 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 261 int tmpfs_alloc_node(tmpfs_mount_t *, enum vtype, uid_t, gid_t, 262 mode_t, char *, dev_t, tmpfs_node_t **); 263 void tmpfs_free_node(tmpfs_mount_t *, tmpfs_node_t *); 264 265 int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *, 266 struct componentname *, char *); 267 268 int tmpfs_vnode_get(struct mount *, tmpfs_node_t *, struct vnode **); 269 270 int tmpfs_alloc_dirent(tmpfs_mount_t *, const char *, uint16_t, 271 tmpfs_dirent_t **); 272 void tmpfs_free_dirent(tmpfs_mount_t *, tmpfs_dirent_t *); 273 void tmpfs_dir_attach(tmpfs_node_t *, tmpfs_dirent_t *, 274 tmpfs_node_t *); 275 void tmpfs_dir_detach(tmpfs_node_t *, tmpfs_dirent_t *); 276 277 tmpfs_dirent_t *tmpfs_dir_lookup(tmpfs_node_t *, struct componentname *); 278 tmpfs_dirent_t *tmpfs_dir_cached(tmpfs_node_t *); 279 280 uint64_t tmpfs_dir_getseq(tmpfs_node_t *, tmpfs_dirent_t *); 281 tmpfs_dirent_t *tmpfs_dir_lookupbyseq(tmpfs_node_t *, off_t); 282 int tmpfs_dir_getdents(tmpfs_node_t *, struct uio *); 283 284 int tmpfs_reg_resize(struct vnode *, off_t); 285 int tmpfs_truncate(struct vnode *, off_t); 286 287 int tmpfs_chflags(struct vnode *, int, struct ucred *, struct proc *); 288 int tmpfs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *); 289 int tmpfs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *); 290 int tmpfs_chsize(struct vnode *, u_quad_t, struct ucred *, struct proc *); 291 int tmpfs_chtimes(struct vnode *, const struct timespec *, 292 const struct timespec *, int, struct ucred *, 293 struct proc *); 294 void tmpfs_update(tmpfs_node_t *, int); 295 int tmpfs_zeropg(tmpfs_node_t *, voff_t, vaddr_t); 296 int tmpfs_uio_cached(tmpfs_node_t *); 297 int tmpfs_uiomove(tmpfs_node_t *, struct uio *, vsize_t); 298 void tmpfs_uio_uncache(tmpfs_node_t *); 299 void tmpfs_uio_cache(tmpfs_node_t *, voff_t, vaddr_t); 300 vaddr_t tmpfs_uio_lookup(tmpfs_node_t *, voff_t); 301 302 /* 303 * Prototypes for tmpfs_mem.c. 304 */ 305 306 void tmpfs_mntmem_init(tmpfs_mount_t *, uint64_t); 307 void tmpfs_mntmem_destroy(tmpfs_mount_t *); 308 309 size_t tmpfs_mem_info(int); 310 uint64_t tmpfs_bytes_max(tmpfs_mount_t *); 311 uint64_t tmpfs_pages_avail(tmpfs_mount_t *); 312 int tmpfs_mem_incr(tmpfs_mount_t *, size_t); 313 void tmpfs_mem_decr(tmpfs_mount_t *, size_t); 314 315 tmpfs_dirent_t *tmpfs_dirent_get(tmpfs_mount_t *); 316 void tmpfs_dirent_put(tmpfs_mount_t *, tmpfs_dirent_t *); 317 318 tmpfs_node_t * tmpfs_node_get(tmpfs_mount_t *); 319 void tmpfs_node_put(tmpfs_mount_t *, tmpfs_node_t *); 320 321 char * tmpfs_strname_alloc(tmpfs_mount_t *, size_t); 322 void tmpfs_strname_free(tmpfs_mount_t *, char *, size_t); 323 int tmpfs_strname_neqlen(struct componentname *, struct componentname *); 324 325 /* 326 * Ensures that the node pointed by 'node' is a directory and that its 327 * contents are consistent with respect to directories. 328 */ 329 #define TMPFS_VALIDATE_DIR(node) \ 330 KASSERT((node)->tn_vnode == NULL || VOP_ISLOCKED((node)->tn_vnode)); \ 331 KASSERT((node)->tn_type == VDIR); \ 332 KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0); 333 334 /* 335 * Memory management stuff. 336 */ 337 338 /* Amount of memory pages to reserve for the system. */ 339 #define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) 340 341 /* 342 * Routines to convert VFS structures to tmpfs internal ones. 343 */ 344 345 static inline tmpfs_mount_t * 346 VFS_TO_TMPFS(struct mount *mp) 347 { 348 tmpfs_mount_t *tmp = mp->mnt_data; 349 350 KASSERT(tmp != NULL); 351 return tmp; 352 } 353 354 static inline tmpfs_node_t * 355 VP_TO_TMPFS_DIR(struct vnode *vp) 356 { 357 tmpfs_node_t *node = vp->v_data; 358 359 KASSERT(node != NULL); 360 TMPFS_VALIDATE_DIR(node); 361 return node; 362 } 363 364 #endif /* defined(_KERNEL) */ 365 366 static __inline tmpfs_node_t * 367 VP_TO_TMPFS_NODE(struct vnode *vp) 368 { 369 tmpfs_node_t *node = vp->v_data; 370 #ifdef KASSERT 371 KASSERT(node != NULL); 372 #endif 373 return node; 374 } 375 376 #endif /* _TMPFS_TMPFS_H_ */ 377