Deleted Added
full compact
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 ---