1 /* $OpenBSD: tmpfs.h,v 1.10 2020/10/12 13:08:03 visa 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_state * 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 #include <lib/libkern/libkern.h> /* for KASSERT() */ 176 177 LIST_HEAD(tmpfs_node_list, tmpfs_node); 178 179 180 #define TMPFS_MAXNAMLEN 255 181 /* Validate maximum td_namelen length. */ 182 /* CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX); */ 183 184 /* 185 * Reserved values for the virtual entries (the first must be 0) and EOF. 186 * The start/end of the incremental range, see tmpfs_dir_getseq(). 187 */ 188 #define TMPFS_DIRSEQ_DOT 0 189 #define TMPFS_DIRSEQ_DOTDOT 1 190 #define TMPFS_DIRSEQ_EOF 2 191 192 #define TMPFS_DIRSEQ_START 3 /* inclusive */ 193 #define TMPFS_DIRSEQ_END UINT64_MAX /* exclusive */ 194 195 /* Mark to indicate that the number is not set. */ 196 #define TMPFS_DIRSEQ_NONE UINT64_MAX 197 198 /* Can we still append entries to a directory? */ 199 #define TMPFS_DIRSEQ_FULL(dnode) \ 200 ((dnode)->tn_spec.tn_dir.tn_next_seq == TMPFS_DIRSEQ_END) 201 202 /* Status flags. */ 203 #define TMPFS_NODE_ACCESSED 0x01 204 #define TMPFS_NODE_MODIFIED 0x02 205 #define TMPFS_NODE_CHANGED 0x04 206 207 #define TMPFS_NODE_STATUSALL \ 208 (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED) 209 210 /* 211 * Bit indicating vnode reclamation. 212 * We abuse tmpfs_node_t::tn_gen for that. 213 */ 214 #define TMPFS_NODE_GEN_MASK (~0UL >> 1) 215 #define TMPFS_RECLAIMING_BIT (~TMPFS_NODE_GEN_MASK) 216 217 #define TMPFS_NODE_RECLAIMING(node) \ 218 (((node)->tn_gen & TMPFS_RECLAIMING_BIT) != 0) 219 220 #define TMPFS_NODE_GEN(node) \ 221 ((node)->tn_gen & TMPFS_NODE_GEN_MASK) 222 223 /* 224 * Internal representation of a tmpfs mount point. 225 */ 226 typedef 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 /* Highest allocated inode number. */ 231 uint64_t tm_highest_inode; 232 struct rwlock tm_acc_lock; 233 234 /* Pointer to the root inode. */ 235 tmpfs_node_t * tm_root; 236 237 /* Maximum number of possible nodes for this file system. */ 238 unsigned int tm_nodes_max; 239 240 /* Number of nodes currently allocated. */ 241 unsigned int tm_nodes_cnt; 242 243 /* List of inodes and the lock protecting it. */ 244 struct rwlock tm_lock; 245 struct tmpfs_node_list tm_nodes; 246 } tmpfs_mount_t; 247 248 /* 249 * This structure maps a file identifier to a tmpfs node. Used by the 250 * NFS code. 251 */ 252 typedef struct tmpfs_fid { 253 uint16_t tf_len; 254 uint16_t tf_pad; 255 uint32_t tf_gen; 256 ino_t tf_id; 257 } tmpfs_fid_t; 258 259 /* 260 * Prototypes for tmpfs_subr.c. 261 */ 262 263 int tmpfs_alloc_node(tmpfs_mount_t *, enum vtype, uid_t, gid_t, 264 mode_t, char *, dev_t, tmpfs_node_t **); 265 void tmpfs_free_node(tmpfs_mount_t *, tmpfs_node_t *); 266 267 int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *, 268 struct componentname *, char *); 269 270 int tmpfs_vnode_get(struct mount *, tmpfs_node_t *, struct vnode **); 271 272 int tmpfs_alloc_dirent(tmpfs_mount_t *, const char *, uint16_t, 273 tmpfs_dirent_t **); 274 void tmpfs_free_dirent(tmpfs_mount_t *, tmpfs_dirent_t *); 275 void tmpfs_dir_attach(tmpfs_node_t *, tmpfs_dirent_t *, 276 tmpfs_node_t *); 277 void tmpfs_dir_detach(tmpfs_node_t *, tmpfs_dirent_t *); 278 279 tmpfs_dirent_t *tmpfs_dir_lookup(tmpfs_node_t *, struct componentname *); 280 tmpfs_dirent_t *tmpfs_dir_cached(tmpfs_node_t *); 281 282 uint64_t tmpfs_dir_getseq(tmpfs_node_t *, tmpfs_dirent_t *); 283 tmpfs_dirent_t *tmpfs_dir_lookupbyseq(tmpfs_node_t *, off_t); 284 int tmpfs_dir_getdents(tmpfs_node_t *, struct uio *); 285 286 int tmpfs_reg_resize(struct vnode *, off_t); 287 int tmpfs_truncate(struct vnode *, off_t); 288 289 int tmpfs_chflags(struct vnode *, int, struct ucred *, struct proc *); 290 int tmpfs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *); 291 int tmpfs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *); 292 int tmpfs_chsize(struct vnode *, u_quad_t, struct ucred *, struct proc *); 293 int tmpfs_chtimes(struct vnode *, const struct timespec *, 294 const struct timespec *, int, struct ucred *, 295 struct proc *); 296 void tmpfs_update(tmpfs_node_t *, int); 297 int tmpfs_zeropg(tmpfs_node_t *, voff_t, vaddr_t); 298 int tmpfs_uio_cached(tmpfs_node_t *); 299 int tmpfs_uiomove(tmpfs_node_t *, struct uio *, vsize_t); 300 void tmpfs_uio_uncache(tmpfs_node_t *); 301 void tmpfs_uio_cache(tmpfs_node_t *, voff_t, vaddr_t); 302 vaddr_t tmpfs_uio_lookup(tmpfs_node_t *, voff_t); 303 304 /* 305 * Prototypes for tmpfs_mem.c. 306 */ 307 308 void tmpfs_mntmem_init(tmpfs_mount_t *, uint64_t); 309 void tmpfs_mntmem_destroy(tmpfs_mount_t *); 310 311 size_t tmpfs_mem_info(int); 312 uint64_t tmpfs_bytes_max(tmpfs_mount_t *); 313 uint64_t tmpfs_pages_avail(tmpfs_mount_t *); 314 int tmpfs_mem_incr(tmpfs_mount_t *, size_t); 315 void tmpfs_mem_decr(tmpfs_mount_t *, size_t); 316 317 tmpfs_dirent_t *tmpfs_dirent_get(tmpfs_mount_t *); 318 void tmpfs_dirent_put(tmpfs_mount_t *, tmpfs_dirent_t *); 319 320 tmpfs_node_t * tmpfs_node_get(tmpfs_mount_t *); 321 void tmpfs_node_put(tmpfs_mount_t *, tmpfs_node_t *); 322 323 char * tmpfs_strname_alloc(tmpfs_mount_t *, size_t); 324 void tmpfs_strname_free(tmpfs_mount_t *, char *, size_t); 325 int tmpfs_strname_neqlen(struct componentname *, struct componentname *); 326 327 /* 328 * Ensures that the node pointed by 'node' is a directory and that its 329 * contents are consistent with respect to directories. 330 */ 331 #define TMPFS_VALIDATE_DIR(node) \ 332 KASSERT((node)->tn_vnode == NULL || VOP_ISLOCKED((node)->tn_vnode)); \ 333 KASSERT((node)->tn_type == VDIR); \ 334 KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0); 335 336 /* 337 * Memory management stuff. 338 */ 339 340 /* Amount of memory pages to reserve for the system. */ 341 #define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) 342 343 /* 344 * Routines to convert VFS structures to tmpfs internal ones. 345 */ 346 347 static inline tmpfs_mount_t * 348 VFS_TO_TMPFS(struct mount *mp) 349 { 350 tmpfs_mount_t *tmp = mp->mnt_data; 351 352 KASSERT(tmp != NULL); 353 return tmp; 354 } 355 356 static inline tmpfs_node_t * 357 VP_TO_TMPFS_DIR(struct vnode *vp) 358 { 359 tmpfs_node_t *node = vp->v_data; 360 361 KASSERT(node != NULL); 362 TMPFS_VALIDATE_DIR(node); 363 return node; 364 } 365 366 #endif /* defined(_KERNEL) */ 367 368 static __inline tmpfs_node_t * 369 VP_TO_TMPFS_NODE(struct vnode *vp) 370 { 371 tmpfs_node_t *node = vp->v_data; 372 #ifdef KASSERT 373 KASSERT(node != NULL); 374 #endif 375 return node; 376 } 377 378 #endif /* _TMPFS_TMPFS_H_ */ 379