1 /* $NetBSD: tmpfs.h,v 1.20 2006/05/27 09:12:31 yamt Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006 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 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #ifndef _FS_TMPFS_TMPFS_H_ 41 #define _FS_TMPFS_TMPFS_H_ 42 43 /* --------------------------------------------------------------------- 44 * KERNEL-SPECIFIC DEFINITIONS 45 * --------------------------------------------------------------------- */ 46 #include <sys/dirent.h> 47 #include <sys/mount.h> 48 #include <sys/queue.h> 49 #include <sys/vnode.h> 50 51 #if defined(_KERNEL) 52 #include <fs/tmpfs/tmpfs_pool.h> 53 #endif /* defined(_KERNEL) */ 54 55 /* --------------------------------------------------------------------- */ 56 57 /* 58 * Internal representation of a tmpfs directory entry. 59 */ 60 struct tmpfs_dirent { 61 TAILQ_ENTRY(tmpfs_dirent) td_entries; 62 63 /* Length of the name stored in this directory entry. This avoids 64 * the need to recalculate it every time the name is used. */ 65 uint16_t td_namelen; 66 67 /* The name of the entry, allocated from a string pool. This 68 * string is not required to be zero-terminated; therefore, the 69 * td_namelen field must always be used when accessing its value. */ 70 char * td_name; 71 72 /* Pointer to the node this entry refers to. */ 73 struct tmpfs_node * td_node; 74 }; 75 76 /* A directory in tmpfs holds a sorted list of directory entries, which in 77 * turn point to other files (which can be directories themselves). 78 * 79 * In tmpfs, this list is managed by a tail queue, whose head is defined by 80 * the struct tmpfs_dir type. 81 * 82 * It is imporant to notice that directories do not have entries for . and 83 * .. as other file systems do. These can be generated when requested 84 * based on information available by other means, such as the pointer to 85 * the node itself in the former case or the pointer to the parent directory 86 * in the latter case. This is done to simplify tmpfs's code and, more 87 * importantly, to remove redundancy. */ 88 TAILQ_HEAD(tmpfs_dir, tmpfs_dirent); 89 90 #define TMPFS_DIRCOOKIE(dirent) ((off_t)(uintptr_t)(dirent)) 91 #define TMPFS_DIRCOOKIE_DOT 0 92 #define TMPFS_DIRCOOKIE_DOTDOT 1 93 #define TMPFS_DIRCOOKIE_EOF 2 94 95 /* --------------------------------------------------------------------- */ 96 97 /* 98 * Internal representation of a tmpfs file system node. 99 * 100 * This structure is splitted in two parts: one holds attributes common 101 * to all file types and the other holds data that is only applicable to 102 * a particular type. The code must be careful to only access those 103 * attributes that are actually allowed by the node's type. 104 */ 105 struct tmpfs_node { 106 /* Doubly-linked list entry which links all existing nodes for a 107 * single file system. This is provided to ease the removal of 108 * all nodes during the unmount operation. */ 109 LIST_ENTRY(tmpfs_node) tn_entries; 110 111 /* The node's type. Any of 'VBLK', 'VCHR', 'VDIR', 'VFIFO', 112 * 'VLNK', 'VREG' and 'VSOCK' is allowed. The usage of vnode 113 * types instead of a custom enumeration is to make things simpler 114 * and faster, as we do not need to convert between two types. */ 115 enum vtype tn_type; 116 117 /* Node identifier. */ 118 ino_t tn_id; 119 120 /* Node's internal status. This is used by several file system 121 * operations to do modifications to the node in a delayed 122 * fashion. */ 123 int tn_status; 124 #define TMPFS_NODE_ACCESSED (1 << 1) 125 #define TMPFS_NODE_MODIFIED (1 << 2) 126 #define TMPFS_NODE_CHANGED (1 << 3) 127 128 /* The node size. It does not necessarily match the real amount 129 * of memory consumed by it. */ 130 off_t tn_size; 131 132 /* Generic node attributes. */ 133 uid_t tn_uid; 134 gid_t tn_gid; 135 mode_t tn_mode; 136 int tn_flags; 137 nlink_t tn_links; 138 struct timespec tn_atime; 139 struct timespec tn_mtime; 140 struct timespec tn_ctime; 141 struct timespec tn_birthtime; 142 unsigned long tn_gen; 143 144 /* Head of byte-level lock list (used by tmpfs_advlock). */ 145 struct lockf * tn_lockf; 146 147 /* As there is a single vnode for each active file within the 148 * system, care has to be taken to avoid allocating more than one 149 * vnode per file. In order to do this, a bidirectional association 150 * is kept between vnodes and nodes. 151 * 152 * Whenever a vnode is allocated, its v_data field is updated to 153 * point to the node it references. At the same time, the node's 154 * tn_vnode field is modified to point to the new vnode representing 155 * it. Further attempts to allocate a vnode for this same node will 156 * result in returning a new reference to the value stored in 157 * tn_vnode. 158 * 159 * May be NULL when the node is unused (that is, no vnode has been 160 * allocated for it or it has been reclaimed). */ 161 struct vnode * tn_vnode; 162 163 /* Pointer to the node returned by tmpfs_lookup() after doing a 164 * delete or a rename lookup; its value is only valid in these two 165 * situations. In case we were looking up . or .., it holds a null 166 * pointer. */ 167 struct tmpfs_dirent * tn_lookup_dirent; 168 169 union { 170 /* Valid when tn_type == VBLK || tn_type == VCHR. */ 171 struct { 172 dev_t tn_rdev; 173 } tn_dev; 174 175 /* Valid when tn_type == VDIR. */ 176 struct { 177 /* Pointer to the parent directory. The root 178 * directory has a pointer to itself in this field; 179 * this property identifies the root node. */ 180 struct tmpfs_node * tn_parent; 181 182 /* Head of a tail-queue that links the contents of 183 * the directory together. See above for a 184 * description of its contents. */ 185 struct tmpfs_dir tn_dir; 186 187 /* Number and pointer of the first directory entry 188 * returned by the readdir operation if it were 189 * called again to continue reading data from the 190 * same directory as before. This is used to speed 191 * up reads of long directories, assuming that no 192 * more than one read is in progress at a given time. 193 * Otherwise, these values are discarded and a linear 194 * scan is performed from the beginning up to the 195 * point where readdir starts returning values. */ 196 off_t tn_readdir_lastn; 197 struct tmpfs_dirent * tn_readdir_lastp; 198 } tn_dir; 199 200 /* Valid when tn_type == VLNK. */ 201 struct tn_lnk { 202 /* The link's target, allocated from a string pool. */ 203 char * tn_link; 204 } tn_lnk; 205 206 /* Valid when tn_type == VREG. */ 207 struct tn_reg { 208 /* The contents of regular files stored in a tmpfs 209 * file system are represented by a single anonymous 210 * memory object (aobj, for short). The aobj provides 211 * direct access to any position within the file, 212 * because its contents are always mapped in a 213 * contiguous region of virtual memory. It is a task 214 * of the memory management subsystem (see uvm(9)) to 215 * issue the required page ins or page outs whenever 216 * a position within the file is accessed. */ 217 struct uvm_object * tn_aobj; 218 size_t tn_aobj_pages; 219 } tn_reg; 220 } tn_spec; 221 }; 222 223 #if defined(_KERNEL) 224 225 LIST_HEAD(tmpfs_node_list, tmpfs_node); 226 227 /* --------------------------------------------------------------------- */ 228 229 /* 230 * Internal representation of a tmpfs mount point. 231 */ 232 struct tmpfs_mount { 233 /* Maximum number of memory pages available for use by the file 234 * system, set during mount time. This variable must never be 235 * used directly as it may be bigger that the current amount of 236 * free memory; in the extreme case, it will hold the SIZE_MAX 237 * value. Instead, use the TMPFS_PAGES_MAX macro. */ 238 size_t tm_pages_max; 239 240 /* Number of pages in use by the file system. Cannot be bigger 241 * than the value returned by TMPFS_PAGES_MAX in any case. */ 242 size_t tm_pages_used; 243 244 /* Pointer to the node representing the root directory of this 245 * file system. */ 246 struct tmpfs_node * tm_root; 247 248 /* Maximum number of possible nodes for this file system; set 249 * during mount time. We need a hard limit on the maximum number 250 * of nodes to avoid allocating too much of them; their objects 251 * cannot be released until the file system is unmounted. 252 * Otherwise, we could easily run out of memory by creating lots 253 * of empty files and then simply removing them. */ 254 ino_t tm_nodes_max; 255 256 /* Number of nodes currently allocated. This number only grows. 257 * When it reaches tm_nodes_max, no more new nodes can be allocated. 258 * Of course, the old, unused ones can be reused. */ 259 ino_t tm_nodes_last; 260 261 /* Nodes are organized in two different lists. The used list 262 * contains all nodes that are currently used by the file system; 263 * i.e., they refer to existing files. The available list contains 264 * all nodes that are currently available for use by new files. 265 * Nodes must be kept in this list (instead of deleting them) 266 * because we need to keep track of their generation number (tn_gen 267 * field). 268 * 269 * Note that nodes are lazily allocated: if the available list is 270 * empty and we have enough space to create more nodes, they will be 271 * created and inserted in the used list. Once these are released, 272 * they will go into the available list, remaining alive until the 273 * file system is unmounted. */ 274 struct tmpfs_node_list tm_nodes_used; 275 struct tmpfs_node_list tm_nodes_avail; 276 277 /* Pools used to store file system meta data. These are not shared 278 * across several instances of tmpfs for the reasons described in 279 * tmpfs_pool.c. */ 280 struct tmpfs_pool tm_dirent_pool; 281 struct tmpfs_pool tm_node_pool; 282 struct tmpfs_str_pool tm_str_pool; 283 }; 284 285 /* --------------------------------------------------------------------- */ 286 287 /* 288 * This structure maps a file identifier to a tmpfs node. Used by the 289 * NFS code. 290 */ 291 struct tmpfs_fid { 292 uint16_t tf_len; 293 uint16_t tf_pad; 294 uint32_t tf_gen; 295 ino_t tf_id; 296 }; 297 298 /* --------------------------------------------------------------------- */ 299 300 /* 301 * Prototypes for tmpfs_subr.c. 302 */ 303 304 int tmpfs_alloc_node(struct tmpfs_mount *, enum vtype, 305 uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *, 306 char *, dev_t, struct proc *, struct tmpfs_node **); 307 void tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *); 308 int tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *, 309 const char *, uint16_t, struct tmpfs_dirent **); 310 void tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *, 311 boolean_t); 312 int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, struct vnode **); 313 void tmpfs_free_vp(struct vnode *); 314 int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *, 315 struct componentname *, char *); 316 void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *); 317 void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *); 318 struct tmpfs_dirent * tmpfs_dir_lookup(struct tmpfs_node *node, 319 struct componentname *cnp); 320 int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *); 321 int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *); 322 struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t); 323 int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *); 324 int tmpfs_reg_resize(struct vnode *, off_t); 325 size_t tmpfs_mem_info(boolean_t); 326 int tmpfs_chflags(struct vnode *, int, kauth_cred_t, struct proc *); 327 int tmpfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct proc *); 328 int tmpfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, struct proc *); 329 int tmpfs_chsize(struct vnode *, u_quad_t, kauth_cred_t, struct proc *); 330 int tmpfs_chtimes(struct vnode *, struct timespec *, struct timespec *, 331 int, kauth_cred_t, struct lwp *); 332 void tmpfs_itimes(struct vnode *, const struct timespec *, 333 const struct timespec *); 334 335 void tmpfs_update(struct vnode *, const struct timespec *, 336 const struct timespec *, int); 337 int tmpfs_truncate(struct vnode *, off_t); 338 339 /* --------------------------------------------------------------------- */ 340 341 /* 342 * Convenience macros to simplify some logical expressions. 343 */ 344 #define IMPLIES(a, b) (!(a) || (b)) 345 #define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a)) 346 347 /* --------------------------------------------------------------------- */ 348 349 /* 350 * Checks that the directory entry pointed by 'de' matches the name 'name' 351 * with a length of 'len'. 352 */ 353 #define TMPFS_DIRENT_MATCHES(de, name, len) \ 354 (de->td_namelen == (uint16_t)len && \ 355 memcmp((de)->td_name, (name), (de)->td_namelen) == 0) 356 357 /* --------------------------------------------------------------------- */ 358 359 /* 360 * Ensures that the node pointed by 'node' is a directory and that its 361 * contents are consistent with respect to directories. 362 */ 363 #define TMPFS_VALIDATE_DIR(node) \ 364 KASSERT((node)->tn_type == VDIR); \ 365 KASSERT((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \ 366 KASSERT((node)->tn_spec.tn_dir.tn_readdir_lastp == NULL || \ 367 TMPFS_DIRCOOKIE((node)->tn_spec.tn_dir.tn_readdir_lastp) == \ 368 (node)->tn_spec.tn_dir.tn_readdir_lastn); 369 370 /* --------------------------------------------------------------------- */ 371 372 /* 373 * Memory management stuff. 374 */ 375 376 /* Amount of memory pages to reserve for the system (e.g., to not use by 377 * tmpfs). 378 * XXX: Should this be tunable through sysctl, for instance? */ 379 #define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) 380 381 /* Returns the maximum size allowed for a tmpfs file system. This macro 382 * must be used instead of directly retrieving the value from tm_pages_max. 383 * The reason is that the size of a tmpfs file system is dynamic: it lets 384 * the user store files as long as there is enough free memory (including 385 * physical memory and swap space). Therefore, the amount of memory to be 386 * used is either the limit imposed by the user during mount time or the 387 * amount of available memory, whichever is lower. To avoid consuming all 388 * the memory for a given mount point, the system will always reserve a 389 * minimum of TMPFS_PAGES_RESERVED pages, which is also taken into account 390 * by this macro (see above). */ 391 static __inline size_t 392 TMPFS_PAGES_MAX(struct tmpfs_mount *tmp) 393 { 394 size_t freepages; 395 396 freepages = tmpfs_mem_info(FALSE); 397 if (freepages < TMPFS_PAGES_RESERVED) 398 freepages = 0; 399 else 400 freepages -= TMPFS_PAGES_RESERVED; 401 402 return MIN(tmp->tm_pages_max, freepages + tmp->tm_pages_used); 403 } 404 405 /* Returns the available space for the given file system. */ 406 #define TMPFS_PAGES_AVAIL(tmp) (TMPFS_PAGES_MAX(tmp) - (tmp)->tm_pages_used) 407 408 /* --------------------------------------------------------------------- */ 409 410 /* 411 * Macros/functions to convert from generic data structures to tmpfs 412 * specific ones. 413 */ 414 415 static __inline 416 struct tmpfs_mount * 417 VFS_TO_TMPFS(struct mount *mp) 418 { 419 struct tmpfs_mount *tmp; 420 421 #ifdef KASSERT 422 KASSERT((mp) != NULL && (mp)->mnt_data != NULL); 423 #endif 424 tmp = (struct tmpfs_mount *)(mp)->mnt_data; 425 return tmp; 426 } 427 428 #endif /* defined(_KERNEL) */ 429 430 static __inline 431 struct tmpfs_node * 432 VP_TO_TMPFS_NODE(struct vnode *vp) 433 { 434 struct tmpfs_node *node; 435 436 #ifdef KASSERT 437 KASSERT((vp) != NULL && (vp)->v_data != NULL); 438 #endif 439 node = (struct tmpfs_node *)vp->v_data; 440 return node; 441 } 442 443 #if defined(_KERNEL) 444 445 static __inline 446 struct tmpfs_node * 447 VP_TO_TMPFS_DIR(struct vnode *vp) 448 { 449 struct tmpfs_node *node; 450 451 node = VP_TO_TMPFS_NODE(vp); 452 #ifdef KASSERT 453 TMPFS_VALIDATE_DIR(node); 454 #endif 455 return node; 456 } 457 458 #endif /* defined(_KERNEL) */ 459 460 /* --------------------------------------------------------------------- 461 * USER AND KERNEL DEFINITIONS 462 * --------------------------------------------------------------------- */ 463 464 /* 465 * This structure is used to communicate mount parameters between userland 466 * and kernel space. 467 */ 468 #define TMPFS_ARGS_VERSION 1 469 struct tmpfs_args { 470 int ta_version; 471 472 /* Size counters. */ 473 ino_t ta_nodes_max; 474 off_t ta_size_max; 475 476 /* Root node attributes. */ 477 uid_t ta_root_uid; 478 gid_t ta_root_gid; 479 mode_t ta_root_mode; 480 }; 481 #endif /* _FS_TMPFS_TMPFS_H_ */ 482