]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/spl/spl-kmem.c
Add missing __GFP_HIGHMEM flag to vmalloc
[mirror_zfs.git] / module / spl / spl-kmem.c
index e97d5f25559de615f65d15da14fb075ffc45f356..824b5e89f5072b2cdec359ebcee1e0f1c2462906 100644 (file)
@@ -27,7 +27,6 @@
 #include <sys/kmem.h>
 #include <sys/vmem.h>
 #include <linux/mm.h>
-#include <linux/ratelimit.h>
 
 /*
  * As a general rule kmem_alloc() allocations should be small, preferably
@@ -35,7 +34,7 @@
  * rate limited warning will be printed to the console for any kmem_alloc()
  * which exceeds a reasonable threshold.
  *
- * The default warning threshold is set to eight pages but capped at 32K to
+ * The default warning threshold is set to sixteen pages but capped at 64K to
  * accommodate systems using large pages.  This value was selected to be small
  * enough to ensure the largest allocations are quickly noticed and fixed.
  * But large enough to avoid logging any warnings when a allocation size is
@@ -44,7 +43,8 @@
  * allocations are quickly caught.  These warnings may be disabled by setting
  * the threshold to zero.
  */
-unsigned int spl_kmem_alloc_warn = MAX(8 * PAGE_SIZE, 32 * 1024);
+/* BEGIN CSTYLED */
+unsigned int spl_kmem_alloc_warn = MIN(16 * PAGE_SIZE, 64 * 1024);
 module_param(spl_kmem_alloc_warn, uint, 0644);
 MODULE_PARM_DESC(spl_kmem_alloc_warn,
        "Warning threshold in bytes for a kmem_alloc()");
@@ -64,6 +64,7 @@ module_param(spl_kmem_alloc_max, uint, 0644);
 MODULE_PARM_DESC(spl_kmem_alloc_max,
        "Maximum size in bytes for a kmem_alloc()");
 EXPORT_SYMBOL(spl_kmem_alloc_max);
+/* END CSTYLED */
 
 int
 kmem_debugging(void)
@@ -132,12 +133,6 @@ strfree(char *str)
 }
 EXPORT_SYMBOL(strfree);
 
-/*
- * Limit the number of large allocation stack traces dumped to not more than
- * 5 every 60 seconds to prevent denial-of-service attacks from debug code.
- */
-DEFINE_RATELIMIT_STATE(kmem_alloc_ratelimit_state, 60 * HZ, 5);
-
 /*
  * General purpose unified implementation of kmem_alloc(). It is an
  * amalgamation of Linux and Illumos allocator design. It should never be
@@ -149,6 +144,7 @@ inline void *
 spl_kmem_alloc_impl(size_t size, int flags, int node)
 {
        gfp_t lflags = kmem_flags_convert(flags);
+       int use_vmem = 0;
        void *ptr;
 
        /*
@@ -157,7 +153,7 @@ spl_kmem_alloc_impl(size_t size, int flags, int node)
         * through the vmem_alloc()/vmem_zalloc() interfaces.
         */
        if ((spl_kmem_alloc_warn > 0) && (size > spl_kmem_alloc_warn) &&
-           !(flags & KM_VMEM) && __ratelimit(&kmem_alloc_ratelimit_state)) {
+           !(flags & KM_VMEM)) {
                printk(KERN_WARNING
                    "Large kmem_alloc(%lu, 0x%x), please file an issue at:\n"
                    "https://github.com/zfsonlinux/zfs/issues/new\n",
@@ -182,9 +178,10 @@ spl_kmem_alloc_impl(size_t size, int flags, int node)
                 * impact performance so frequently manipulating the virtual
                 * address space is strongly discouraged.
                 */
-               if (unlikely(size > spl_kmem_alloc_max)) {
+               if ((size > spl_kmem_alloc_max) || use_vmem) {
                        if (flags & KM_VMEM) {
-                               ptr = spl_vmalloc(size, lflags, PAGE_KERNEL);
+                               ptr = __vmalloc(size, lflags | __GFP_HIGHMEM,
+                                   PAGE_KERNEL);
                        } else {
                                return (NULL);
                        }
@@ -195,12 +192,13 @@ spl_kmem_alloc_impl(size_t size, int flags, int node)
                if (likely(ptr) || (flags & KM_NOSLEEP))
                        return (ptr);
 
-               if (unlikely(__ratelimit(&kmem_alloc_ratelimit_state))) {
-                       printk(KERN_WARNING
-                           "Possible memory allocation deadlock: "
-                           "size=%lu lflags=0x%x",
-                           (unsigned long)size, lflags);
-                       dump_stack();
+               /*
+                * For vmem_alloc() and vmem_zalloc() callers retry immediately
+                * using __vmalloc() which is unlikely to fail.
+                */
+               if ((flags & KM_VMEM) && (use_vmem == 0))  {
+                       use_vmem = 1;
+                       continue;
                }
 
                /*
@@ -373,6 +371,10 @@ spl_kmem_free_track(const void *ptr, size_t size)
 {
        kmem_debug_t *dptr;
 
+       /* Ignore NULL pointer since we haven't tracked it at all */
+       if (ptr == NULL)
+               return;
+
        /* Must exist in hash due to kmem_alloc() */
        dptr = kmem_del_init(&kmem_lock, kmem_table, KMEM_HASH_BITS, ptr);
        ASSERT3P(dptr, !=, NULL);
@@ -506,10 +508,11 @@ spl_kmem_fini_tracking(struct list_head *list, spinlock_t *lock)
                printk(KERN_WARNING "%-16s %-5s %-16s %s:%s\n", "address",
                    "size", "data", "func", "line");
 
-       list_for_each_entry(kd, list, kd_list)
+       list_for_each_entry(kd, list, kd_list) {
                printk(KERN_WARNING "%p %-5d %-16s %s:%d\n", kd->kd_addr,
                    (int)kd->kd_size, spl_sprintf_addr(kd, str, 17, 8),
                    kd->kd_func, kd->kd_line);
+       }
 
        spin_unlock_irqrestore(lock, flags);
 }
@@ -518,9 +521,12 @@ spl_kmem_fini_tracking(struct list_head *list, spinlock_t *lock)
 int
 spl_kmem_init(void)
 {
+
 #ifdef DEBUG_KMEM
        kmem_alloc_used_set(0);
 
+
+
 #ifdef DEBUG_KMEM_TRACKING
        spl_kmem_init_tracking(&kmem_list, &kmem_lock, KMEM_TABLE_SIZE);
 #endif /* DEBUG_KMEM_TRACKING */