1 /* $NetBSD: tmpfs.h,v 1.36 2008/07/28 18:00:20 pooka 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/queue.h> 39 #include <sys/vnode.h> 40 41 #include <fs/tmpfs/tmpfs_pool.h> 42 #include <fs/tmpfs/tmpfs_args.h> 43 44 /* --------------------------------------------------------------------- */ 45 46 /* Each entry in a directory has a cookie that identifies it. Cookies 47 * supersede offsets within directories because, given how tmpfs stores 48 * directories in memory, there is no such thing as an offset. (Emulating 49 * a real offset could be very difficult.) 50 * 51 * The '.', '..' and the end of directory markers have fixed cookies which 52 * cannot collide with the cookies generated by other entries. The cookies 53 * fot the other entries are generated based on the memory address on which 54 * stores their information is stored. 55 * 56 * Ideally, using the entry's memory pointer as the cookie would be enough 57 * to represent it and it wouldn't cause collisions in any system. 58 * Unfortunately, this results in "offsets" with very large values which 59 * later raise problems in the Linux compatibility layer (and maybe in other 60 * places) as described in PR kern/32034. Hence we need to workaround this 61 * with a rather ugly hack. 62 * 63 * Linux 32-bit binaries, unless built with _FILE_OFFSET_BITS=64, have off_t 64 * set to 'long', which is a 32-bit *signed* long integer. Regardless of 65 * the macro value, GLIBC (2.3 at least) always uses the getdents64 66 * system call (when calling readdir) which internally returns off64_t 67 * offsets. In order to make 32-bit binaries work, *GLIBC* converts the 68 * 64-bit values returned by the kernel to 32-bit ones and aborts with 69 * EOVERFLOW if the conversion results in values that won't fit in 32-bit 70 * integers (which it assumes is because the directory is extremely large). 71 * This wouldn't cause problems if we were dealing with unsigned integers, 72 * but as we have signed integers, this check fails due to sign expansion. 73 * 74 * For example, consider that the kernel returns the 0xc1234567 cookie to 75 * userspace in a off64_t integer. Later on, GLIBC casts this value to 76 * off_t (remember, signed) with code similar to: 77 * system call returns the offset in kernel_value; 78 * off_t casted_value = kernel_value; 79 * if (sizeof(off_t) != sizeof(off64_t) && 80 * kernel_value != casted_value) 81 * error! 82 * In this case, casted_value still has 0xc1234567, but when it is compared 83 * for equality against kernel_value, it is promoted to a 64-bit integer and 84 * becomes 0xffffffffc1234567, which is different than 0x00000000c1234567. 85 * Then, GLIBC assumes this is because the directory is very large. 86 * 87 * Given that all the above happens in user-space, we have no control over 88 * it; therefore we must workaround the issue here. We do this by 89 * truncating the pointer value to a 32-bit integer and hope that there 90 * won't be collisions. In fact, this will not cause any problems in 91 * 32-bit platforms but some might arise in 64-bit machines (I'm not sure 92 * if they can happen at all in practice). 93 * 94 * XXX A nicer solution shall be attempted. */ 95 #define TMPFS_DIRCOOKIE_DOT 0 96 #define TMPFS_DIRCOOKIE_DOTDOT 1 97 #define TMPFS_DIRCOOKIE_EOF 2 98 static __inline 99 off_t 100 tmpfs_dircookie(struct tmpfs_dirent *de) 101 { 102 off_t cookie; 103 104 cookie = ((off_t)(uintptr_t)de >> 1) & 0x7FFFFFFF; 105 KASSERT(cookie != TMPFS_DIRCOOKIE_DOT); 106 KASSERT(cookie != TMPFS_DIRCOOKIE_DOTDOT); 107 KASSERT(cookie != TMPFS_DIRCOOKIE_EOF); 108 109 return cookie; 110 } 111 112 /* --------------------------------------------------------------------- */ 113 114 LIST_HEAD(tmpfs_node_list, tmpfs_node); 115 116 /* --------------------------------------------------------------------- */ 117 118 /* 119 * Internal representation of a tmpfs mount point. 120 */ 121 struct tmpfs_mount { 122 /* Maximum number of memory pages available for use by the file 123 * system, set during mount time. This variable must never be 124 * used directly as it may be bigger than the current amount of 125 * free memory; in the extreme case, it will hold the SIZE_MAX 126 * value. Instead, use the TMPFS_PAGES_MAX macro. */ 127 unsigned int tm_pages_max; 128 129 /* Number of pages in use by the file system. Cannot be bigger 130 * than the value returned by TMPFS_PAGES_MAX in any case. */ 131 unsigned int tm_pages_used; 132 133 /* Pointer to the node representing the root directory of this 134 * file system. */ 135 struct tmpfs_node * tm_root; 136 137 /* Maximum number of possible nodes for this file system; set 138 * during mount time. We need a hard limit on the maximum number 139 * of nodes to avoid allocating too much of them; their objects 140 * cannot be released until the file system is unmounted. 141 * Otherwise, we could easily run out of memory by creating lots 142 * of empty files and then simply removing them. */ 143 unsigned int tm_nodes_max; 144 145 /* Number of nodes currently allocated. This number only grows. 146 * When it reaches tm_nodes_max, no more new nodes can be allocated. 147 * Of course, the old, unused ones can be reused. */ 148 unsigned int tm_nodes_cnt; 149 150 /* Node list. */ 151 kmutex_t tm_lock; 152 struct tmpfs_node_list tm_nodes; 153 154 /* Pools used to store file system meta data. These are not shared 155 * across several instances of tmpfs for the reasons described in 156 * tmpfs_pool.c. */ 157 struct tmpfs_pool tm_dirent_pool; 158 struct tmpfs_pool tm_node_pool; 159 struct tmpfs_str_pool tm_str_pool; 160 }; 161 162 /* --------------------------------------------------------------------- */ 163 164 /* 165 * This structure maps a file identifier to a tmpfs node. Used by the 166 * NFS code. 167 */ 168 struct tmpfs_fid { 169 uint16_t tf_len; 170 uint16_t tf_pad; 171 uint32_t tf_gen; 172 ino_t tf_id; 173 }; 174 175 /* --------------------------------------------------------------------- */ 176 177 /* 178 * Prototypes for tmpfs_subr.c. 179 */ 180 181 int tmpfs_alloc_node(struct tmpfs_mount *, enum vtype, 182 uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *, 183 char *, dev_t, struct tmpfs_node **); 184 void tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *); 185 int tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *, 186 const char *, uint16_t, struct tmpfs_dirent **); 187 void tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *, 188 bool); 189 int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, struct vnode **); 190 void tmpfs_free_vp(struct vnode *); 191 int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *, 192 struct componentname *, char *); 193 void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *); 194 void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *); 195 struct tmpfs_dirent * tmpfs_dir_lookup(struct tmpfs_node *node, 196 struct componentname *cnp); 197 int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *); 198 int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *); 199 struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t); 200 int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *); 201 int tmpfs_reg_resize(struct vnode *, off_t); 202 size_t tmpfs_mem_info(bool); 203 int tmpfs_chflags(struct vnode *, int, kauth_cred_t, struct lwp *); 204 int tmpfs_chmod(struct vnode *, mode_t, kauth_cred_t, struct lwp *); 205 int tmpfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t, struct lwp *); 206 int tmpfs_chsize(struct vnode *, u_quad_t, kauth_cred_t, struct lwp *); 207 int tmpfs_chtimes(struct vnode *, const struct timespec *, 208 const struct timespec *, const struct timespec *, int, kauth_cred_t, 209 struct lwp *); 210 void tmpfs_itimes(struct vnode *, const struct timespec *, 211 const struct timespec *, const struct timespec *); 212 213 void tmpfs_update(struct vnode *, const struct timespec *, 214 const struct timespec *, const struct timespec *, int); 215 int tmpfs_truncate(struct vnode *, off_t); 216 217 /* --------------------------------------------------------------------- */ 218 219 /* 220 * Convenience macros to simplify some logical expressions. 221 */ 222 #define IMPLIES(a, b) (!(a) || (b)) 223 #define IFF(a, b) (IMPLIES(a, b) && IMPLIES(b, a)) 224 225 /* --------------------------------------------------------------------- */ 226 227 /* 228 * Checks that the directory entry pointed by 'de' matches the name 'name' 229 * with a length of 'len'. 230 */ 231 #define TMPFS_DIRENT_MATCHES(de, name, len) \ 232 (de->td_namelen == (uint16_t)len && \ 233 memcmp((de)->td_name, (name), (de)->td_namelen) == 0) 234 235 /* --------------------------------------------------------------------- */ 236 237 /* 238 * Ensures that the node pointed by 'node' is a directory and that its 239 * contents are consistent with respect to directories. 240 */ 241 #define TMPFS_VALIDATE_DIR(node) \ 242 KASSERT((node)->tn_type == VDIR); \ 243 KASSERT((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \ 244 KASSERT((node)->tn_spec.tn_dir.tn_readdir_lastp == NULL || \ 245 tmpfs_dircookie((node)->tn_spec.tn_dir.tn_readdir_lastp) == \ 246 (node)->tn_spec.tn_dir.tn_readdir_lastn); 247 248 /* --------------------------------------------------------------------- */ 249 250 /* 251 * Memory management stuff. 252 */ 253 254 /* Amount of memory pages to reserve for the system (e.g., to not use by 255 * tmpfs). 256 * XXX: Should this be tunable through sysctl, for instance? */ 257 #define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) 258 259 /* Returns the maximum size allowed for a tmpfs file system. This macro 260 * must be used instead of directly retrieving the value from tm_pages_max. 261 * The reason is that the size of a tmpfs file system is dynamic: it lets 262 * the user store files as long as there is enough free memory (including 263 * physical memory and swap space). Therefore, the amount of memory to be 264 * used is either the limit imposed by the user during mount time or the 265 * amount of available memory, whichever is lower. To avoid consuming all 266 * the memory for a given mount point, the system will always reserve a 267 * minimum of TMPFS_PAGES_RESERVED pages, which is also taken into account 268 * by this macro (see above). */ 269 static __inline size_t 270 TMPFS_PAGES_MAX(struct tmpfs_mount *tmp) 271 { 272 size_t freepages; 273 274 freepages = tmpfs_mem_info(false); 275 if (freepages < TMPFS_PAGES_RESERVED) 276 freepages = 0; 277 else 278 freepages -= TMPFS_PAGES_RESERVED; 279 280 return MIN(tmp->tm_pages_max, freepages + tmp->tm_pages_used); 281 } 282 283 /* Returns the available space for the given file system. */ 284 #define TMPFS_PAGES_AVAIL(tmp) \ 285 ((ssize_t)(TMPFS_PAGES_MAX(tmp) - (tmp)->tm_pages_used)) 286 287 /* --------------------------------------------------------------------- */ 288 289 /* 290 * Macros/functions to convert from generic data structures to tmpfs 291 * specific ones. 292 */ 293 294 static __inline 295 struct tmpfs_mount * 296 VFS_TO_TMPFS(struct mount *mp) 297 { 298 struct tmpfs_mount *tmp; 299 300 #ifdef KASSERT 301 KASSERT((mp) != NULL && (mp)->mnt_data != NULL); 302 #endif 303 tmp = (struct tmpfs_mount *)(mp)->mnt_data; 304 return tmp; 305 } 306 307 static __inline 308 struct tmpfs_node * 309 VP_TO_TMPFS_DIR(struct vnode *vp) 310 { 311 struct tmpfs_node *node; 312 313 node = VP_TO_TMPFS_NODE(vp); 314 #ifdef KASSERT 315 TMPFS_VALIDATE_DIR(node); 316 #endif 317 return node; 318 } 319 #endif /* _FS_TMPFS_TMPFS_H_ */ 320