linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Changli Gao <xiaosuo@gmail.com>
To: akpm@linux-foundation.org
Cc: Eric Dumazet <eric.dumazet@gmail.com>,
	Jiri Slaby <jslaby@suse.cz>, Changli Gao <xiaosuo@gmail.com>,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>,
	Alexey Dobriyan <adobriyan@gmail.com>,
	Ingo Molnar <mingo@elte.hu>,
	Peter Zijlstra <peterz@infradead.org>,
	linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
	Avi Kivity <avi@redhat.com>,
	Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Subject: [RFC] mm: generic adaptive large memory allocation APIs
Date: Thu,  6 May 2010 08:30:38 +0800	[thread overview]
Message-ID: <1273105838-4441-1-git-send-email-xiaosuo@gmail.com> (raw)

kvmalloc() will try to allocate physically contiguous memory first, and try 
vmalloc to allocate virtually contiguous memory when the former allocation
fails.

kvfree() is used to free the memory allocated by kvmalloc(). It can't be used
in atomic context. If the callers are in atomic contex, they can use
kvfree_inatomic() instead.

There is much duplicate code to do such things in kernel, so I generate the
above APIs.

Thank Eric Dumazet for the "kv" prefix. :)

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>

void *kvmalloc(size_t size)
{
	void *ptr;

	if (size < PAGE_SIZE)
		return kmalloc(PAGE_SIZE, GFP_KERNEL);
	ptr = alloc_pages_exact(size, GFP_KERNEL | __GFP_NOWARN);
	if (ptr != NULL)
		return ptr;

	return vmalloc(size);
}
EXPORT_SYMBOL(kvmalloc);

void kvfree(void *ptr, size_t size)
{
	if (size < PAGE_SIZE)
		kfree(ptr);
	else if (is_vmalloc_addr(ptr))
		vfree(ptr);
	else
		free_pages_exact(ptr, size);
}
EXPORT_SYMBOL(kvfree);

struct kvfree_work_struct {
	struct work_struct	work;
	void			*head;
	void			**ptail;
};

DEFINE_PER_CPU(struct kvfree_work_struct, kvfree_work_struct);

static void kvfree_work(struct work_struct *_work)
{
	struct kvfree_work_struct *work;
	void *head, *tmp;
	
	work = container_of(_work, struct kvfree_work_struct, work);
	local_bh_disable();
	head = work->head;
	work->head = NULL;
	work->ptail = &work->head;
	local_bh_enable();

	while (head) {
		tmp = head;
		head = *(void **)head;
		vfree(tmp);
	}
}

void kvfree_inatomic(void *ptr, size_t size)
{
	if (size < PAGE_SIZE) {
		kfree(ptr);
	} else if (is_vmalloc_addr(ptr)) {
		struct kvfree_work_struct *work;

		*(void **)ptr = NULL;
		local_irq_disable();
		work = this_cpu_ptr(&kvfree_work_struct);
		*(work->ptail) = ptr;
		work->ptail = (void**)ptr;
		schedule_work(&work->work);
		local_irq_enable();
	} else {
		free_pages_exact(ptr, size);
	}
}
EXPORT_SYMBOL(kvfree_inatomic);

static int kvfree_work_struct_init(void)
{
	int cpu;
	struct kvfree_work_struct *work;

	for_each_possible_cpu(cpu) {
		work = per_cpu_ptr(&kvfree_work_struct, cpu);
		INIT_WORK(&work->work, kvfree_work);
		work->head = NULL;
		work->ptail = &work->head;
	}

	return 0;
}
//pure_initcall(kvfree_work_struct_init);

//--------------------
// for testing
static int test_init(void)
{
	int size;
	void *ptr;

	kvfree_work_struct_init();
	for (size = 1; size < (1<<30); size <<= 1) {
		ptr = kvmalloc(size);
		if (is_vmalloc_addr(ptr)) {
			printk("%d\n", size);
			break;
		}
		kvfree(ptr, size);
	}

	return 0;
}
module_init(test_init);

static void test_exit(void)
{
	int cpu;
	struct kvfree_work_struct *work;

	for_each_possible_cpu(cpu) {
		work = per_cpu_ptr(&kvfree_work_struct, cpu);
		cancel_work_sync(&work->work);
	}
}
module_exit(test_exit);

MODULE_LICENSE("GPL");

             reply	other threads:[~2010-05-06  0:30 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-06  0:30 Changli Gao [this message]
2010-05-06  0:37 ` [RFC] mm: generic adaptive large memory allocation APIs Changli Gao
2010-05-06  1:25 ` Changli Gao
2010-05-06  3:12 ` Tetsuo Handa
2010-05-06  3:22   ` Changli Gao
2010-05-06 15:35 ` Jamie Lokier
2010-05-07  4:32 ` Changli Gao
2010-05-07 12:42   ` Tetsuo Handa
2010-05-07 12:52     ` Peter Zijlstra
2010-05-13  4:45 ` KOSAKI Motohiro
2010-05-13  8:43   ` Jiri Slaby
2010-05-13  9:05     ` KOSAKI Motohiro
2010-05-13  9:19       ` Jiri Slaby
2010-05-13  9:40         ` KOSAKI Motohiro
2010-05-13 10:16           ` Jiri Slaby
2010-05-13 10:43             ` KOSAKI Motohiro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1273105838-4441-1-git-send-email-xiaosuo@gmail.com \
    --to=xiaosuo@gmail.com \
    --cc=adobriyan@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=avi@redhat.com \
    --cc=eric.dumazet@gmail.com \
    --cc=jslaby@suse.cz \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=paulmck@linux.vnet.ibm.com \
    --cc=penguin-kernel@i-love.sakura.ne.jp \
    --cc=peterz@infradead.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).