summaryrefslogtreecommitdiffstats
path: root/include/sys
diff options
context:
space:
mode:
Diffstat (limited to 'include/sys')
-rw-r--r--include/sys/kmem.h234
1 files changed, 146 insertions, 88 deletions
diff --git a/include/sys/kmem.h b/include/sys/kmem.h
index 17b3a2276..e90c6b8ce 100644
--- a/include/sys/kmem.h
+++ b/include/sys/kmem.h
@@ -87,10 +87,10 @@ kzalloc_nofail(size_t size, gfp_t flags)
return ptr;
}
-#ifdef HAVE_KMALLOC_NODE
static inline void *
kmalloc_node_nofail(size_t size, gfp_t flags, int node)
{
+#ifdef HAVE_KMALLOC_NODE
void *ptr;
do {
@@ -98,16 +98,63 @@ kmalloc_node_nofail(size_t size, gfp_t flags, int node)
} while (ptr == NULL && (flags & __GFP_WAIT));
return ptr;
-}
+#else
+ return kmalloc_nofail(size, flags);
#endif /* HAVE_KMALLOC_NODE */
+}
+
+static inline void *
+vmalloc_nofail(size_t size, gfp_t flags)
+{
+ void *ptr;
+
+ /*
+ * Retry failed __vmalloc() allocations once every second. The
+ * rational for the delay is that the likely failure modes are:
+ *
+ * 1) The system has completely exhausted memory, in which case
+ * delaying 1 second for the memory reclaim to run is reasonable
+ * to avoid thrashing the system.
+ * 2) The system has memory but has exhausted the small virtual
+ * address space available on 32-bit systems. Retrying the
+ * allocation immediately will only result in spinning on the
+ * virtual address space lock. It is better delay a second and
+ * hope that another process will free some of the address space.
+ * But the bottom line is there is not much we can actually do
+ * since we can never safely return a failure and honor the
+ * Solaris semantics.
+ */
+ while (1) {
+ ptr = __vmalloc(size, flags | __GFP_HIGHMEM, PAGE_KERNEL);
+ if (unlikely((ptr == NULL) && (flags & __GFP_WAIT))) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ);
+ } else {
+ break;
+ }
+ }
+
+ return ptr;
+}
+
+static inline void *
+vzalloc_nofail(size_t size, gfp_t flags)
+{
+ void *ptr;
+
+ ptr = vmalloc_nofail(size, flags);
+ if (ptr)
+ memset(ptr, 0, (size));
+
+ return ptr;
+}
#ifdef DEBUG_KMEM
-# ifdef HAVE_ATOMIC64_T
-extern atomic64_t kmem_alloc_used;
-extern unsigned long long kmem_alloc_max;
-extern atomic64_t vmem_alloc_used;
-extern unsigned long long vmem_alloc_max;
+/*
+ * Memory accounting functions to be used only when DEBUG_KMEM is set.
+ */
+# ifdef HAVE_ATOMIC64_T
# define kmem_alloc_used_add(size) atomic64_add(size, &kmem_alloc_used)
# define kmem_alloc_used_sub(size) atomic64_sub(size, &kmem_alloc_used)
@@ -118,13 +165,13 @@ extern unsigned long long vmem_alloc_max;
# define vmem_alloc_used_read() atomic64_read(&vmem_alloc_used)
# define vmem_alloc_used_set(size) atomic64_set(&vmem_alloc_used, size)
-# else
-
-extern atomic_t kmem_alloc_used;
+extern atomic64_t kmem_alloc_used;
extern unsigned long long kmem_alloc_max;
-extern atomic_t vmem_alloc_used;
+extern atomic64_t vmem_alloc_used;
extern unsigned long long vmem_alloc_max;
+# else /* HAVE_ATOMIC64_T */
+
# define kmem_alloc_used_add(size) atomic_add(size, &kmem_alloc_used)
# define kmem_alloc_used_sub(size) atomic_sub(size, &kmem_alloc_used)
# define kmem_alloc_used_read() atomic_read(&kmem_alloc_used)
@@ -134,90 +181,107 @@ extern unsigned long long vmem_alloc_max;
# define vmem_alloc_used_read() atomic_read(&vmem_alloc_used)
# define vmem_alloc_used_set(size) atomic_set(&vmem_alloc_used, size)
-# endif /* _LP64 */
-
-# define kmem_alloc(size, flags) __kmem_alloc((size), (flags), 0, 0)
-# define kmem_zalloc(size, flags) __kmem_alloc((size), ((flags) | \
- __GFP_ZERO), 0, 0)
-
-/* The node alloc functions are only used by the SPL code itself */
-# ifdef HAVE_KMALLOC_NODE
-# define kmem_alloc_node(size, flags, node) __kmem_alloc((size), (flags), 1, \
- node)
-# else
-# define kmem_alloc_node(size, flags, node) __kmem_alloc((size), (flags), 0, 0)
-# endif
+extern atomic_t kmem_alloc_used;
+extern unsigned long long kmem_alloc_max;
+extern atomic_t vmem_alloc_used;
+extern unsigned long long vmem_alloc_max;
-# define vmem_zalloc(size, flags) vmem_alloc((size), ((flags) | \
- __GFP_ZERO))
+# endif /* HAVE_ATOMIC64_T */
# ifdef DEBUG_KMEM_TRACKING
-
-extern void *kmem_alloc_track(size_t size, int flags, const char *func,
- int line, int node_alloc, int node);
-extern void kmem_free_track(void *ptr, size_t size);
-extern void *vmem_alloc_track(size_t size, int flags, const char *func,
- int line);
-extern void vmem_free_track(void *ptr, size_t size);
-
-# define __kmem_alloc(size, flags, na, node) kmem_alloc_track((size), \
- (flags), __FUNCTION__, \
- __LINE__, (na), (node))
-# define kmem_free(ptr, size) kmem_free_track((ptr), (size))
-# define vmem_alloc(size, flags) vmem_alloc_track((size), \
- (flags),__FUNCTION__, \
- __LINE__)
-# define vmem_free(ptr, size) vmem_free_track((ptr), (size))
+/*
+ * DEBUG_KMEM && DEBUG_KMEM_TRACKING
+ *
+ * The maximum level of memory debugging. All memory will be accounted
+ * for and each allocation will be explicitly tracked. Any allocation
+ * which is leaked will be reported on module unload and the exact location
+ * where that memory was allocation will be reported. This level of memory
+ * tracking will have a significant impact on performance and should only
+ * be enabled for debugging. This feature may be enabled by passing
+ * --enable-debug-kmem-tracking to configure.
+ */
+# define kmem_alloc(sz, fl) kmem_alloc_track((sz), (fl), \
+ __FUNCTION__, __LINE__, 0, 0)
+# define kmem_zalloc(sz, fl) kmem_alloc_track((sz), (fl)|__GFP_ZERO,\
+ __FUNCTION__, __LINE__, 0, 0)
+# define kmem_alloc_node(sz, fl, nd) kmem_alloc_track((sz), (fl), \
+ __FUNCTION__, __LINE__, 1, nd)
+# define kmem_free(ptr, sz) kmem_free_track((ptr), (sz))
+
+# define vmem_alloc(sz, fl) vmem_alloc_track((sz), (fl), \
+ __FUNCTION__, __LINE__)
+# define vmem_zalloc(sz, fl) vmem_alloc_track((sz), (fl)|__GFP_ZERO,\
+ __FUNCTION__, __LINE__)
+# define vmem_free(ptr, sz) vmem_free_track((ptr), (sz))
+
+extern void *kmem_alloc_track(size_t, int, const char *, int, int, int);
+extern void kmem_free_track(void *, size_t);
+extern void *vmem_alloc_track(size_t, int, const char *, int);
+extern void vmem_free_track(void *, size_t);
# else /* DEBUG_KMEM_TRACKING */
-
-extern void *kmem_alloc_debug(size_t size, int flags, const char *func,
- int line, int node_alloc, int node);
-extern void kmem_free_debug(void *ptr, size_t size);
-extern void *vmem_alloc_debug(size_t size, int flags, const char *func,
- int line);
-extern void vmem_free_debug(void *ptr, size_t size);
-
-# define __kmem_alloc(size, flags, na, node) kmem_alloc_debug((size), \
- (flags), __FUNCTION__, \
- __LINE__, (na), (node))
-# define kmem_free(ptr, size) kmem_free_debug((ptr), (size))
-# define vmem_alloc(size, flags) vmem_alloc_debug((size), \
- (flags), __FUNCTION__, \
- __LINE__)
-# define vmem_free(ptr, size) vmem_free_debug((ptr), (size))
+/*
+ * DEBUG_KMEM && !DEBUG_KMEM_TRACKING
+ *
+ * The default build will set DEBUG_KEM. This provides basic memory
+ * accounting with little to no impact on performance. When the module
+ * is unloaded in any memory was leaked the total number of leaked bytes
+ * will be reported on the console. To disable this basic accounting
+ * pass the --disable-debug-kmem option to configure.
+ */
+# define kmem_alloc(sz, fl) kmem_alloc_debug((sz), (fl), \
+ __FUNCTION__, __LINE__, 0, 0)
+# define kmem_zalloc(sz, fl) kmem_alloc_debug((sz), (fl)|__GFP_ZERO,\
+ __FUNCTION__, __LINE__, 0, 0)
+# define kmem_alloc_node(sz, fl, nd) kmem_alloc_debug((sz), (fl), \
+ __FUNCTION__, __LINE__, 1, nd)
+# define kmem_free(ptr, sz) kmem_free_debug((ptr), (sz))
+
+# define vmem_alloc(sz, fl) vmem_alloc_debug((sz), (fl), \
+ __FUNCTION__, __LINE__)
+# define vmem_zalloc(sz, fl) vmem_alloc_debug((sz), (fl)|__GFP_ZERO,\
+ __FUNCTION__, __LINE__)
+# define vmem_free(ptr, sz) vmem_free_debug((ptr), (sz))
+
+extern void *kmem_alloc_debug(size_t, int, const char *, int, int, int);
+extern void kmem_free_debug(void *, size_t);
+extern void *vmem_alloc_debug(size_t, int, const char *, int);
+extern void vmem_free_debug(void *, size_t);
# endif /* DEBUG_KMEM_TRACKING */
-
#else /* DEBUG_KMEM */
+/*
+ * !DEBUG_KMEM && !DEBUG_KMEM_TRACKING
+ *
+ * All debugging is disabled. There will be no overhead even for
+ * minimal memory accounting. To enable basic accounting pass the
+ * --enable-debug-kmem option to configure.
+ */
+# define kmem_alloc(sz, fl) kmalloc_nofail((sz), (fl))
+# define kmem_zalloc(sz, fl) kzalloc_nofail((sz), (fl))
+# define kmem_alloc_node(sz, fl, nd) kmalloc_node_nofail((sz), (fl), (nd))
+# define kmem_free(ptr, sz) ((void)(sz), kfree(ptr))
-# define kmem_alloc(size, flags) kmalloc_nofail((size), (flags))
-# define kmem_zalloc(size, flags) kzalloc_nofail((size), (flags))
-# define kmem_free(ptr, size) ((void)(size), kfree(ptr))
-
-# ifdef HAVE_KMALLOC_NODE
-# define kmem_alloc_node(size, flags, node) \
- kmalloc_node_nofail((size), (flags), (node))
-# else
-# define kmem_alloc_node(size, flags, node) \
- kmalloc_nofail((size), (flags))
-# endif
-
-# define vmem_alloc(size, flags) __vmalloc((size), ((flags) | \
- __GFP_HIGHMEM), PAGE_KERNEL)
-# define vmem_zalloc(size, flags) \
-({ \
- void *_ptr_ = __vmalloc((size),((flags)|__GFP_HIGHMEM),PAGE_KERNEL); \
- if (_ptr_) \
- memset(_ptr_, 0, (size)); \
- _ptr_; \
-})
-# define vmem_free(ptr, size) ((void)(size), vfree(ptr))
+# define vmem_alloc(sz, fl) vmalloc_nofail((sz), (fl))
+# define vmem_zalloc(sz, fl) vzalloc_nofail((sz), (fl))
+# define vmem_free(ptr, sz) ((void)(sz), vfree(ptr))
#endif /* DEBUG_KMEM */
+extern int kmem_debugging(void);
+extern char *kmem_vasprintf(const char *fmt, va_list ap);
+extern char *kmem_asprintf(const char *fmt, ...);
+extern char *strdup(const char *str);
+extern void strfree(char *str);
+
+
/*
- * Slab allocation interfaces
+ * Slab allocation interfaces. The SPL slab differs from the standard
+ * Linux SLAB or SLUB primarily in that each cache may be backed by slabs
+ * allocated from the physical or virtal memory address space. The virtual
+ * slabs allow for good behavior when allocation large objects of identical
+ * size. This slab implementation also supports both constructors and
+ * destructions which the Linux slab does not.
*/
enum {
KMC_BIT_NOTOUCH = 0, /* Don't update ages */
@@ -246,12 +310,6 @@ enum {
#define KMC_REAP_CHUNK INT_MAX
#define KMC_DEFAULT_SEEKS 1
-extern int kmem_debugging(void);
-extern char *kmem_vasprintf(const char *fmt, va_list ap);
-extern char *kmem_asprintf(const char *fmt, ...);
-#define strfree(str) kfree(str)
-#define strdup(str) kstrdup(str, GFP_KERNEL)
-
extern struct list_head spl_kmem_cache_list;
extern struct rw_semaphore spl_kmem_cache_sem;