#ifndef _SPL_KMEM_H
#define _SPL_KMEM_H
+#include <sys/debug.h>
#include <linux/slab.h>
#include <linux/sched.h>
return (lflags);
}
+typedef struct {
+ struct task_struct *fstrans_thread;
+ unsigned int saved_flags;
+} fstrans_cookie_t;
+
+static inline fstrans_cookie_t
+spl_fstrans_mark(void)
+{
+ fstrans_cookie_t cookie;
+
+ cookie.fstrans_thread = current;
+ cookie.saved_flags = current->flags & PF_FSTRANS;
+ current->flags |= PF_FSTRANS;
+
+ return (cookie);
+}
+
+static inline void
+spl_fstrans_unmark(fstrans_cookie_t cookie)
+{
+ ASSERT3P(cookie.fstrans_thread, ==, current);
+ ASSERT(current->flags & PF_FSTRANS);
+
+ current->flags &= ~(PF_FSTRANS);
+ current->flags |= cookie.saved_flags;
+}
+
+static inline int
+spl_fstrans_check(void)
+{
+ return (current->flags & PF_FSTRANS);
+}
+
#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)
extern vmem_t *zio_arena;
extern size_t vmem_size(vmem_t *vmp, int typemask);
+extern void *spl_vmalloc(unsigned long size, gfp_t lflags, pgprot_t prot);
/*
* Memory allocation interfaces
if (skc->skc_flags & KMC_KMEM)
ptr = (void *)__get_free_pages(lflags, get_order(size));
else
- ptr = __vmalloc(size, lflags | __GFP_HIGHMEM, PAGE_KERNEL);
+ ptr = spl_vmalloc(size, lflags | __GFP_HIGHMEM, PAGE_KERNEL);
/* Resulting allocated memory will be page aligned */
ASSERT(IS_P2ALIGNED(ptr, PAGE_SIZE));
sks = spl_slab_alloc(skc, ska->ska_flags);
memalloc_noio_restore(noio_flag);
#else
+ fstrans_cookie_t cookie = spl_fstrans_mark();
sks = spl_slab_alloc(skc, ska->ska_flags);
+ spl_fstrans_unmark(cookie);
#endif
spin_lock(&skc->skc_lock);
if (sks) {
*/
if (unlikely(size > spl_kmem_alloc_max)) {
if (flags & KM_VMEM) {
- ptr = __vmalloc(size, lflags, PAGE_KERNEL);
+ ptr = spl_vmalloc(size, lflags, PAGE_KERNEL);
} else {
return (NULL);
}
}
EXPORT_SYMBOL(spl_vmem_free);
+/*
+ * Public vmalloc() interface designed to be safe to be called during I/O.
+ */
+void *
+spl_vmalloc(unsigned long size, gfp_t lflags, pgprot_t prot)
+{
+#if defined(PF_MEMALLOC_NOIO)
+ void *ptr;
+ unsigned noio_flag = 0;
+
+ if (spl_fstrans_check())
+ noio_flag = memalloc_noio_save();
+
+ ptr = __vmalloc(size, lflags, prot);
+
+ if (spl_fstrans_check())
+ memalloc_noio_restore(noio_flag);
+
+ return (ptr);
+#else
+ return (__vmalloc(size, lflags, prot));
+#endif
+}
+EXPORT_SYMBOL(spl_vmalloc);
+
int
spl_vmem_init(void)
{