Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 094dd33b authored by Al Viro's avatar Al Viro
Browse files

Merge branch 'vfree' into for-next

parents 59d8053f 32fcfd40
Loading
Loading
Loading
Loading
+40 −5
Original line number Diff line number Diff line
@@ -27,10 +27,30 @@
#include <linux/pfn.h>
#include <linux/kmemleak.h>
#include <linux/atomic.h>
#include <linux/llist.h>
#include <asm/uaccess.h>
#include <asm/tlbflush.h>
#include <asm/shmparam.h>

struct vfree_deferred {
	struct llist_head list;
	struct work_struct wq;
};
static DEFINE_PER_CPU(struct vfree_deferred, vfree_deferred);

static void __vunmap(const void *, int);

static void free_work(struct work_struct *w)
{
	struct vfree_deferred *p = container_of(w, struct vfree_deferred, wq);
	struct llist_node *llnode = llist_del_all(&p->list);
	while (llnode) {
		void *p = llnode;
		llnode = llist_next(llnode);
		__vunmap(p, 1);
	}
}

/*** Page table manipulation functions ***/

static void vunmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end)
@@ -1184,10 +1204,14 @@ void __init vmalloc_init(void)

	for_each_possible_cpu(i) {
		struct vmap_block_queue *vbq;
		struct vfree_deferred *p;

		vbq = &per_cpu(vmap_block_queue, i);
		spin_lock_init(&vbq->lock);
		INIT_LIST_HEAD(&vbq->free);
		p = &per_cpu(vfree_deferred, i);
		init_llist_head(&p->list);
		INIT_WORK(&p->wq, free_work);
	}

	/* Import existing vmlist entries. */
@@ -1520,14 +1544,24 @@ static void __vunmap(const void *addr, int deallocate_pages)
 *	obtained from vmalloc(), vmalloc_32() or __vmalloc(). If @addr is
 *	NULL, no operation is performed.
 *
 *	Must not be called in interrupt context.
 *	Must not be called in NMI context (strictly speaking, only if we don't
 *	have CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG, but making the calling
 *	conventions for vfree() arch-depenedent would be a really bad idea)
 *	
 */
void vfree(const void *addr)
{
	BUG_ON(in_interrupt());
	BUG_ON(in_nmi());

	kmemleak_free(addr);

	if (!addr)
		return;
	if (unlikely(in_interrupt())) {
		struct vfree_deferred *p = &__get_cpu_var(vfree_deferred);
		llist_add((struct llist_node *)addr, &p->list);
		schedule_work(&p->wq);
	} else
		__vunmap(addr, 1);
}
EXPORT_SYMBOL(vfree);
@@ -1545,6 +1579,7 @@ void vunmap(const void *addr)
{
	BUG_ON(in_interrupt());
	might_sleep();
	if (addr)
		__vunmap(addr, 0);
}
EXPORT_SYMBOL(vunmap);