Print this page

        

@@ -18,11 +18,11 @@
  *
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2016 Joyent, Inc.
+ * Copyright 2015 Joyent, Inc.
  */
 
 #include <sys/types.h>
 #include <sys/errno.h>
 #include <sys/param.h>

@@ -41,11 +41,10 @@
 #include <sys/policy.h>
 #include <sys/fs/tmp.h>
 #include <sys/fs/tmpnode.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
-#include <vm/anon.h>
 
 #define KILOBYTE        1024
 #define MEGABYTE        (1024 * KILOBYTE)
 #define GIGABYTE        (1024 * MEGABYTE)
 

@@ -53,84 +52,10 @@
 
 #define VALIDMODEBITS   07777
 
 extern pgcnt_t swapfs_minfree;
 
-void *
-tmp_kmem_zalloc(struct tmount *tm, size_t size, int flag)
-{
-        void *buf;
-        zone_t *zone;
-        size_t pages;
-
-        mutex_enter(&tm->tm_contents);
-        zone = tm->tm_vfsp->vfs_zone;
-        if (tm->tm_anonmem + size > tm->tm_anonmax ||
-            tm->tm_anonmem + size < tm->tm_anonmem ||
-            size + ptob(tmpfs_minfree) <= size ||
-            !anon_checkspace(size + ptob(tmpfs_minfree), zone)) {
-                mutex_exit(&tm->tm_contents);
-                return (NULL);
-        }
-
-        /*
-         * Only make anonymous memory reservations when a page boundary is
-         * crossed.  This is necessary since the anon_resv functions rounds up
-         * to PAGESIZE internally.
-         */
-        pages = btopr(tm->tm_allocmem + size);
-        pages -= btopr(tm->tm_allocmem);
-        if (pages > 0 && anon_try_resv_zone(ptob(pages), zone) == 0) {
-                mutex_exit(&tm->tm_contents);
-                return (NULL);
-        }
-
-        tm->tm_allocmem += size;
-        tm->tm_anonmem += size;
-        mutex_exit(&tm->tm_contents);
-
-        buf = kmem_zalloc(size, flag);
-        if (buf == NULL) {
-                mutex_enter(&tm->tm_contents);
-                ASSERT(tm->tm_anonmem > tm->tm_anonmem - size);
-                tm->tm_anonmem -= size;
-                if (pages > 0) {
-                        /*
-                         * Re-chasing the zone pointer is necessary since a
-                         * forced umount could have been performed while the
-                         * tm_contents lock was dropped during allocation.
-                         */
-                        anon_unresv_zone(ptob(pages), tm->tm_vfsp->vfs_zone);
-                }
-                mutex_exit(&tm->tm_contents);
-        }
-
-        return (buf);
-}
-
-void
-tmp_kmem_free(struct tmount *tm, void *buf, size_t size)
-{
-        size_t pages;
-
-        kmem_free(buf, size);
-        mutex_enter(&tm->tm_contents);
-        ASSERT(tm->tm_anonmem > tm->tm_anonmem - size);
-        tm->tm_anonmem -= size;
-        pages = btopr(tm->tm_allocmem);
-        tm->tm_allocmem -= size;
-        pages -= btopr(tm->tm_allocmem);
-        /*
-         * Like the tmp_kmem_zalloc case, only unreserve anonymous memory when
-         * a page boundary has been crossed.
-         */
-        if (pages > 0) {
-                anon_unresv_zone(size, tm->tm_vfsp->vfs_zone);
-        }
-        mutex_exit(&tm->tm_contents);
-}
-
 int
 tmp_taccess(void *vtp, int mode, struct cred *cred)
 {
         struct tmpnode *tp = vtp;
         int shift = 0;

@@ -172,12 +97,46 @@
 
         return (0);
 }
 
 /*
- * Convert a string containing a number (number of bytes) to a size_t,
- * containing the corresponding number of bytes. On 32-bit kernels, the
+ * Allocate zeroed memory if tmpfs_maxkmem has not been exceeded
+ * or the 'musthave' flag is set.  'musthave' allocations should
+ * always be subordinate to normal allocations so that tmpfs_maxkmem
+ * can't be exceeded by more than a few KB.  Example: when creating
+ * a new directory, the tmpnode is a normal allocation; if that
+ * succeeds, the dirents for "." and ".." are 'musthave' allocations.
+ */
+void *
+tmp_memalloc(size_t size, int musthave)
+{
+        static time_t last_warning;
+        time_t now;
+
+        if (atomic_add_long_nv(&tmp_kmemspace, size) < tmpfs_maxkmem ||
+            musthave)
+                return (kmem_zalloc(size, KM_SLEEP));
+
+        atomic_add_long(&tmp_kmemspace, -size);
+        now = gethrestime_sec();
+        if (last_warning != now) {
+                last_warning = now;
+                cmn_err(CE_WARN, "tmp_memalloc: tmpfs over memory limit");
+        }
+        return (NULL);
+}
+
+void
+tmp_memfree(void *cp, size_t size)
+{
+        kmem_free(cp, size);
+        atomic_add_long(&tmp_kmemspace, -size);
+}
+
+/*
+ * Convert a string containing a number (number of bytes) to a pgcnt_t,
+ * containing the corresponding number of pages. On 32-bit kernels, the
  * maximum value encoded in 'str' is PAGESIZE * ULONG_MAX, while the value
  * returned in 'maxpg' is at most ULONG_MAX.
  *
  * The number may be followed by a magnitude suffix: "k" or "K" for kilobytes;
  * "m" or "M" for megabytes; "g" or "G" for gigabytes.  This interface allows

@@ -191,16 +150,18 @@
  *
  * Parse and overflow errors are detected and a non-zero number returned on
  * error.
  */
 int
-tmp_convnum(char *str, size_t *maxbytes)
+tmp_convnum(char *str, pgcnt_t *maxpg)
 {
         u_longlong_t num = 0;
-        u_longlong_t max_bytes = (uint64_t)SIZE_MAX;
-        size_t pages;
-
+#ifdef _LP64
+        u_longlong_t max_bytes = ULONG_MAX;
+#else
+        u_longlong_t max_bytes = PAGESIZE * (uint64_t)ULONG_MAX;
+#endif
         char *c;
         const struct convchar {
                 char *cc_char;
                 uint64_t cc_factor;
         } convchars[] = {

@@ -286,27 +247,18 @@
 valid_char:
                 continue;
         }
 
 done:
-
         /*
-         * We've been given a size in bytes; however, we want to make sure that
-         * we have at least one page worth no matter what. Therefore we use
-         * btopr to round up. However, this may cause an overflow only if 'num'
-         * is between (max_bytes - PAGESIZE) and (max_bytes). In this case the
-         * resulting number is zero, which is what we check for below. Note, we
-         * require at least one page, so if pages is zero, well, it wasn't going
-         * to work anyways.
+         * Since btopr() rounds up to page granularity, this round-up can
+         * cause an overflow only if 'num' is between (max_bytes - PAGESIZE)
+         * and (max_bytes). In this case the resulting number is zero, which
+         * is what we check for below.
          */
-        pages = btopr(num);
-        if (pages == 0) {
+        if ((*maxpg = (pgcnt_t)btopr(num)) == 0 && num != 0)
                 return (EINVAL);
-        }
-
-        *maxbytes = ptob(pages);
-
         return (0);
 }
 
 /*
  * Parse an octal mode string for use as the permissions set for the root