Annotation of src/sys/fs/tmpfs/tmpfs_vfsops.c, Revision 1.33
1.33 ! pooka 1: /* $NetBSD: tmpfs_vfsops.c,v 1.32 2007/11/26 19:01:55 pooka Exp $ */
1.1 jmmv 2:
3: /*
1.31 ad 4: * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
1.1 jmmv 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
1.6 jmmv 8: * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9: * 2005 program.
1.1 jmmv 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: /*
1.2 jmmv 41: * Efficient memory file system.
1.6 jmmv 42: *
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.
1.1 jmmv 49: */
50:
51: #include <sys/cdefs.h>
1.33 ! pooka 52: __KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.32 2007/11/26 19:01:55 pooka Exp $");
1.1 jmmv 53:
54: #include <sys/param.h>
55: #include <sys/types.h>
1.31 ad 56: #include <sys/malloc.h>
1.1 jmmv 57: #include <sys/mount.h>
1.8 jmmv 58: #include <sys/stat.h>
1.1 jmmv 59: #include <sys/systm.h>
60: #include <sys/vnode.h>
1.22 ad 61: #include <sys/proc.h>
1.1 jmmv 62:
63: #include <fs/tmpfs/tmpfs.h>
64:
1.31 ad 65: MALLOC_JUSTDEFINE(M_TMPFSMNT, "tmpfs mount", "tmpfs mount structures");
66: MALLOC_JUSTDEFINE(M_TMPFSTMP, "tmpfs temp", "tmpfs temporary structures");
67:
1.1 jmmv 68: /* --------------------------------------------------------------------- */
69:
1.32 pooka 70: static int tmpfs_mount(struct mount *, const char *, void *, size_t *);
71: static int tmpfs_start(struct mount *, int);
72: static int tmpfs_unmount(struct mount *, int);
1.1 jmmv 73: static int tmpfs_root(struct mount *, struct vnode **);
74: static int tmpfs_vget(struct mount *, ino_t, struct vnode **);
75: static int tmpfs_fhtovp(struct mount *, struct fid *, struct vnode **);
1.13 martin 76: static int tmpfs_vptofh(struct vnode *, struct fid *, size_t *);
1.32 pooka 77: static int tmpfs_statvfs(struct mount *, struct statvfs *);
78: static int tmpfs_sync(struct mount *, int, kauth_cred_t);
1.1 jmmv 79: static void tmpfs_init(void);
80: static void tmpfs_done(void);
81: static int tmpfs_snapshot(struct mount *, struct vnode *,
82: struct timespec *);
83:
84: /* --------------------------------------------------------------------- */
85:
86: static int
1.32 pooka 87: tmpfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
1.1 jmmv 88: {
1.32 pooka 89: struct lwp *l = curlwp;
1.1 jmmv 90: int error;
91: ino_t nodes;
92: size_t pages;
93: struct tmpfs_mount *tmp;
94: struct tmpfs_node *root;
1.23 dsl 95: struct tmpfs_args *args = data;
96:
97: if (*data_len < sizeof *args)
98: return EINVAL;
1.1 jmmv 99:
100: /* Handle retrieval of mount point arguments. */
101: if (mp->mnt_flag & MNT_GETARGS) {
102: if (mp->mnt_data == NULL)
103: return EIO;
104: tmp = VFS_TO_TMPFS(mp);
105:
1.23 dsl 106: args->ta_version = TMPFS_ARGS_VERSION;
107: args->ta_nodes_max = tmp->tm_nodes_max;
108: args->ta_size_max = tmp->tm_pages_max * PAGE_SIZE;
1.31 ad 109:
1.30 ad 110: root = tmp->tm_root;
1.23 dsl 111: args->ta_root_uid = root->tn_uid;
112: args->ta_root_gid = root->tn_gid;
113: args->ta_root_mode = root->tn_mode;
1.1 jmmv 114:
1.23 dsl 115: *data_len = sizeof *args;
116: return 0;
1.1 jmmv 117: }
118:
119: if (mp->mnt_flag & MNT_UPDATE) {
1.2 jmmv 120: /* XXX: There is no support yet to update file system
1.1 jmmv 121: * settings. Should be added. */
122:
123: return EOPNOTSUPP;
124: }
125:
1.23 dsl 126: if (args->ta_version != TMPFS_ARGS_VERSION)
1.1 jmmv 127: return EINVAL;
128:
129: /* Do not allow mounts if we do not have enough memory to preserve
130: * the minimum reserved pages. */
1.20 thorpej 131: if (tmpfs_mem_info(true) < TMPFS_PAGES_RESERVED)
1.1 jmmv 132: return EINVAL;
133:
1.2 jmmv 134: /* Get the maximum number of memory pages this file system is
1.1 jmmv 135: * allowed to use, based on the maximum size the user passed in
136: * the mount structure. A value of zero is treated as if the
137: * maximum available space was requested. */
1.23 dsl 138: if (args->ta_size_max < PAGE_SIZE || args->ta_size_max >= SIZE_MAX)
1.1 jmmv 139: pages = SIZE_MAX;
140: else
1.23 dsl 141: pages = args->ta_size_max / PAGE_SIZE +
142: (args->ta_size_max % PAGE_SIZE == 0 ? 0 : 1);
1.7 jmmv 143: KASSERT(pages > 0);
1.1 jmmv 144:
1.23 dsl 145: if (args->ta_nodes_max <= 3)
1.7 jmmv 146: nodes = 3 + pages * PAGE_SIZE / 1024;
1.1 jmmv 147: else
1.23 dsl 148: nodes = args->ta_nodes_max;
1.7 jmmv 149: KASSERT(nodes >= 3);
1.1 jmmv 150:
151: /* Allocate the tmpfs mount structure and fill it. */
1.31 ad 152: tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount),
153: M_TMPFSMNT, M_WAITOK);
154: KASSERT(tmp != NULL);
1.1 jmmv 155:
156: tmp->tm_nodes_max = nodes;
1.31 ad 157: tmp->tm_nodes_last = 2;
158: LIST_INIT(&tmp->tm_nodes_used);
159: LIST_INIT(&tmp->tm_nodes_avail);
1.1 jmmv 160:
161: tmp->tm_pages_max = pages;
162: tmp->tm_pages_used = 0;
163: tmpfs_pool_init(&tmp->tm_dirent_pool, sizeof(struct tmpfs_dirent),
164: "dirent", tmp);
165: tmpfs_pool_init(&tmp->tm_node_pool, sizeof(struct tmpfs_node),
166: "node", tmp);
167: tmpfs_str_pool_init(&tmp->tm_str_pool, tmp);
168:
169: /* Allocate the root node. */
1.23 dsl 170: error = tmpfs_alloc_node(tmp, VDIR, args->ta_root_uid,
171: args->ta_root_gid, args->ta_root_mode & ALLPERMS, NULL, NULL,
1.33 ! pooka 172: VNOVAL, &root);
1.1 jmmv 173: KASSERT(error == 0 && root != NULL);
174: tmp->tm_root = root;
175:
176: mp->mnt_data = tmp;
177: mp->mnt_flag |= MNT_LOCAL;
178: mp->mnt_stat.f_namemax = MAXNAMLEN;
1.27 pooka 179: mp->mnt_fs_bshift = PAGE_SHIFT;
180: mp->mnt_dev_bshift = DEV_BSHIFT;
1.1 jmmv 181: vfs_getnewfsid(mp);
182:
183: return set_statvfs_info(path, UIO_USERSPACE, "tmpfs", UIO_SYSSPACE,
1.24 pooka 184: mp->mnt_op->vfs_name, mp, l);
1.1 jmmv 185: }
186:
187: /* --------------------------------------------------------------------- */
188:
189: static int
1.32 pooka 190: tmpfs_start(struct mount *mp, int flags)
1.1 jmmv 191: {
192:
193: return 0;
194: }
195:
196: /* --------------------------------------------------------------------- */
197:
198: /* ARGSUSED2 */
199: static int
1.32 pooka 200: tmpfs_unmount(struct mount *mp, int mntflags)
1.1 jmmv 201: {
202: int error;
203: int flags = 0;
204: struct tmpfs_mount *tmp;
205: struct tmpfs_node *node;
206:
207: /* Handle forced unmounts. */
208: if (mntflags & MNT_FORCE)
209: flags |= FORCECLOSE;
210:
211: /* Finalize all pending I/O. */
212: error = vflush(mp, NULL, flags);
213: if (error != 0)
214: return error;
215:
216: tmp = VFS_TO_TMPFS(mp);
217:
218: /* Free all associated data. The loop iterates over the linked list
219: * we have containing all used nodes. For each of them that is
220: * a directory, we free all its directory entries. Note that after
221: * freeing a node, it will automatically go to the available list,
222: * so we will later have to iterate over it to release its items. */
1.31 ad 223: node = LIST_FIRST(&tmp->tm_nodes_used);
224: while (node != NULL) {
225: struct tmpfs_node *next;
226:
1.1 jmmv 227: if (node->tn_type == VDIR) {
228: struct tmpfs_dirent *de;
229:
1.11 jmmv 230: de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir);
1.1 jmmv 231: while (de != NULL) {
232: struct tmpfs_dirent *nde;
233:
234: nde = TAILQ_NEXT(de, td_entries);
1.16 jmmv 235: KASSERT(de->td_node->tn_vnode == NULL);
1.20 thorpej 236: tmpfs_free_dirent(tmp, de, false);
1.1 jmmv 237: de = nde;
238: node->tn_size -= sizeof(struct tmpfs_dirent);
239: }
240: }
241:
1.31 ad 242: next = LIST_NEXT(node, tn_entries);
1.1 jmmv 243: tmpfs_free_node(tmp, node);
1.31 ad 244: node = next;
245: }
246: node = LIST_FIRST(&tmp->tm_nodes_avail);
247: while (node != NULL) {
248: struct tmpfs_node *next;
249:
250: next = LIST_NEXT(node, tn_entries);
251: LIST_REMOVE(node, tn_entries);
252: TMPFS_POOL_PUT(&tmp->tm_node_pool, node);
253: node = next;
1.1 jmmv 254: }
255:
256: tmpfs_pool_destroy(&tmp->tm_dirent_pool);
257: tmpfs_pool_destroy(&tmp->tm_node_pool);
258: tmpfs_str_pool_destroy(&tmp->tm_str_pool);
259:
260: KASSERT(tmp->tm_pages_used == 0);
261:
262: /* Throw away the tmpfs_mount structure. */
1.31 ad 263: free(mp->mnt_data, M_TMPFSMNT);
1.1 jmmv 264: mp->mnt_data = NULL;
265:
266: return 0;
267: }
268:
269: /* --------------------------------------------------------------------- */
270:
271: static int
272: tmpfs_root(struct mount *mp, struct vnode **vpp)
273: {
274:
275: return tmpfs_alloc_vp(mp, VFS_TO_TMPFS(mp)->tm_root, vpp);
276: }
277:
278: /* --------------------------------------------------------------------- */
279:
280: static int
1.17 christos 281: tmpfs_vget(struct mount *mp, ino_t ino,
282: struct vnode **vpp)
1.1 jmmv 283: {
284:
285: printf("tmpfs_vget called; need for it unknown yet\n");
286: return EOPNOTSUPP;
287: }
288:
289: /* --------------------------------------------------------------------- */
290:
291: static int
292: tmpfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
293: {
1.19 thorpej 294: bool found;
1.13 martin 295: struct tmpfs_fid tfh;
1.1 jmmv 296: struct tmpfs_mount *tmp;
297: struct tmpfs_node *node;
298:
299: tmp = VFS_TO_TMPFS(mp);
300:
1.13 martin 301: if (fhp->fid_len != sizeof(struct tmpfs_fid))
1.1 jmmv 302: return EINVAL;
303:
1.13 martin 304: memcpy(&tfh, fhp, sizeof(struct tmpfs_fid));
305:
1.31 ad 306: if (tfh.tf_id >= tmp->tm_nodes_max)
1.1 jmmv 307: return EINVAL;
308:
1.20 thorpej 309: found = false;
1.31 ad 310: LIST_FOREACH(node, &tmp->tm_nodes_used, tn_entries) {
1.13 martin 311: if (node->tn_id == tfh.tf_id &&
312: node->tn_gen == tfh.tf_gen) {
1.20 thorpej 313: found = true;
1.1 jmmv 314: break;
315: }
316: }
317:
318: return found ? tmpfs_alloc_vp(mp, node, vpp) : EINVAL;
319: }
320:
321: /* --------------------------------------------------------------------- */
322:
323: static int
1.13 martin 324: tmpfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1 jmmv 325: {
1.13 martin 326: struct tmpfs_fid tfh;
1.1 jmmv 327: struct tmpfs_node *node;
328:
1.13 martin 329: if (*fh_size < sizeof(struct tmpfs_fid)) {
330: *fh_size = sizeof(struct tmpfs_fid);
331: return E2BIG;
332: }
333: *fh_size = sizeof(struct tmpfs_fid);
1.1 jmmv 334: node = VP_TO_TMPFS_NODE(vp);
335:
1.13 martin 336: memset(&tfh, 0, sizeof(tfh));
337: tfh.tf_len = sizeof(struct tmpfs_fid);
338: tfh.tf_gen = node->tn_gen;
339: tfh.tf_id = node->tn_id;
340: memcpy(fhp, &tfh, sizeof(tfh));
1.1 jmmv 341:
342: return 0;
343: }
344:
345: /* --------------------------------------------------------------------- */
346:
347: /* ARGSUSED2 */
348: static int
1.32 pooka 349: tmpfs_statvfs(struct mount *mp, struct statvfs *sbp)
1.1 jmmv 350: {
1.31 ad 351: fsfilcnt_t freenodes, usednodes;
1.1 jmmv 352: struct tmpfs_mount *tmp;
1.31 ad 353: struct tmpfs_node *dummy;
1.1 jmmv 354:
355: tmp = VFS_TO_TMPFS(mp);
356:
357: sbp->f_iosize = sbp->f_frsize = sbp->f_bsize = PAGE_SIZE;
358:
359: sbp->f_blocks = TMPFS_PAGES_MAX(tmp);
360: sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp);
361: sbp->f_bresvd = 0;
362:
1.31 ad 363: freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_last,
1.1 jmmv 364: TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
1.31 ad 365: LIST_FOREACH(dummy, &tmp->tm_nodes_avail, tn_entries)
366: freenodes++;
1.1 jmmv 367:
1.31 ad 368: usednodes = 0;
369: LIST_FOREACH(dummy, &tmp->tm_nodes_used, tn_entries)
370: usednodes++;
371:
372: sbp->f_files = freenodes + usednodes;
1.1 jmmv 373: sbp->f_favail = sbp->f_ffree = freenodes;
374: sbp->f_fresvd = 0;
375:
376: copy_statvfs_info(sbp, mp);
377:
378: return 0;
379: }
380:
381: /* --------------------------------------------------------------------- */
382:
383: /* ARGSUSED0 */
384: static int
1.17 christos 385: tmpfs_sync(struct mount *mp, int waitfor,
1.32 pooka 386: kauth_cred_t uc)
1.1 jmmv 387: {
388:
389: return 0;
390: }
391:
392: /* --------------------------------------------------------------------- */
393:
394: static void
395: tmpfs_init(void)
396: {
397:
1.31 ad 398: malloc_type_attach(M_TMPFSMNT);
399: malloc_type_attach(M_TMPFSTMP);
1.1 jmmv 400: }
401:
402: /* --------------------------------------------------------------------- */
403:
404: static void
405: tmpfs_done(void)
406: {
407:
1.31 ad 408: malloc_type_detach(M_TMPFSTMP);
409: malloc_type_detach(M_TMPFSMNT);
1.1 jmmv 410: }
411:
412: /* --------------------------------------------------------------------- */
413:
414: static int
1.17 christos 415: tmpfs_snapshot(struct mount *mp, struct vnode *vp,
416: struct timespec *ctime)
1.1 jmmv 417: {
418:
419: return EOPNOTSUPP;
420: }
421:
422: /* --------------------------------------------------------------------- */
423:
424: /*
425: * tmpfs vfs operations.
426: */
427:
428: extern const struct vnodeopv_desc tmpfs_fifoop_opv_desc;
429: extern const struct vnodeopv_desc tmpfs_specop_opv_desc;
430: extern const struct vnodeopv_desc tmpfs_vnodeop_opv_desc;
431:
432: const struct vnodeopv_desc * const tmpfs_vnodeopv_descs[] = {
433: &tmpfs_fifoop_opv_desc,
434: &tmpfs_specop_opv_desc,
435: &tmpfs_vnodeop_opv_desc,
436: NULL,
437: };
438:
439: struct vfsops tmpfs_vfsops = {
440: MOUNT_TMPFS, /* vfs_name */
1.23 dsl 441: sizeof (struct tmpfs_args),
1.1 jmmv 442: tmpfs_mount, /* vfs_mount */
443: tmpfs_start, /* vfs_start */
444: tmpfs_unmount, /* vfs_unmount */
445: tmpfs_root, /* vfs_root */
1.32 pooka 446: (void *)eopnotsupp, /* vfs_quotactl */
1.1 jmmv 447: tmpfs_statvfs, /* vfs_statvfs */
448: tmpfs_sync, /* vfs_sync */
449: tmpfs_vget, /* vfs_vget */
450: tmpfs_fhtovp, /* vfs_fhtovp */
451: tmpfs_vptofh, /* vfs_vptofh */
452: tmpfs_init, /* vfs_init */
453: NULL, /* vfs_reinit */
454: tmpfs_done, /* vfs_done */
455: NULL, /* vfs_mountroot */
456: tmpfs_snapshot, /* vfs_snapshot */
457: vfs_stdextattrctl, /* vfs_extattrctl */
1.25 pooka 458: (void *)eopnotsupp, /* vfs_suspendctl */
1.1 jmmv 459: tmpfs_vnodeopv_descs,
1.14 christos 460: 0, /* vfs_refcount */
461: { NULL, NULL },
1.1 jmmv 462: };
463: VFS_ATTACH(tmpfs_vfsops);
CVSweb <webmaster@jp.NetBSD.org>