From: Alexey Korolev <akorolev@infradead.org>
To: mel@csn.ul.ie, linux-mm@kvack.org
Subject: HugeTLB mapping for drivers (sample driver)
Date: Tue, 14 Jul 2009 03:07:47 +0100 (BST) [thread overview]
Message-ID: <alpine.LFD.2.00.0907140258100.25576@casper.infradead.org> (raw)
Hi,
This is a sample driver which provides huge page mapping to user space.
It might be useful for understanding purposes.
Here we defined file operations for device driver.
We must call htlbfs get_unmapped_area and hugetlbfs_file_mmap functions to
done some HTLB mapping preparations. (If proposed approach is more
or less Ok, it will be more accurate to avoid hugetlbfs calls at all - and
substitute them with htlb functions).
Allocated page get assiciated with mapping via add_to_page_cache call in
file->open.
---
diff -Naurp empty/hpage_map.c hpage_map/hpage_map.c
--- empty/hpage_map.c 1970-01-01 12:00:00.000000000 +1200
+++ hpage_map/hpage_map.c 2009-07-13 18:40:28.000000000 +1200
@@ -0,0 +1,137 @@
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/pagemap.h>
+#include <linux/hugetlb.h>
+#include <linux/pagevec.h>
+#include <linux/miscdevice.h>
+
+static void make_file_empty(struct file *file)
+{
+ struct address_space *mapping = file->f_mapping;
+ struct pagevec pvec;
+ pgoff_t next = 0;
+ int i;
+
+ pagevec_init(&pvec, 0);
+ while (1) {
+ if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
+ if (!next)
+ break;
+ next = 0;
+ continue;
+ }
+
+ for (i = 0; i < pagevec_count(&pvec); ++i) {
+ struct page *page = pvec.pages[i];
+
+ lock_page(page);
+ if (page->index > next)
+ next = page->index;
+ ++next;
+ remove_from_page_cache(page);
+ unlock_page(page);
+ hugetlb_free_pages(page);
+ }
+ }
+ BUG_ON(mapping->nrpages);
+}
+
+
+static int hpage_map_mmap(struct file *file, struct vm_area_struct
*vma)
+{
+ unsigned long idx;
+ struct address_space *mapping;
+ int ret = VM_FAULT_SIGBUS;
+
+ idx = vma->vm_pgoff >> huge_page_order(h);
+ mapping = file->f_mapping;
+ ret = hugetlbfs_file_mmap(file, vma);
+
+ return ret;
+}
+
+
+static unsigned long hpage_map_get_unmapped_area(struct file *file,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ return hugetlb_get_unmapped_area(file, addr, len, pgoff, flags);
+}
+
+static int hpage_map_open(struct inode * inode, struct file * file)
+{
+ struct page *page;
+ int num_hpages = 10, cnt = 0;
+ int ret = 0;
+
+ /* Announce hugetlb file mapping */
+ mapping_set_hugetlb(file->f_mapping);
+
+ for (cnt = 0; cnt < num_hpages; cnt++ ) {
+ page = hugetlb_alloc_pages_node(0,GFP_KERNEL);
+ if (IS_ERR(page)) {
+ ret = -PTR_ERR(page);
+ goto out_err;
+ }
+ ret = add_to_page_cache(page, file->f_mapping, cnt, GFP_KERNEL);
+ if (ret) {
+ hugetlb_free_pages(page);
+ goto out_err;
+ }
+ SetPageUptodate(page);
+ unlock_page(page);
+ }
+ return 0;
+out_err:
+ printk(KERN_ERR"%s : Error %d \n",__func__, ret);
+ make_file_empty(file);
+ return ret;
+}
+
+
+static int hpage_map_release(struct inode * inode, struct file * file)
+{
+ make_file_empty(file);
+ return 0;
+}
+/*
+ * The file operations for /dev/hpage_map
+ */
+static const struct file_operations hpage_map_fops = {
+ .owner = THIS_MODULE,
+ .mmap = hpage_map_mmap,
+ .open = hpage_map_open,
+ .release = hpage_map_release,
+ .get_unmapped_area = hpage_map_get_unmapped_area,
+};
+
+static struct miscdevice hpage_map_dev = {
+ MISC_DYNAMIC_MINOR,
+ "hpage_map",
+ &hpage_map_fops
+};
+
+static int __init
+hpage_map_init(void)
+{
+ /* Create the device in the /sys/class/misc directory. */
+ if (misc_register(&hpage_map_dev))
+ return -EIO;
+ return 0;
+}
+
+module_init(hpage_map_init);
+
+static void __exit
+hpage_map_exit(void)
+{
+ misc_deregister(&hpage_map_dev);
+}
+
+module_exit(hpage_map_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexey Korolev");
+MODULE_DESCRIPTION("Example of driver with hugetlb mapping");
+MODULE_VERSION("1.0");
diff -Naurp empty/Makefile hpage_map/Makefile
--- empty/Makefile 1970-01-01 12:00:00.000000000 +1200
+++ hpage_map/Makefile 2009-07-13 18:31:27.000000000 +1200
@@ -0,0 +1,7 @@
+obj-m := hpage_map.o
+
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+default:
+ $(MAKE) -C $(KDIR) M=$(PWD) modules
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next reply other threads:[~2009-07-14 1:40 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-07-14 2:07 Alexey Korolev [this message]
2009-07-14 10:27 ` Mel Gorman
2009-07-15 0:08 ` Alexey Korolev
2009-07-19 13:39 ` Alexey Korolev
2009-07-20 8:11 ` Mel Gorman
2009-07-21 9:32 ` Alexey Korolev
2009-07-21 9:40 ` Mel Gorman
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=alpine.LFD.2.00.0907140258100.25576@casper.infradead.org \
--to=akorolev@infradead.org \
--cc=linux-mm@kvack.org \
--cc=mel@csn.ul.ie \
/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