1/* $NetBSD: tmpfs.h,v 1.56 2020/05/17 19:39:15 ad Exp $ */ 2 3/* 4 * Copyright (c) 2005, 2006, 2007, 2020 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 /* Sequence number, see tmpfs_dir_getseq(). */ 58 uint32_t td_seq; 59 60 /* Name and its length. */ 61 char * td_name; 62 uint16_t td_namelen; 63} tmpfs_dirent_t; 64 65TAILQ_HEAD(tmpfs_dir, tmpfs_dirent); 66 67/* 68 * Internal representation of a tmpfs file system node -- inode. 69 * 70 * This structure is split in two parts: one holds attributes common 71 * to all file types and the other holds data that is only applicable to 72 * a particular type. 73 * 74 * All fields are protected by vnode lock. The vnode association itself 75 * is protected by vcache. 76 */ 77typedef struct tmpfs_node { 78 LIST_ENTRY(tmpfs_node) tn_entries; 79 80 /* 81 * Each inode has a corresponding vnode. It is a bi-directional 82 * association. Whenever vnode is allocated, its v_data field is 83 * set to the inode it reference, and tmpfs_node_t::tn_vnode is 84 * set to point to the said vnode. 85 * 86 * Further attempts to allocate a vnode for this same node will 87 * result in returning a new reference to the value stored in 88 * tn_vnode. It may be NULL when the node is unused (that is, 89 * no vnode has been allocated or it has been reclaimed). 90 */ 91 vnode_t * tn_vnode; 92 93 /* Prevent node from being reclaimed. */ 94 uint32_t tn_holdcount; 95 96 /* Directory entry. Only a hint, since hard link can have multiple. */ 97 tmpfs_dirent_t * tn_dirent_hint; 98 99 /* The inode type: VBLK, VCHR, VDIR, VFIFO, VLNK, VREG or VSOCK. */ 100 enum vtype tn_type; 101 102 /* Inode identifier and generation number. */ 103 ino_t tn_id; 104 uint32_t tn_gen; 105 106 /* The inode size. */ 107 off_t tn_size; 108 109 /* Generic node attributes. */ 110 uid_t tn_uid; 111 gid_t tn_gid; 112 mode_t tn_mode; 113 int tn_flags; 114 nlink_t tn_links; 115 unsigned tn_tflags; 116 struct timespec tn_atime; 117 struct timespec tn_mtime; 118 struct timespec tn_ctime; 119 struct timespec tn_birthtime; 120 kmutex_t tn_timelock; 121 122 /* Head of byte-level lock list (used by tmpfs_advlock). */ 123 struct lockf * tn_lockf; 124 125 union { 126 /* Type case: VBLK or VCHR. */ 127 struct { 128 dev_t tn_rdev; 129 } tn_dev; 130 131 /* Type case: VDIR. */ 132 struct { 133 /* Parent directory (root inode points to itself). */ 134 struct tmpfs_node * tn_parent; 135 136 /* List of directory entries. */ 137 struct tmpfs_dir tn_dir; 138 139 /* Last given sequence number and their arena. */ 140 uint32_t tn_next_seq; 141 void * tn_seq_arena; 142 143 /* 144 * Pointer of the last directory entry returned 145 * by the readdir(3) operation. 146 */ 147 struct tmpfs_dirent * tn_readdir_lastp; 148 } tn_dir; 149 150 /* Type case: VLNK. */ 151 struct tn_lnk { 152 /* The link's target. */ 153 char * tn_link; 154 } tn_lnk; 155 156 /* Type case: VREG. */ 157 struct tn_reg { 158 /* Underlying UVM object to store contents. */ 159 struct uvm_object * tn_aobj; 160 size_t tn_aobj_pages; 161 } tn_reg; 162 } tn_spec; 163} tmpfs_node_t; 164 165#if defined(_KERNEL) 166 167VFS_PROTOS(tmpfs); 168 169LIST_HEAD(tmpfs_node_list, tmpfs_node); 170 171#define TMPFS_MAXNAMLEN 255 172/* Validate maximum td_namelen length. */ 173CTASSERT(TMPFS_MAXNAMLEN < UINT16_MAX); 174 175/* 176 * Reserved values for the virtual entries (the first must be 0) and EOF. 177 * The start/end of the incremental range, see tmpfs_dir_getseq(). 178 */ 179#define TMPFS_DIRSEQ_DOT 0 180#define TMPFS_DIRSEQ_DOTDOT 1 181#define TMPFS_DIRSEQ_EOF 2 182 183#define TMPFS_DIRSEQ_START 3 /* inclusive */ 184#define TMPFS_DIRSEQ_END (1U << 30) /* exclusive */ 185 186/* Mark to indicate that the number is not set. */ 187#define TMPFS_DIRSEQ_NONE (1U << 31) 188 189/* Flags: time update requests. */ 190#define TMPFS_UPDATE_ATIME 0x01 191#define TMPFS_UPDATE_MTIME 0x02 192#define TMPFS_UPDATE_CTIME 0x04 193 194/* 195 * Bits indicating whiteout use for the directory. 196 * We abuse tmpfs_node_t::tn_gen for that. 197 */ 198#define TMPFS_WHITEOUT_BIT (1U << 31) 199#define TMPFS_NODE_GEN_MASK (TMPFS_WHITEOUT_BIT - 1) 200 201#define TMPFS_NODE_GEN(node) \ 202 ((node)->tn_gen & TMPFS_NODE_GEN_MASK) 203 204/* White-out inode indicator. */ 205#define TMPFS_NODE_WHITEOUT ((tmpfs_node_t *)-1) 206 207/* 208 * Bit indicating this node must be reclaimed when holdcount reaches zero. 209 * Ored into tmpfs_node_t::tn_holdcount. 210 */ 211#define TMPFS_NODE_RECLAIMED (1U << 30) 212 213/* 214 * Internal representation of a tmpfs mount point. 215 */ 216typedef struct tmpfs_mount { 217 /* Limit and number of bytes in use by the file system. */ 218 uint64_t tm_mem_limit; 219 uint64_t tm_bytes_used; 220 kmutex_t tm_acc_lock; 221 222 /* Pointer to the root inode. */ 223 tmpfs_node_t * tm_root; 224 225 /* Maximum number of possible nodes for this file system. */ 226 unsigned int tm_nodes_max; 227 228 /* Number of nodes currently allocated. */ 229 unsigned int tm_nodes_cnt; 230 231 /* List of inodes and the lock protecting it. */ 232 kmutex_t tm_lock; 233 struct tmpfs_node_list tm_nodes; 234} tmpfs_mount_t; 235 236/* 237 * This structure maps a file identifier to a tmpfs node. Used by the 238 * NFS code. 239 */ 240typedef struct tmpfs_fid { 241 uint16_t tf_len; 242 uint16_t tf_pad; 243 uint32_t tf_gen; 244 ino_t tf_id; 245} tmpfs_fid_t; 246 247/* 248 * Prototypes for tmpfs_subr.c. 249 */ 250 251void tmpfs_free_node(tmpfs_mount_t *, tmpfs_node_t *); 252 253int tmpfs_construct_node(vnode_t *, vnode_t **, struct vattr *, 254 struct componentname *, char *); 255 256int tmpfs_alloc_dirent(tmpfs_mount_t *, const char *, uint16_t, 257 tmpfs_dirent_t **); 258void tmpfs_free_dirent(tmpfs_mount_t *, tmpfs_dirent_t *); 259void tmpfs_dir_attach(tmpfs_node_t *, tmpfs_dirent_t *, tmpfs_node_t *); 260void tmpfs_dir_detach(tmpfs_node_t *, tmpfs_dirent_t *); 261 262tmpfs_dirent_t *tmpfs_dir_lookup(tmpfs_node_t *, struct componentname *); 263tmpfs_dirent_t *tmpfs_dir_cached(tmpfs_node_t *); 264 265uint32_t tmpfs_dir_getseq(tmpfs_node_t *, tmpfs_dirent_t *); 266tmpfs_dirent_t *tmpfs_dir_lookupbyseq(tmpfs_node_t *, off_t); 267int tmpfs_dir_getdents(tmpfs_node_t *, struct uio *, off_t *); 268 269int tmpfs_reg_resize(vnode_t *, off_t); 270 271int tmpfs_chflags(vnode_t *, int, kauth_cred_t, lwp_t *); 272int tmpfs_chmod(vnode_t *, mode_t, kauth_cred_t, lwp_t *); 273int tmpfs_chown(vnode_t *, uid_t, gid_t, kauth_cred_t, lwp_t *); 274int tmpfs_chsize(vnode_t *, u_quad_t, kauth_cred_t, lwp_t *); 275int tmpfs_chtimes(vnode_t *, const struct timespec *, 276 const struct timespec *, const struct timespec *, int, 277 kauth_cred_t, lwp_t *); 278void tmpfs_update(vnode_t *, unsigned); 279void tmpfs_update_locked(vnode_t *, unsigned); 280void tmpfs_update_lazily(vnode_t *, unsigned); 281 282/* 283 * Prototypes for tmpfs_mem.c. 284 */ 285 286void tmpfs_mntmem_init(tmpfs_mount_t *, uint64_t); 287void tmpfs_mntmem_destroy(tmpfs_mount_t *); 288int tmpfs_mntmem_set(tmpfs_mount_t *, uint64_t); 289 290size_t tmpfs_mem_info(bool); 291uint64_t tmpfs_bytes_max(tmpfs_mount_t *); 292size_t tmpfs_pages_avail(tmpfs_mount_t *); 293bool tmpfs_mem_incr(tmpfs_mount_t *, size_t); 294void tmpfs_mem_decr(tmpfs_mount_t *, size_t); 295 296tmpfs_dirent_t *tmpfs_dirent_get(tmpfs_mount_t *); 297void tmpfs_dirent_put(tmpfs_mount_t *, tmpfs_dirent_t *); 298 299tmpfs_node_t * tmpfs_node_get(tmpfs_mount_t *); 300void tmpfs_node_put(tmpfs_mount_t *, tmpfs_node_t *); 301 302char * tmpfs_strname_alloc(tmpfs_mount_t *, size_t); 303void tmpfs_strname_free(tmpfs_mount_t *, char *, size_t); 304bool tmpfs_strname_neqlen(struct componentname *, struct componentname *); 305 306/* 307 * Ensures that the node pointed by 'node' is a directory and that its 308 * contents are consistent with respect to directories. 309 */ 310#define TMPFS_VALIDATE_DIR(node) \ 311 KASSERT((node)->tn_vnode == NULL || VOP_ISLOCKED((node)->tn_vnode)); \ 312 KASSERT((node)->tn_type == VDIR); \ 313 KASSERT((node)->tn_size % sizeof(tmpfs_dirent_t) == 0); 314 315/* 316 * Routines to convert VFS structures to tmpfs internal ones. 317 */ 318 319static __inline tmpfs_mount_t * 320VFS_TO_TMPFS(struct mount *mp) 321{ 322 tmpfs_mount_t *tmp = mp->mnt_data; 323 324 KASSERT(tmp != NULL); 325 return tmp; 326} 327 328static __inline tmpfs_node_t * 329VP_TO_TMPFS_DIR(vnode_t *vp) 330{ 331 tmpfs_node_t *node = vp->v_data; 332 333 KASSERT(node != NULL); 334 TMPFS_VALIDATE_DIR(node); 335 return node; 336} 337 338#endif /* defined(_KERNEL) */ 339 340static __inline tmpfs_node_t * 341VP_TO_TMPFS_NODE(vnode_t *vp) 342{ 343 tmpfs_node_t *node = vp->v_data; 344#ifdef KASSERT 345 KASSERT(node != NULL); 346#endif 347 return node; 348} 349 350#endif /* _FS_TMPFS_TMPFS_H_ */ 351