I have been on a quest to make the stock vax install CD (-image) usable on VAX machines with 8 MB recently. (8 MB is the lowest I could persuade simh to emulate, for 4 MB we will need a custom kernel anyway and for smaller even a custom /boot - I will cover installing on those machines in an upcoming improvement of the install docs).
After a few easy steps, I hit a hard wall: using MFS filesystem on the install CD does not work well (we take too long to configure swap, the userland part of MFS gets often killed way before). However, tmpfs does not work at all under such low memory situations. See mount_tmpfs(8), in the paragraph about the -s option: Note that four megabytes are always reserved for the system and cannot be assigned to the file system. Now, with a 3.2 MB text GENERIC kernel and 8 MB RAM, we certainly don't have 4 MB available at all - so tmpfs is not usable. But, on the other hand, the CD is not usable without tmpfs - so we are in a deadlock. Simple way out: since we know the tmpfs is needed more than any RAM, we could tell tmpfs to lower the amount of ram reserved for the system via sysctl(8). This is what the first patch attached does. The second patch updates the man page and adds a kauth decision to allow this changes only for root. Finally, the trivial third patch uses the new feature and makes VAX install CDs work on an emulated VAX 11/780 with 8 MB total ram. Any objections to the general aproach? Reviews, especially of the kauth and sysctl code welcome (everything else is mostly mechanical). One open issue is the name - I somehow thought "reservee" would be a proper noune for "reserved memory", but apparently this does not work out well for native speakers, so it probably should be named something else. What about "min_ram_free"? Other suggestions? Martin
Index: sys/fs/tmpfs/tmpfs.h =================================================================== RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs.h,v retrieving revision 1.49 diff -u -p -r1.49 tmpfs.h --- sys/fs/tmpfs/tmpfs.h 30 Apr 2014 01:33:51 -0000 1.49 +++ sys/fs/tmpfs/tmpfs.h 30 May 2014 13:42:10 -0000 @@ -311,7 +311,7 @@ bool tmpfs_strname_neqlen(struct compon */ /* Amount of memory pages to reserve for the system. */ -#define TMPFS_PAGES_RESERVED (4 * 1024 * 1024 / PAGE_SIZE) +extern size_t tmpfs_pages_reserved; /* * Routines to convert VFS structures to tmpfs internal ones. Index: sys/fs/tmpfs/tmpfs_mem.c =================================================================== RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_mem.c,v retrieving revision 1.5 diff -u -p -r1.5 tmpfs_mem.c --- sys/fs/tmpfs/tmpfs_mem.c 30 Apr 2014 01:33:51 -0000 1.5 +++ sys/fs/tmpfs/tmpfs_mem.c 30 May 2014 13:42:10 -0000 @@ -48,6 +48,8 @@ __KERNEL_RCSID(0, "$NetBSD: tmpfs_mem.c, extern struct pool tmpfs_dirent_pool; extern struct pool tmpfs_node_pool; +size_t tmpfs_pages_reserved = 4 * 1024 * 1024 / PAGE_SIZE; + void tmpfs_mntmem_init(struct tmpfs_mount *mp, uint64_t memlimit) { @@ -89,7 +91,7 @@ tmpfs_mntmem_set(struct tmpfs_mount *mp, * => If 'total' is true, then return _total_ amount of pages. * => If false, then return the amount of _free_ memory pages. * - * Remember to remove TMPFS_PAGES_RESERVED from the returned value to avoid + * Remember to remove tmpfs_pages_reserved from the returned value to avoid * excessive memory usage. */ size_t @@ -118,10 +120,10 @@ tmpfs_bytes_max(struct tmpfs_mount *mp) size_t freepages = tmpfs_mem_info(false); uint64_t avail_mem; - if (freepages < TMPFS_PAGES_RESERVED) { + if (freepages < tmpfs_pages_reserved) { freepages = 0; } else { - freepages -= TMPFS_PAGES_RESERVED; + freepages -= tmpfs_pages_reserved; } avail_mem = round_page(mp->tm_bytes_used) + (freepages << PAGE_SHIFT); return MIN(mp->tm_mem_limit, avail_mem); Index: sys/fs/tmpfs/tmpfs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/fs/tmpfs/tmpfs_vfsops.c,v retrieving revision 1.61 diff -u -p -r1.61 tmpfs_vfsops.c --- sys/fs/tmpfs/tmpfs_vfsops.c 30 Apr 2014 01:59:30 -0000 1.61 +++ sys/fs/tmpfs/tmpfs_vfsops.c 30 May 2014 13:42:10 -0000 @@ -49,9 +49,11 @@ __KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops #include <sys/kmem.h> #include <sys/mount.h> #include <sys/stat.h> +#include <sys/sysctl.h> #include <sys/systm.h> #include <sys/vnode.h> #include <sys/module.h> +#include <sys/kauth.h> #include <miscfs/genfs/genfs.h> #include <fs/tmpfs/tmpfs.h> @@ -59,6 +61,9 @@ __KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops MODULE(MODULE_CLASS_VFS, tmpfs, NULL); +static struct sysctllog *tmpfs_sysctl_log; +static int tmpfs_pages_reservee(SYSCTLFN_PROTO); + struct pool tmpfs_dirent_pool; struct pool tmpfs_node_pool; @@ -132,7 +137,7 @@ tmpfs_mount(struct mount *mp, const char /* Prohibit mounts if there is not enough memory. */ - if (tmpfs_mem_info(true) < TMPFS_PAGES_RESERVED) + if (tmpfs_mem_info(true) < tmpfs_pages_reserved) return EINVAL; /* Get the memory usage limit for this file-system. */ @@ -432,13 +437,91 @@ struct vfsops tmpfs_vfsops = { static int tmpfs_modcmd(modcmd_t cmd, void *arg) { + int error; + const struct sysctlnode *tmpfsnode; switch (cmd) { case MODULE_CMD_INIT: - return vfs_attach(&tmpfs_vfsops); + error = vfs_attach(&tmpfs_vfsops); + if (error != 0) + break; + error = sysctl_createv(&tmpfs_sysctl_log, 0, NULL, &tmpfsnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "tmpfs", + SYSCTL_DESCR("tmpfs memory file system"), + NULL, 0, NULL, 0, + CTL_VFS, 24, CTL_EOL); + if (error != 0) { + printf("could not create vfs.tmpfs node: %d\n", error); + } else { + error = sysctl_createv(&tmpfs_sysctl_log, 0, + &tmpfsnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_QUAD, "reservee", + SYSCTL_DESCR("memory reserved for system use"), + tmpfs_pages_reservee, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + if (error != 0) + printf("could not create vfs.tmmpfs.reservee leaf: %d\n", error); + } + error = 0; + /* + * XXX the "24" above could be dynamic, thereby eliminating + * one more instance of the "number to vfs" mapping problem, + * but "24" is the order as taken from sys/mount.h + */ + break; case MODULE_CMD_FINI: - return vfs_detach(&tmpfs_vfsops); + error = vfs_detach(&tmpfs_vfsops); + if (error != 0) + break; + sysctl_teardown(&tmpfs_sysctl_log); + break; default: - return ENOTTY; + error = ENOTTY; + break; } + + return error; +} + +static int +tmpfs_pages_reservee(SYSCTLFN_ARGS) +{ + u_quad_t *oldval; + const u_quad_t *newval; + size_t new_pages; + int error = 0; + + if (namelen != 0) + return EOPNOTSUPP; + + if (oldlenp && oldp) { + if (*oldlenp == sizeof(u_quad_t)) { + oldval = (u_quad_t*)oldp; + *oldval = PAGE_SIZE * tmpfs_pages_reserved; + } else { + error = EINVAL; + } + } + + if (newlen && newp) { + /* are we allowed to change this? */ + error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TMPFS, + KAUTH_REQ_SYSTEM_TMPFS_RESERVEE, NULL, NULL, NULL); + if (error != 0) + return error; + if (newlen == sizeof(u_quad_t)) { + newval = (const u_quad_t*)newp; + new_pages = *newval / PAGE_SIZE; + /* arbitrary lower limit */ + if (new_pages < 32) + new_pages = 32; + tmpfs_pages_reserved = new_pages; + } else { + error = EINVAL; + } + } + + return error; }
Index: sbin/mount_tmpfs/mount_tmpfs.8 =================================================================== RCS file: /cvsroot/src/sbin/mount_tmpfs/mount_tmpfs.8,v retrieving revision 1.17 diff -u -r1.17 mount_tmpfs.8 --- sbin/mount_tmpfs/mount_tmpfs.8 4 Dec 2013 18:05:21 -0000 1.17 +++ sbin/mount_tmpfs/mount_tmpfs.8 30 May 2014 13:42:46 -0000 @@ -83,8 +83,12 @@ Specifies the total file system size in bytes. If zero is given (the default), the available amount of memory (including main memory and swap space) will be used. -Note that four megabytes are always reserved for the system and cannot +Note that some memory (by default: +four megabytes) are always reserved for the system and cannot be assigned to the file system. +This resevee can be queried (or as root: set) with the +.Pa vfs.tmpfs.reservee +sysctl. .Ar Size can alternatively be specified as a percentage of the available system ram by using the notation @@ -159,3 +163,10 @@ .Pq Fl n will prevent this; the default value for this setting is also often adjusted to an adequate value to resolve this. +.Pp +Changing the +.Pa vfs.tmpfs.reservee +sysctl value after mounting one or more tmpfs file systems will cause +non obvious behaviour. +The new limit will not change the per filesystem limits of existing mounts, +but the total memory usage will be enforced for any new allocations. Index: sys/sys/kauth.h =================================================================== RCS file: /cvsroot/src/sys/sys/kauth.h,v retrieving revision 1.71 diff -u -r1.71 kauth.h --- sys/sys/kauth.h 18 Mar 2013 19:35:46 -0000 1.71 +++ sys/sys/kauth.h 30 May 2014 13:42:46 -0000 @@ -111,6 +111,7 @@ KAUTH_SYSTEM_LFS, KAUTH_SYSTEM_FS_EXTATTR, KAUTH_SYSTEM_FS_SNAPSHOT, + KAUTH_SYSTEM_TMPFS, }; /* @@ -156,6 +157,7 @@ KAUTH_REQ_SYSTEM_LFS_FCNTL, KAUTH_REQ_SYSTEM_MOUNT_UMAP, KAUTH_REQ_SYSTEM_MOUNT_DEVICE, + KAUTH_REQ_SYSTEM_TMPFS_RESERVEE, }; /* Index: sys/secmodel/suser/secmodel_suser.c =================================================================== RCS file: /cvsroot/src/sys/secmodel/suser/secmodel_suser.c,v retrieving revision 1.41 diff -u -r1.41 secmodel_suser.c --- sys/secmodel/suser/secmodel_suser.c 25 Feb 2014 18:30:13 -0000 1.41 +++ sys/secmodel/suser/secmodel_suser.c 30 May 2014 13:42:46 -0000 @@ -443,6 +443,18 @@ break; + case KAUTH_SYSTEM_TMPFS: + switch (req) { + case KAUTH_REQ_SYSTEM_TMPFS_RESERVEE: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + default: + break; + } + + break; + default: break; }
Index: distrib/vax/cdroms/installcd/etc.rc =================================================================== RCS file: /cvsroot/src/distrib/vax/cdroms/installcd/etc.rc,v retrieving revision 1.3 diff -u -r1.3 etc.rc --- distrib/vax/cdroms/installcd/etc.rc 30 May 2014 13:19:42 -0000 1.3 +++ distrib/vax/cdroms/installcd/etc.rc 30 May 2014 13:43:06 -0000 @@ -1,4 +1,4 @@ -# $NetBSD: etc.rc,v 1.3 2014/05/30 13:19:42 martin Exp $ +# $NetBSD: etc.rc,v 1.2 2014/05/23 12:25:46 martin Exp $ # # Copyright (c) 1997 Perry E. Metzger # Copyright (c) 1994 Christopher G. Demetriou @@ -61,6 +61,9 @@ fi fi +# we really need the following tmpfs mounts - even at the cost of serious +# low memory operation, so allow tmpfs to eat up most of our memory: +sysctl -w vfs.tmpfs.reservee=102400 >/dev/null 2>&1 # mount a few tempfs to allow modifications over the CD contents mount -t tmpfs tmpfs /tmp || lowmemfail mount -t tmpfs tmpfs /var || lowmemfail