1 /* $NetBSD: tmpfs.h,v 1.41 2011/05/24 20:17:49 rmind Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006, 2007 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 #include <sys/dirent.h> 37 #include <sys/mount.h> 38 #include <sys/pool.h> 39 #include <sys/queue.h> 40 #include <sys/vnode.h> 41 42 /* 43 * Internal representation of a tmpfs directory entry. 44 * 45 * All fields are protected by vnode lock. 46 */ 47 typedef struct tmpfs_dirent { 48 TAILQ_ENTRY(tmpfs_dirent) td_entries; 49 50 /* Pointer to the inode this entry refers to. */ 51 struct tmpfs_node * td_node; 52 53 /* Name and its length. */ 54 char * td_name; 55 uint16_t td_namelen; 56 } tmpfs_dirent_t; 57 58 TAILQ_HEAD(tmpfs_dir, tmpfs_dirent); 59 60 #if defined(_KERNEL) 61 62 /* Validate maximum td_namelen length. */ 63 CTASSERT(MAXNAMLEN < UINT16_MAX); 64 65 #define TMPFS_DIRCOOKIE_DOT 0 66 #define TMPFS_DIRCOOKIE_DOTDOT 1 67 #define TMPFS_DIRCOOKIE_EOF 2 68 69 /* 70 * Each entry in a directory has a cookie that identifies it. Cookies 71 * supersede offsets within directories, as tmpfs has no offsets as such. 72 * 73 * The '.', '..' and the end of directory markers have fixed cookies, 74 * which cannot collide with the cookies generated by other entries. 75 * 76 * The cookies for the other entries are generated based on the memory 77 * address of their representative meta-data structure. 78 * 79 * XXX: Truncating directory cookies to 31 bits now - workaround for 80 * problem with Linux compat, see PR/32034. 81 */ 82 static inline off_t 83 tmpfs_dircookie(tmpfs_dirent_t *de) 84 { 85 off_t cookie; 86 87 cookie = ((off_t)(uintptr_t)de >> 1) & 0x7FFFFFFF; 88 KASSERT(cookie != TMPFS_DIRCOOKIE_DOT); 89 KASSERT(cookie != TMPFS_DIRCOOKIE_DOTDOT); 90 KASSERT(cookie != TMPFS_DIRCOOKIE_EOF); 91 92 return cookie; 93 } 94 #endif 95 96 /* 97 * Internal representation of a tmpfs file system node -- inode. 98 * 99 * This structure is splitted in two parts: one holds attributes common 100 * to all file types and the other holds data that is only applicable to 101 * a particular type. 102 * 103 * All fields are protected by vnode lock. The vnode association itself 104 * is protected by tmpfs_node_t::tn_vlock. 105 */ 106 typedef struct tmpfs_node { 107 LIST_ENTRY(tmpfs_node) tn_entries; 108 109 /* The inode type: VBLK, VCHR, VDIR, VFIFO, VLNK, VREG or VSOCK. */ 110 enum vtype tn_type; 111 112 /* Inode identifier. */ 113 ino_t tn_id; 114 115 /* Inode status flags (for operations in delayed manner). */ 116 int tn_status; 117 118 /* The inode size. */ 119 off_t tn_size; 120 121 /* Generic node attributes. */ 122 uid_t tn_uid; 123 gid_t tn_gid; 124 mode_t tn_mode; 125 int tn_flags; 126 nlink_t tn_links; 127 struct timespec tn_atime; 128 struct timespec tn_mtime; 129 struct timespec tn_ctime; 130 struct timespec tn_birthtime; 131 unsigned long tn_gen; 132 133 /* Head of byte-level lock list (used by tmpfs_advlock). */ 134 struct lockf * tn_lockf; 135 136 /* 137 * Each inode has a corresponding vnode. It is a bi-directional 138 * association. Whenever vnode is allocated, its v_data field is 139 * set to the inode it reference, and tmpfs_node_t::tn_vnode is 140 * set to point to the said vnode. 141 * 142 * Further attempts to allocate a vnode for this same node will 143 * result in returning a new reference to the value stored in 144 * tn_vnode. It may be NULL when the node is unused (that is, 145 * no vnode has been allocated or it has been reclaimed). 146 */ 147 kmutex_t tn_vlock; 148 vnode_t * tn_vnode; 149 150 union { 151 /* Type case: VBLK or VCHR. */ 152 struct { 153 dev_t tn_rdev; 154 } tn_dev; 155 156 /* Type case: VDIR. */ 157 struct { 158 /* Parent directory (root inode points to itself). */ 159 struct tmpfs_node * tn_parent; 160 161 /* List of directory entries. */ 162 struct tmpfs_dir tn_dir; 163 164 /* 165 * Number and pointer of the last directory entry 166 * returned by the readdir(3) operation. 167 */ 168 off_t tn_readdir_lastn; 169 struct tmpfs_dirent * tn_readdir_lastp; 170 } tn_dir; 171 172 /* Type case: VLNK. */ 173 struct tn_lnk { 174 /* The link's target. */ 175 char * tn_link; 176 } tn_lnk; 177 178 /* Type case: VREG. */ 179 struct tn_reg { 180 /* Underlying UVM object to store contents. */ 181 struct uvm_object * tn_aobj; 182 size_t tn_aobj_pages; 183 } tn_reg; 184 } tn_spec; 185 } tmpfs_node_t; 186 187 #if defined(_KERNEL) 188 189 LIST_HEAD(tmpfs_node_list, tmpfs_node); 190 191 /* Status flags. */ 192 #define TMPFS_NODE_ACCESSED 0x01 193 #define TMPFS_NODE_MODIFIED 0x02 194 #define TMPFS_NODE_CHANGED 0x04 195 196 #define TMPFS_NODE_STATUSALL \ 197 (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED) 198 199 /* White-out inode indicator. */ 200 #define TMPFS_NODE_WHITEOUT ((struct tmpfs_node *)-1) 201 202 /* 203 * Internal representation of a tmpfs mount point. 204 */ 205 typedef struct tmpfs_mount { 206 /* Limit and number of bytes in use by the file system. */ 207 uint64_t tm_mem_limit; 208 uint64_t tm_bytes_used; 209 kmutex_t tm_acc_lock; 210 211 /* Pointer to the root inode. */ 212 tmpfs_node_t * tm_root; 213 214 /* Maximum number of possible nodes for this file system. */ 215 unsigned int tm_nodes_max; 216 217 /* Number of nodes currently allocated. */ 218 unsigned int tm_nodes_cnt; 219 220 /* List of inodes and the lock protecting it. */ 221 kmutex_t tm_lock; 222 struct tmpfs_node_list tm_nodes; 223 } tmpfs_mount_t; 224 225 /* 226 * This structure maps a file identifier to a tmpfs node. Used by the 227 * NFS code. 228 */ 229 typedef struct tmpfs_fid { 230 uint16_t tf_len; 231 uint16_t tf_pad; 232 uint32_t tf_gen; 233 ino_t tf_id; 234 } tmpfs_fid_t; 235 236 /* 237 * Prototypes for tmpfs_subr.c. 238 */ 239 240 int tmpfs_alloc_node(struct tmpfs_mount *, enum vtype, 241 uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *, 242 char *, dev_t, struct tmpfs_node **); 243 void tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *); 244 int tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *, 245 const char *, uint16_t, struct tmpfs_dirent **); 246 void tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *, 247 bool); 248 int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, struct vnode **); 249 void tmpfs_free_vp(struct vnode *); 250 int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *, 251 struct componentname *, char *); 252 void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *); 253 void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *); 254 struct tmpfs_dirent * tmpfs_dir_lookup(struct tmpfs_node *node, 255 struct componentname *cnp); 256 int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *); 257 int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *); 258 struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t); 259 int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *); 260 int tmpfs_reg_resize(struct vnode *, off_t); 261 int tmpfs_chflags(struct vnode *, int, kauth_cred_t, struct lwp *); 262 int tmpfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *); 263 int tmpfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, struct lwp *); 264 int tmpfs_chsize(struct vnode *, u_quad_t, kauth_cred_t, struct lwp *); 265 int tmpfs_chtimes(struct vnode *, const struct timespec *, 266 const struct timespec *, const struct timespec *, int, kauth_cred_t, 267 struct lwp *); 268 void tmpfs_update(struct vnode *, const struct timespec *, 269 const struct timespec *, const struct timespec *, int); 270 int tmpfs_truncate(struct vnode *, off_t); 271 272 /* 273 * Prototypes for tmpfs_mem.c. 274 */ 275 276 void tmpfs_mntmem_init(struct tmpfs_mount *, uint64_t); 277 void tmpfs_mntmem_destroy(struct tmpfs_mount *); 278 279 size_t tmpfs_mem_info(bool); 280 uint64_t tmpfs_bytes_max(struct tmpfs_mount *); 281 size_t tmpfs_pages_avail(struct tmpfs_mount *); 282 bool tmpfs_mem_incr(struct tmpfs_mount *, size_t); 283 void tmpfs_mem_decr(struct tmpfs_mount *, size_t); 284 285 struct tmpfs_dirent *tmpfs_dirent_get(struct tmpfs_mount *); 286 void tmpfs_dirent_put(struct tmpfs_mount *, struct tmpfs_dirent *); 287 288 struct tmpfs_node *tmpfs_node_get(struct tmpfs_mount *); 289 void tmpfs_node_put(struct tmpfs_mount *, struct tmpfs_node *); 290 291 char * tmpfs_strname_alloc(struct tmpfs_mount *, size_t); 292 void tmpfs_strname_free(struct tmpfs_mount *, char *, size_t); 293 bool tmpfs_strname_neqlen(struct componentname *, struct componentname *); 294 295 /* 296 * Ensures that the node pointed by 'node' is a directory and that its 297 * contents are consistent with respect to directories. 298 */ 299 #define TMPFS_VALIDATE_DIR(node) \ 300 KASSERT((node)->tn_type == VDIR); \ 301 KASSERT((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \ 302 KASSERT((node)->tn_spec.tn_dir.tn_readdir_lastp == NULL || \ 303 tmpfs_dircookie((node)->tn_spec.tn_dir.tn_readdir_lastp) == \ 304 (node)->tn_spec.tn_dir.tn_readdir_lastn); 305 306 /* 307 * Memory management stuff. 308 */ 309 310 /* Amount of memory pages to reserve for the system. */ 311 #define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) 312 313 /* 314 * Routines to convert VFS structures to tmpfs internal ones. 315 */ 316 317 static inline tmpfs_mount_t * 318 VFS_TO_TMPFS(struct mount *mp) 319 { 320 tmpfs_mount_t *tmp = mp->mnt_data; 321 322 KASSERT(tmp != NULL); 323 return tmp; 324 } 325 326 static inline tmpfs_node_t * 327 VP_TO_TMPFS_DIR(vnode_t *vp) 328 { 329 tmpfs_node_t *node = vp->v_data; 330 331 KASSERT(node != NULL); 332 TMPFS_VALIDATE_DIR(node); 333 return node; 334 } 335 336 #endif /* defined(_KERNEL) */ 337 338 static __inline tmpfs_node_t * 339 VP_TO_TMPFS_NODE(struct vnode *vp) 340 { 341 tmpfs_node_t *node = vp->v_data; 342 #ifdef KASSERT 343 KASSERT(node != NULL); 344 #endif 345 return node; 346 } 347 348 #endif /* _FS_TMPFS_TMPFS_H_ */ 349