Annotation of src/sys/fs/tmpfs/tmpfs_vfsops.c, Revision 1.27.4.3
1.27.4.3! matt 1: /* $NetBSD: tmpfs_vfsops.c,v 1.27.4.2 2007/11/08 10:59:58 matt Exp $ */
1.1 jmmv 2:
3: /*
1.27.4.2 matt 4: * Copyright (c) 2005, 2006, 2007 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.27.4.3! matt 52: __KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops.c,v 1.27.4.2 2007/11/08 10:59:58 matt Exp $");
1.1 jmmv 53:
54: #include <sys/param.h>
55: #include <sys/types.h>
1.27.4.2 matt 56: #include <sys/kmem.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:
65: /* --------------------------------------------------------------------- */
66:
1.27.4.3! matt 67: static int tmpfs_mount(struct mount *, const char *, void *, size_t *);
! 68: static int tmpfs_start(struct mount *, int);
! 69: static int tmpfs_unmount(struct mount *, int);
1.1 jmmv 70: static int tmpfs_root(struct mount *, struct vnode **);
71: static int tmpfs_vget(struct mount *, ino_t, struct vnode **);
72: static int tmpfs_fhtovp(struct mount *, struct fid *, struct vnode **);
1.13 martin 73: static int tmpfs_vptofh(struct vnode *, struct fid *, size_t *);
1.27.4.3! matt 74: static int tmpfs_statvfs(struct mount *, struct statvfs *);
! 75: static int tmpfs_sync(struct mount *, int, kauth_cred_t);
1.1 jmmv 76: static void tmpfs_init(void);
77: static void tmpfs_done(void);
78: static int tmpfs_snapshot(struct mount *, struct vnode *,
79: struct timespec *);
80:
81: /* --------------------------------------------------------------------- */
82:
83: static int
1.27.4.3! matt 84: tmpfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
1.1 jmmv 85: {
1.27.4.3! matt 86: struct lwp *l = curlwp;
1.1 jmmv 87: int error;
88: ino_t nodes;
89: size_t pages;
90: struct tmpfs_mount *tmp;
91: struct tmpfs_node *root;
1.23 dsl 92: struct tmpfs_args *args = data;
93:
94: if (*data_len < sizeof *args)
95: return EINVAL;
1.1 jmmv 96:
97: /* Handle retrieval of mount point arguments. */
98: if (mp->mnt_flag & MNT_GETARGS) {
99: if (mp->mnt_data == NULL)
100: return EIO;
101: tmp = VFS_TO_TMPFS(mp);
102:
1.23 dsl 103: args->ta_version = TMPFS_ARGS_VERSION;
104: args->ta_nodes_max = tmp->tm_nodes_max;
105: args->ta_size_max = tmp->tm_pages_max * PAGE_SIZE;
1.27.4.2 matt 106:
1.27.4.3! matt 107: root = tmp->tm_root;
1.23 dsl 108: args->ta_root_uid = root->tn_uid;
109: args->ta_root_gid = root->tn_gid;
110: args->ta_root_mode = root->tn_mode;
1.1 jmmv 111:
1.23 dsl 112: *data_len = sizeof *args;
113: return 0;
1.1 jmmv 114: }
115:
116: if (mp->mnt_flag & MNT_UPDATE) {
1.2 jmmv 117: /* XXX: There is no support yet to update file system
1.1 jmmv 118: * settings. Should be added. */
119:
120: return EOPNOTSUPP;
121: }
122:
1.23 dsl 123: if (args->ta_version != TMPFS_ARGS_VERSION)
1.1 jmmv 124: return EINVAL;
125:
126: /* Do not allow mounts if we do not have enough memory to preserve
127: * the minimum reserved pages. */
1.20 thorpej 128: if (tmpfs_mem_info(true) < TMPFS_PAGES_RESERVED)
1.1 jmmv 129: return EINVAL;
130:
1.2 jmmv 131: /* Get the maximum number of memory pages this file system is
1.1 jmmv 132: * allowed to use, based on the maximum size the user passed in
133: * the mount structure. A value of zero is treated as if the
134: * maximum available space was requested. */
1.23 dsl 135: if (args->ta_size_max < PAGE_SIZE || args->ta_size_max >= SIZE_MAX)
1.1 jmmv 136: pages = SIZE_MAX;
137: else
1.23 dsl 138: pages = args->ta_size_max / PAGE_SIZE +
139: (args->ta_size_max % PAGE_SIZE == 0 ? 0 : 1);
1.7 jmmv 140: KASSERT(pages > 0);
1.1 jmmv 141:
1.23 dsl 142: if (args->ta_nodes_max <= 3)
1.7 jmmv 143: nodes = 3 + pages * PAGE_SIZE / 1024;
1.1 jmmv 144: else
1.23 dsl 145: nodes = args->ta_nodes_max;
1.7 jmmv 146: KASSERT(nodes >= 3);
1.1 jmmv 147:
148: /* Allocate the tmpfs mount structure and fill it. */
1.27.4.2 matt 149: tmp = kmem_alloc(sizeof(struct tmpfs_mount), KM_SLEEP);
150: if (tmp == NULL)
151: return ENOMEM;
1.1 jmmv 152:
153: tmp->tm_nodes_max = nodes;
1.27.4.2 matt 154: tmp->tm_nodes_cnt = 0;
155: LIST_INIT(&tmp->tm_nodes);
156:
157: mutex_init(&tmp->tm_lock, MUTEX_DEFAULT, IPL_NONE);
1.1 jmmv 158:
159: tmp->tm_pages_max = pages;
160: tmp->tm_pages_used = 0;
161: tmpfs_pool_init(&tmp->tm_dirent_pool, sizeof(struct tmpfs_dirent),
162: "dirent", tmp);
163: tmpfs_pool_init(&tmp->tm_node_pool, sizeof(struct tmpfs_node),
164: "node", tmp);
165: tmpfs_str_pool_init(&tmp->tm_str_pool, tmp);
166:
167: /* Allocate the root node. */
1.23 dsl 168: error = tmpfs_alloc_node(tmp, VDIR, args->ta_root_uid,
169: args->ta_root_gid, args->ta_root_mode & ALLPERMS, NULL, NULL,
1.27.4.3! matt 170: VNOVAL, &root);
1.1 jmmv 171: KASSERT(error == 0 && root != NULL);
1.27.4.3! matt 172: root->tn_links++;
1.1 jmmv 173: tmp->tm_root = root;
174:
175: mp->mnt_data = tmp;
176: mp->mnt_flag |= MNT_LOCAL;
177: mp->mnt_stat.f_namemax = MAXNAMLEN;
1.27 pooka 178: mp->mnt_fs_bshift = PAGE_SHIFT;
179: mp->mnt_dev_bshift = DEV_BSHIFT;
1.27.4.2 matt 180: mp->mnt_iflag |= IMNT_MPSAFE;
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.27.4.3! matt 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.27.4.3! matt 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.27.4.3! matt 223: node = LIST_FIRST(&tmp->tm_nodes);
! 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.27.4.3! matt 242: next = LIST_NEXT(node, tn_entries);
1.1 jmmv 243: tmpfs_free_node(tmp, node);
1.27.4.3! matt 244: node = next;
1.1 jmmv 245: }
246:
247: tmpfs_pool_destroy(&tmp->tm_dirent_pool);
248: tmpfs_pool_destroy(&tmp->tm_node_pool);
249: tmpfs_str_pool_destroy(&tmp->tm_str_pool);
250:
251: KASSERT(tmp->tm_pages_used == 0);
252:
253: /* Throw away the tmpfs_mount structure. */
1.27.4.2 matt 254: mutex_destroy(&tmp->tm_lock);
255: kmem_free(tmp, sizeof(*tmp));
1.1 jmmv 256: mp->mnt_data = NULL;
257:
258: return 0;
259: }
260:
261: /* --------------------------------------------------------------------- */
262:
263: static int
264: tmpfs_root(struct mount *mp, struct vnode **vpp)
265: {
266:
267: return tmpfs_alloc_vp(mp, VFS_TO_TMPFS(mp)->tm_root, vpp);
268: }
269:
270: /* --------------------------------------------------------------------- */
271:
272: static int
1.17 christos 273: tmpfs_vget(struct mount *mp, ino_t ino,
274: struct vnode **vpp)
1.1 jmmv 275: {
276:
277: printf("tmpfs_vget called; need for it unknown yet\n");
278: return EOPNOTSUPP;
279: }
280:
281: /* --------------------------------------------------------------------- */
282:
283: static int
284: tmpfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
285: {
1.19 thorpej 286: bool found;
1.13 martin 287: struct tmpfs_fid tfh;
1.1 jmmv 288: struct tmpfs_mount *tmp;
289: struct tmpfs_node *node;
290:
291: tmp = VFS_TO_TMPFS(mp);
292:
1.13 martin 293: if (fhp->fid_len != sizeof(struct tmpfs_fid))
1.1 jmmv 294: return EINVAL;
295:
1.13 martin 296: memcpy(&tfh, fhp, sizeof(struct tmpfs_fid));
297:
1.27.4.3! matt 298: if (tfh.tf_id >= tmp->tm_nodes_max)
1.1 jmmv 299: return EINVAL;
300:
1.20 thorpej 301: found = false;
1.27.4.3! matt 302: mutex_enter(&tmp->tm_lock);
1.27.4.2 matt 303: LIST_FOREACH(node, &tmp->tm_nodes, tn_entries) {
1.13 martin 304: if (node->tn_id == tfh.tf_id &&
305: node->tn_gen == tfh.tf_gen) {
1.20 thorpej 306: found = true;
1.1 jmmv 307: break;
308: }
309: }
1.27.4.2 matt 310: mutex_exit(&tmp->tm_lock);
1.1 jmmv 311:
1.27.4.2 matt 312: /* XXXAD nothing to prevent 'node' from being removed. */
1.1 jmmv 313: return found ? tmpfs_alloc_vp(mp, node, vpp) : EINVAL;
314: }
315:
316: /* --------------------------------------------------------------------- */
317:
318: static int
1.13 martin 319: tmpfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1 jmmv 320: {
1.13 martin 321: struct tmpfs_fid tfh;
1.1 jmmv 322: struct tmpfs_node *node;
323:
1.13 martin 324: if (*fh_size < sizeof(struct tmpfs_fid)) {
325: *fh_size = sizeof(struct tmpfs_fid);
326: return E2BIG;
327: }
328: *fh_size = sizeof(struct tmpfs_fid);
1.1 jmmv 329: node = VP_TO_TMPFS_NODE(vp);
330:
1.13 martin 331: memset(&tfh, 0, sizeof(tfh));
332: tfh.tf_len = sizeof(struct tmpfs_fid);
333: tfh.tf_gen = node->tn_gen;
334: tfh.tf_id = node->tn_id;
335: memcpy(fhp, &tfh, sizeof(tfh));
1.1 jmmv 336:
337: return 0;
338: }
339:
340: /* --------------------------------------------------------------------- */
341:
342: /* ARGSUSED2 */
343: static int
1.27.4.3! matt 344: tmpfs_statvfs(struct mount *mp, struct statvfs *sbp)
1.1 jmmv 345: {
1.27.4.2 matt 346: fsfilcnt_t freenodes;
1.1 jmmv 347: struct tmpfs_mount *tmp;
348:
349: tmp = VFS_TO_TMPFS(mp);
350:
351: sbp->f_iosize = sbp->f_frsize = sbp->f_bsize = PAGE_SIZE;
352:
353: sbp->f_blocks = TMPFS_PAGES_MAX(tmp);
354: sbp->f_bavail = sbp->f_bfree = TMPFS_PAGES_AVAIL(tmp);
355: sbp->f_bresvd = 0;
356:
1.27.4.2 matt 357: freenodes = MIN(tmp->tm_nodes_max - tmp->tm_nodes_cnt,
1.1 jmmv 358: TMPFS_PAGES_AVAIL(tmp) * PAGE_SIZE / sizeof(struct tmpfs_node));
359:
1.27.4.2 matt 360: sbp->f_files = tmp->tm_nodes_cnt + freenodes;
1.1 jmmv 361: sbp->f_favail = sbp->f_ffree = freenodes;
362: sbp->f_fresvd = 0;
363:
364: copy_statvfs_info(sbp, mp);
365:
366: return 0;
367: }
368:
369: /* --------------------------------------------------------------------- */
370:
371: /* ARGSUSED0 */
372: static int
1.17 christos 373: tmpfs_sync(struct mount *mp, int waitfor,
1.27.4.3! matt 374: kauth_cred_t uc)
1.1 jmmv 375: {
376:
377: return 0;
378: }
379:
380: /* --------------------------------------------------------------------- */
381:
382: static void
383: tmpfs_init(void)
384: {
385:
386: }
387:
388: /* --------------------------------------------------------------------- */
389:
390: static void
391: tmpfs_done(void)
392: {
393:
394: }
395:
396: /* --------------------------------------------------------------------- */
397:
398: static int
1.17 christos 399: tmpfs_snapshot(struct mount *mp, struct vnode *vp,
400: struct timespec *ctime)
1.1 jmmv 401: {
402:
403: return EOPNOTSUPP;
404: }
405:
406: /* --------------------------------------------------------------------- */
407:
408: /*
409: * tmpfs vfs operations.
410: */
411:
412: extern const struct vnodeopv_desc tmpfs_fifoop_opv_desc;
413: extern const struct vnodeopv_desc tmpfs_specop_opv_desc;
414: extern const struct vnodeopv_desc tmpfs_vnodeop_opv_desc;
415:
416: const struct vnodeopv_desc * const tmpfs_vnodeopv_descs[] = {
417: &tmpfs_fifoop_opv_desc,
418: &tmpfs_specop_opv_desc,
419: &tmpfs_vnodeop_opv_desc,
420: NULL,
421: };
422:
423: struct vfsops tmpfs_vfsops = {
424: MOUNT_TMPFS, /* vfs_name */
1.23 dsl 425: sizeof (struct tmpfs_args),
1.1 jmmv 426: tmpfs_mount, /* vfs_mount */
427: tmpfs_start, /* vfs_start */
428: tmpfs_unmount, /* vfs_unmount */
429: tmpfs_root, /* vfs_root */
1.27.4.3! matt 430: (void *)eopnotsupp, /* vfs_quotactl */
1.1 jmmv 431: tmpfs_statvfs, /* vfs_statvfs */
432: tmpfs_sync, /* vfs_sync */
433: tmpfs_vget, /* vfs_vget */
434: tmpfs_fhtovp, /* vfs_fhtovp */
435: tmpfs_vptofh, /* vfs_vptofh */
436: tmpfs_init, /* vfs_init */
437: NULL, /* vfs_reinit */
438: tmpfs_done, /* vfs_done */
439: NULL, /* vfs_mountroot */
440: tmpfs_snapshot, /* vfs_snapshot */
441: vfs_stdextattrctl, /* vfs_extattrctl */
1.25 pooka 442: (void *)eopnotsupp, /* vfs_suspendctl */
1.1 jmmv 443: tmpfs_vnodeopv_descs,
1.14 christos 444: 0, /* vfs_refcount */
445: { NULL, NULL },
1.1 jmmv 446: };
447: VFS_ATTACH(tmpfs_vfsops);
CVSweb <webmaster@jp.NetBSD.org>