tmpfs_vfsops.c (171029) | tmpfs_vfsops.c (171070) |
---|---|
1/* $NetBSD: tmpfs_vfsops.c,v 1.10 2005/12/11 12:24:29 christos Exp $ */ 2 3/* 4 * Copyright (c) 2005 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 --- 34 unchanged lines hidden (view full) --- 43 * tmpfs is a file system that uses NetBSD's virtual memory sub-system 44 * (the well-known UVM) to store file data and metadata in an efficient 45 * way. This means that it does not follow the structure of an on-disk 46 * file system because it simply does not need to. Instead, it uses 47 * memory-specific data structures and algorithms to automatically 48 * allocate and release resources. 49 */ 50#include <sys/cdefs.h> | 1/* $NetBSD: tmpfs_vfsops.c,v 1.10 2005/12/11 12:24:29 christos Exp $ */ 2 3/* 4 * Copyright (c) 2005 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 --- 34 unchanged lines hidden (view full) --- 43 * tmpfs is a file system that uses NetBSD's virtual memory sub-system 44 * (the well-known UVM) to store file data and metadata in an efficient 45 * way. This means that it does not follow the structure of an on-disk 46 * file system because it simply does not need to. Instead, it uses 47 * memory-specific data structures and algorithms to automatically 48 * allocate and release resources. 49 */ 50#include <sys/cdefs.h> |
51__FBSDID("$FreeBSD: head/sys/fs/tmpfs/tmpfs_vfsops.c 171029 2007-06-25 18:46:13Z delphij $"); | 51__FBSDID("$FreeBSD: head/sys/fs/tmpfs/tmpfs_vfsops.c 171070 2007-06-28 02:39:31Z delphij $"); |
52 53#include <sys/param.h> 54#include <sys/lock.h> 55#include <sys/mutex.h> 56#include <sys/kernel.h> 57#include <sys/stat.h> 58#include <sys/systm.h> 59#include <sys/sysctl.h> 60 61#include <vm/vm.h> 62#include <vm/vm_object.h> 63#include <vm/vm_param.h> 64 65#include <fs/tmpfs/tmpfs.h> 66 67/* | 52 53#include <sys/param.h> 54#include <sys/lock.h> 55#include <sys/mutex.h> 56#include <sys/kernel.h> 57#include <sys/stat.h> 58#include <sys/systm.h> 59#include <sys/sysctl.h> 60 61#include <vm/vm.h> 62#include <vm/vm_object.h> 63#include <vm/vm_param.h> 64 65#include <fs/tmpfs/tmpfs.h> 66 67/* |
68 * Default permission for root node | 68 * Default permission for root node |
69 */ 70#define TMPFS_DEFAULT_ROOT_MODE (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 71 72MALLOC_DEFINE(M_TMPFSMNT, "tmpfs mount", "tmpfs mount structures"); 73 74/* --------------------------------------------------------------------- */ 75 76static int tmpfs_mount(struct mount *, struct thread *); 77static int tmpfs_unmount(struct mount *, int, struct thread *); 78static int tmpfs_root(struct mount *, int flags, struct vnode **, 79 struct thread *); 80static int tmpfs_fhtovp(struct mount *, struct fid *, struct vnode **); 81static int tmpfs_statfs(struct mount *, struct statfs *, struct thread *); 82 83/* --------------------------------------------------------------------- */ 84 85static const char *tmpfs_opts[] = { | 69 */ 70#define TMPFS_DEFAULT_ROOT_MODE (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 71 72MALLOC_DEFINE(M_TMPFSMNT, "tmpfs mount", "tmpfs mount structures"); 73 74/* --------------------------------------------------------------------- */ 75 76static int tmpfs_mount(struct mount *, struct thread *); 77static int tmpfs_unmount(struct mount *, int, struct thread *); 78static int tmpfs_root(struct mount *, int flags, struct vnode **, 79 struct thread *); 80static int tmpfs_fhtovp(struct mount *, struct fid *, struct vnode **); 81static int tmpfs_statfs(struct mount *, struct statfs *, struct thread *); 82 83/* --------------------------------------------------------------------- */ 84 85static const char *tmpfs_opts[] = { |
86 "from", "size", "inodes", "uid", "gid", "mode", | 86 "from", "size", "inodes", "uid", "gid", "mode", |
87 NULL 88}; 89 90/* --------------------------------------------------------------------- */ 91 92#define SWI_MAXMIB 3 93 94static u_int --- 8 unchanged lines hidden (view full) --- 103 total = 0; 104 105 len = sizeof(dmmax); 106 if (kernel_sysctlbyname(curthread, "vm.dmmax", &dmmax, &len, 107 NULL, 0, NULL, 0) != 0) 108 return total; 109 110 len = sizeof(nswapdev); | 87 NULL 88}; 89 90/* --------------------------------------------------------------------- */ 91 92#define SWI_MAXMIB 3 93 94static u_int --- 8 unchanged lines hidden (view full) --- 103 total = 0; 104 105 len = sizeof(dmmax); 106 if (kernel_sysctlbyname(curthread, "vm.dmmax", &dmmax, &len, 107 NULL, 0, NULL, 0) != 0) 108 return total; 109 110 len = sizeof(nswapdev); |
111 if (kernel_sysctlbyname(curthread, "vm.nswapdev", | 111 if (kernel_sysctlbyname(curthread, "vm.nswapdev", |
112 &nswapdev, &len, 113 NULL, 0, NULL, 0) != 0) 114 return total; 115 116 mibi = (SWI_MAXMIB - 1) * sizeof(int); 117 oid[0] = 0; 118 oid[1] = 3; 119 | 112 &nswapdev, &len, 113 NULL, 0, NULL, 0) != 0) 114 return total; 115 116 mibi = (SWI_MAXMIB - 1) * sizeof(int); 117 oid[0] = 0; 118 oid[1] = 3; 119 |
120 if (kernel_sysctl(curthread, oid, 2, | 120 if (kernel_sysctl(curthread, oid, 2, |
121 soid, &mibi, (void *)sname, strlen(sname), 122 NULL, 0) != 0) 123 return total; 124 125 mibi = (SWI_MAXMIB - 1); 126 for (unswdev = 0; unswdev < nswapdev; ++unswdev) { 127 soid[mibi] = unswdev; 128 len = sizeof(struct xswdev); | 121 soid, &mibi, (void *)sname, strlen(sname), 122 NULL, 0) != 0) 123 return total; 124 125 mibi = (SWI_MAXMIB - 1); 126 for (unswdev = 0; unswdev < nswapdev; ++unswdev) { 127 soid[mibi] = unswdev; 128 len = sizeof(struct xswdev); |
129 if (kernel_sysctl(curthread, 130 soid, mibi + 1, &xsd, &len, NULL, 0, | 129 if (kernel_sysctl(curthread, 130 soid, mibi + 1, &xsd, &len, NULL, 0, |
131 NULL, 0) != 0) 132 return total; 133 if (len == sizeof(struct xswdev)) 134 total += (xsd.xsw_nblks - dmmax); 135 } 136 137 /* Not Reached */ 138 return total; 139} 140 141/* --------------------------------------------------------------------- */ 142static int 143tmpfs_node_ctor(void *mem, int size, void *arg, int flags) 144{ 145 struct tmpfs_node *node = (struct tmpfs_node *)mem; | 131 NULL, 0) != 0) 132 return total; 133 if (len == sizeof(struct xswdev)) 134 total += (xsd.xsw_nblks - dmmax); 135 } 136 137 /* Not Reached */ 138 return total; 139} 140 141/* --------------------------------------------------------------------- */ 142static int 143tmpfs_node_ctor(void *mem, int size, void *arg, int flags) 144{ 145 struct tmpfs_node *node = (struct tmpfs_node *)mem; |
146 | 146 |
147 if (node->tn_id == 0) { 148 /* if this node structure first time used */ 149 struct tmpfs_mount *tmp = (struct tmpfs_mount *)arg; 150 TMPFS_LOCK(tmp); 151 node->tn_id = tmp->tm_nodes_last++; 152 TMPFS_UNLOCK(tmp); | 147 if (node->tn_id == 0) { 148 /* if this node structure first time used */ 149 struct tmpfs_mount *tmp = (struct tmpfs_mount *)arg; 150 TMPFS_LOCK(tmp); 151 node->tn_id = tmp->tm_nodes_last++; 152 TMPFS_UNLOCK(tmp); |
153 node->tn_gen = arc4random(); 154 } 155 else { | 153 node->tn_gen = arc4random(); 154 } else { |
156 node->tn_gen++; 157 } | 155 node->tn_gen++; 156 } |
158 | 157 |
159 node->tn_size = 0; 160 node->tn_status = 0; 161 node->tn_flags = 0; 162 node->tn_links = 0; 163 node->tn_lockf = NULL; 164 node->tn_vnode = NULL; 165 node->tn_vpstate = 0; 166 node->tn_lookup_dirent = NULL; 167 168 return (0); 169} 170 171static void 172tmpfs_node_dtor(void *mem, int size, void *arg) 173{ 174 struct tmpfs_node *node = (struct tmpfs_node *)mem; 175 node->tn_type = VNON; 176} 177 | 158 node->tn_size = 0; 159 node->tn_status = 0; 160 node->tn_flags = 0; 161 node->tn_links = 0; 162 node->tn_lockf = NULL; 163 node->tn_vnode = NULL; 164 node->tn_vpstate = 0; 165 node->tn_lookup_dirent = NULL; 166 167 return (0); 168} 169 170static void 171tmpfs_node_dtor(void *mem, int size, void *arg) 172{ 173 struct tmpfs_node *node = (struct tmpfs_node *)mem; 174 node->tn_type = VNON; 175} 176 |
178static int | 177static int |
179tmpfs_node_init(void *mem, int size, int flags) 180{ 181 struct tmpfs_node *node = (struct tmpfs_node *)mem; 182 node->tn_id = 0; 183 184 mtx_init(&node->tn_interlock, "tmpfs node interlock", NULL, MTX_DEF); | 178tmpfs_node_init(void *mem, int size, int flags) 179{ 180 struct tmpfs_node *node = (struct tmpfs_node *)mem; 181 node->tn_id = 0; 182 183 mtx_init(&node->tn_interlock, "tmpfs node interlock", NULL, MTX_DEF); |
185 | 184 |
186 return (0); 187} 188 189static void 190tmpfs_node_fini(void *mem, int size) 191{ 192 struct tmpfs_node *node = (struct tmpfs_node *)mem; | 185 return (0); 186} 187 188static void 189tmpfs_node_fini(void *mem, int size) 190{ 191 struct tmpfs_node *node = (struct tmpfs_node *)mem; |
193 | 192 |
194 mtx_destroy(&node->tn_interlock); 195} 196 197static int 198tmpfs_mount(struct mount *mp, struct thread *l) 199{ 200 struct tmpfs_args args; 201 struct tmpfs_mount *tmp; --- 16 unchanged lines hidden (view full) --- 218 args.ta_root_gid = 0; 219 if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &args.ta_root_uid) != 1) 220 args.ta_root_uid = 0; 221 if (vfs_scanopt(mp->mnt_optnew, "mode", "%o", &args.ta_root_mode) != 1) 222 args.ta_root_mode = TMPFS_DEFAULT_ROOT_MODE; 223 if(vfs_scanopt(mp->mnt_optnew, "inodes", "%d", &args.ta_nodes_max) != 1) 224 args.ta_nodes_max = 0; 225 | 193 mtx_destroy(&node->tn_interlock); 194} 195 196static int 197tmpfs_mount(struct mount *mp, struct thread *l) 198{ 199 struct tmpfs_args args; 200 struct tmpfs_mount *tmp; --- 16 unchanged lines hidden (view full) --- 217 args.ta_root_gid = 0; 218 if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &args.ta_root_uid) != 1) 219 args.ta_root_uid = 0; 220 if (vfs_scanopt(mp->mnt_optnew, "mode", "%o", &args.ta_root_mode) != 1) 221 args.ta_root_mode = TMPFS_DEFAULT_ROOT_MODE; 222 if(vfs_scanopt(mp->mnt_optnew, "inodes", "%d", &args.ta_nodes_max) != 1) 223 args.ta_nodes_max = 0; 224 |
226 if(vfs_scanopt(mp->mnt_optnew, 227 "size", | 225 if(vfs_scanopt(mp->mnt_optnew, 226 "size", |
228 "%qu", &args.ta_size_max) != 1) 229 args.ta_size_max = 0; 230 231 /* Do not allow mounts if we do not have enough memory to preserve 232 * the minimum reserved pages. */ 233 mem_size = cnt.v_free_count + cnt.v_inactive_count + get_swpgtotal(); 234 mem_size -= mem_size > cnt.v_wire_count ? cnt.v_wire_count : mem_size; 235 if (mem_size < TMPFS_PAGES_RESERVED) --- 14 unchanged lines hidden (view full) --- 250 nodes = 3 + pages * PAGE_SIZE / 1024; 251 else 252 nodes = args.ta_nodes_max; 253 MPASS(nodes >= 3); 254 255 /* Allocate the tmpfs mount structure and fill it. */ 256 tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount), 257 M_TMPFSMNT, M_WAITOK | M_ZERO); | 227 "%qu", &args.ta_size_max) != 1) 228 args.ta_size_max = 0; 229 230 /* Do not allow mounts if we do not have enough memory to preserve 231 * the minimum reserved pages. */ 232 mem_size = cnt.v_free_count + cnt.v_inactive_count + get_swpgtotal(); 233 mem_size -= mem_size > cnt.v_wire_count ? cnt.v_wire_count : mem_size; 234 if (mem_size < TMPFS_PAGES_RESERVED) --- 14 unchanged lines hidden (view full) --- 249 nodes = 3 + pages * PAGE_SIZE / 1024; 250 else 251 nodes = args.ta_nodes_max; 252 MPASS(nodes >= 3); 253 254 /* Allocate the tmpfs mount structure and fill it. */ 255 tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount), 256 M_TMPFSMNT, M_WAITOK | M_ZERO); |
258 | 257 |
259 mtx_init(&tmp->allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF); 260 tmp->tm_nodes_max = nodes; 261 tmp->tm_nodes_last = 2; 262 tmp->tm_nodes_inuse = 0; 263 tmp->tm_maxfilesize = get_swpgtotal() * PAGE_SIZE; 264 LIST_INIT(&tmp->tm_nodes_used); | 258 mtx_init(&tmp->allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF); 259 tmp->tm_nodes_max = nodes; 260 tmp->tm_nodes_last = 2; 261 tmp->tm_nodes_inuse = 0; 262 tmp->tm_maxfilesize = get_swpgtotal() * PAGE_SIZE; 263 LIST_INIT(&tmp->tm_nodes_used); |
265 | 264 |
266 tmp->tm_pages_max = pages; 267 tmp->tm_pages_used = 0; 268 tmp->tm_dirent_pool = uma_zcreate( 269 "TMPFS dirent", 270 sizeof(struct tmpfs_dirent), 271 NULL, NULL, NULL, NULL, 272 UMA_ALIGN_PTR, | 265 tmp->tm_pages_max = pages; 266 tmp->tm_pages_used = 0; 267 tmp->tm_dirent_pool = uma_zcreate( 268 "TMPFS dirent", 269 sizeof(struct tmpfs_dirent), 270 NULL, NULL, NULL, NULL, 271 UMA_ALIGN_PTR, |
273 0); | 272 0); |
274 tmp->tm_node_pool = uma_zcreate( 275 "TMPFS node", 276 sizeof(struct tmpfs_node), 277 tmpfs_node_ctor, tmpfs_node_dtor, 278 tmpfs_node_init, tmpfs_node_fini, 279 UMA_ALIGN_PTR, 280 0); 281 tmpfs_str_zone_create(&tmp->tm_str_pool); --- 11 unchanged lines hidden (view full) --- 293 return error; 294 } 295 tmp->tm_root = root; 296 297 MNT_ILOCK(mp); 298 mp->mnt_flag |= MNT_LOCAL; 299 mp->mnt_kern_flag |= MNTK_MPSAFE; 300 MNT_IUNLOCK(mp); | 273 tmp->tm_node_pool = uma_zcreate( 274 "TMPFS node", 275 sizeof(struct tmpfs_node), 276 tmpfs_node_ctor, tmpfs_node_dtor, 277 tmpfs_node_init, tmpfs_node_fini, 278 UMA_ALIGN_PTR, 279 0); 280 tmpfs_str_zone_create(&tmp->tm_str_pool); --- 11 unchanged lines hidden (view full) --- 292 return error; 293 } 294 tmp->tm_root = root; 295 296 MNT_ILOCK(mp); 297 mp->mnt_flag |= MNT_LOCAL; 298 mp->mnt_kern_flag |= MNTK_MPSAFE; 299 MNT_IUNLOCK(mp); |
301 | 300 |
302 mp->mnt_data = tmp; 303 mp->mnt_stat.f_namemax = MAXNAMLEN; 304 vfs_getnewfsid(mp); 305 vfs_mountedfrom(mp, "tmpfs"); 306 307 return 0; 308} 309 --- 13 unchanged lines hidden (view full) --- 323 flags |= FORCECLOSE; 324 325 /* Finalize all pending I/O. */ 326 error = vflush(mp, 0, flags, l); 327 if (error != 0) 328 return error; 329 330 tmp = VFS_TO_TMPFS(mp); | 301 mp->mnt_data = tmp; 302 mp->mnt_stat.f_namemax = MAXNAMLEN; 303 vfs_getnewfsid(mp); 304 vfs_mountedfrom(mp, "tmpfs"); 305 306 return 0; 307} 308 --- 13 unchanged lines hidden (view full) --- 322 flags |= FORCECLOSE; 323 324 /* Finalize all pending I/O. */ 325 error = vflush(mp, 0, flags, l); 326 if (error != 0) 327 return error; 328 329 tmp = VFS_TO_TMPFS(mp); |
331 | 330 |
332 /* Free all associated data. The loop iterates over the linked list 333 * we have containing all used nodes. For each of them that is 334 * a directory, we free all its directory entries. Note that after 335 * freeing a node, it will automatically go to the available list, 336 * so we will later have to iterate over it to release its items. */ 337 node = LIST_FIRST(&tmp->tm_nodes_used); 338 while (node != NULL) { 339 struct tmpfs_node *next; --- 22 unchanged lines hidden (view full) --- 362 tmpfs_str_zone_destroy(&tmp->tm_str_pool); 363 364 mtx_destroy(&tmp->allnode_lock); 365 MPASS(tmp->tm_pages_used == 0); 366 367 /* Throw away the tmpfs_mount structure. */ 368 free(mp->mnt_data, M_TMPFSMNT); 369 mp->mnt_data = NULL; | 331 /* Free all associated data. The loop iterates over the linked list 332 * we have containing all used nodes. For each of them that is 333 * a directory, we free all its directory entries. Note that after 334 * freeing a node, it will automatically go to the available list, 335 * so we will later have to iterate over it to release its items. */ 336 node = LIST_FIRST(&tmp->tm_nodes_used); 337 while (node != NULL) { 338 struct tmpfs_node *next; --- 22 unchanged lines hidden (view full) --- 361 tmpfs_str_zone_destroy(&tmp->tm_str_pool); 362 363 mtx_destroy(&tmp->allnode_lock); 364 MPASS(tmp->tm_pages_used == 0); 365 366 /* Throw away the tmpfs_mount structure. */ 367 free(mp->mnt_data, M_TMPFSMNT); 368 mp->mnt_data = NULL; |
370 | 369 |
371 MNT_ILOCK(mp); 372 mp->mnt_flag &= ~MNT_LOCAL; 373 MNT_IUNLOCK(mp); 374 return 0; 375} 376 377/* --------------------------------------------------------------------- */ 378 --- 49 unchanged lines hidden (view full) --- 428static int 429tmpfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *l) 430{ 431 fsfilcnt_t freenodes; 432 struct tmpfs_mount *tmp; 433 434 tmp = VFS_TO_TMPFS(mp); 435 | 370 MNT_ILOCK(mp); 371 mp->mnt_flag &= ~MNT_LOCAL; 372 MNT_IUNLOCK(mp); 373 return 0; 374} 375 376/* --------------------------------------------------------------------- */ 377 --- 49 unchanged lines hidden (view full) --- 427static int 428tmpfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *l) 429{ 430 fsfilcnt_t freenodes; 431 struct tmpfs_mount *tmp; 432 433 tmp = VFS_TO_TMPFS(mp); 434 |
436 sbp->f_iosize = PAGE_SIZE; | 435 sbp->f_iosize = PAGE_SIZE; |
437 sbp->f_bsize = PAGE_SIZE; 438 439 sbp->f_blocks = TMPFS_PAGES_MAX(tmp); 440 sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp); 441 442 freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_inuse, 443 TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node)); 444 --- 21 unchanged lines hidden --- | 436 sbp->f_bsize = PAGE_SIZE; 437 438 sbp->f_blocks = TMPFS_PAGES_MAX(tmp); 439 sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp); 440 441 freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_inuse, 442 TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node)); 443 --- 21 unchanged lines hidden --- |