tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Making tmpfs reserved memory configurable



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


Home | Main Index | Thread Index | Old Index