LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Nick Piggin <npiggin@suse.de>
To: akpm@linux-foundation.org, Andrea Arcangeli <andrea@qumranet.com>,
Robin Holt <holt@sgi.com>, Avi Kivity <avi@qumranet.com>,
Izik Eidus <izike@qumranet.com>,
kvm-devel@lists.sourceforge.net,
Peter Zijlstra <a.p.zijlstra@chello.nl>,
general@lists.openfabrics.org,
Steve Wise <swise@opengridcomputing.com>,
Roland Dreier <rdreier@cisco.com>,
Kanoj Sarcar <kanojsarcar@yahoo.com>,
steiner@sgi.com, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, daniel.blueman@quadrics.com,
Christoph Lameter <clameter@sgi.com>
Subject: [patch] my mmu notifier sample driver
Date: Tue, 19 Feb 2008 09:44:50 +0100 [thread overview]
Message-ID: <20080219084450.GB22249@wotan.suse.de> (raw)
In-Reply-To: <20080219084357.GA22249@wotan.suse.de>
Index: linux-2.6/drivers/char/mmu_notifier_skel.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/char/mmu_notifier_skel.c
@@ -0,0 +1,255 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mmu_notifier.h>
+#include <linux/radix-tree.h>
+#include <linux/seqlock.h>
+#include <asm/tlbflush.h>
+
+static DEFINE_SPINLOCK(mmn_lock);
+static RADIX_TREE(rmap_tree, GFP_ATOMIC);
+static seqcount_t rmap_seq = SEQCNT_ZERO;
+
+static int __rmap_add(unsigned long mem, unsigned long vaddr)
+{
+ int err;
+
+ err = radix_tree_insert(&rmap_tree, mem >> PAGE_SHIFT, (void *)vaddr);
+
+ return err;
+}
+
+static void __rmap_del(unsigned long mem)
+{
+ void *ret;
+
+ ret = radix_tree_delete(&rmap_tree, mem >> PAGE_SHIFT);
+ BUG_ON(!ret);
+}
+
+static unsigned long rmap_find(unsigned long mem)
+{
+ unsigned long vaddr;
+
+ rcu_read_lock();
+ vaddr = (unsigned long)radix_tree_lookup(&rmap_tree, mem >> PAGE_SHIFT);
+ rcu_read_unlock();
+
+ return vaddr;
+}
+
+static struct page *follow_page_atomic(struct mm_struct *mm, unsigned long address, int write)
+{
+ struct vm_area_struct *vma;
+
+ vma = find_vma(mm, address);
+ if (!vma || (vma->vm_start > address))
+ return NULL;
+
+ if (vma->vm_flags & (VM_IO | VM_PFNMAP))
+ return NULL;
+
+ return follow_page(vma, address, FOLL_GET|(write ? FOLL_WRITE : 0));
+}
+
+static int mmn_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ unsigned long source_vaddr = (unsigned long)vmf->pgoff << PAGE_SHIFT;
+ unsigned long dest_vaddr = (unsigned long)vmf->virtual_address;
+ unsigned long pfn;
+ struct page *page;
+ pgprot_t prot;
+ int write = vmf->flags & FAULT_FLAG_WRITE;
+ int ret;
+
+ printk("mmn_vm_fault %s@vaddr=%lx sourcing from %lx\n", write ? "write" : "read", dest_vaddr, source_vaddr);
+
+ BUG_ON(mm != current->mm); /* disallow get_user_pages */
+
+again:
+ spin_lock(&mmn_lock);
+ write_seqcount_begin(&rmap_seq);
+ page = follow_page_atomic(mm, source_vaddr, write);
+ if (unlikely(!page)) {
+ write_seqcount_end(&rmap_seq);
+ spin_unlock(&mmn_lock);
+ ret = get_user_pages(current, mm, source_vaddr,
+ 1, write, 0, &page, NULL);
+ if (ret != 1)
+ goto out_err;
+ put_page(page);
+ goto again;
+ }
+
+ ret = __rmap_add(source_vaddr, dest_vaddr);
+ if (ret)
+ goto out_lock;
+
+ pfn = page_to_pfn(page);
+ prot = vma->vm_page_prot;
+ if (!write)
+ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags & ~(VM_WRITE|VM_MAYWRITE));
+ ret = vm_insert_pfn(vma, dest_vaddr, pfn);
+ vma->vm_page_prot = prot;
+ if (ret) {
+ if (ret == -EBUSY)
+ WARN_ON(1);
+ goto out_rmap;
+ }
+ write_seqcount_end(&rmap_seq);
+ spin_unlock(&mmn_lock);
+ put_page(page);
+
+ return VM_FAULT_NOPAGE;
+
+out_rmap:
+ __rmap_del(source_vaddr);
+out_lock:
+ write_seqcount_end(&rmap_seq);
+ spin_unlock(&mmn_lock);
+ put_page(page);
+out_err:
+ switch (ret) {
+ case -EFAULT:
+ case -EEXIST:
+ case -EBUSY:
+ return VM_FAULT_SIGBUS;
+ case -ENOMEM:
+ return VM_FAULT_OOM;
+ default:
+ BUG();
+ }
+}
+
+struct vm_operations_struct mmn_vm_ops = {
+ .fault = mmn_vm_fault,
+};
+
+static int mmu_notifier_busy;
+static struct mmu_notifier mmu_notifier;
+
+static int mmn_clear_young(struct mmu_notifier *mn, unsigned long address)
+{
+ unsigned long vaddr;
+ unsigned seq;
+ struct mm_struct *mm = mn->mm;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ do {
+ seq = read_seqcount_begin(&rmap_seq);
+ vaddr = rmap_find(address);
+ } while (read_seqcount_retry(&rmap_seq, seq));
+
+ if (vaddr == 0)
+ return 0;
+
+ printk("mmn_clear_young@vaddr=%lx sourced from %lx\n", vaddr, address);
+
+ spin_lock(&mmn_lock);
+ pgd = pgd_offset(mm, vaddr);
+ pud = pud_offset(pgd, vaddr);
+ if (pud) {
+ pmd = pmd_offset(pud, vaddr);
+ if (pmd) {
+ ptep = pte_offset_map(pmd, vaddr);
+ if (ptep) {
+ pte = *ptep;
+ if (!pte_present(pte)) {
+ /* x86 specific, don't have a vma */
+ ptep_get_and_clear(mm, vaddr, ptep);
+ __flush_tlb_one(vaddr);
+ }
+ pte_unmap(ptep);
+ }
+ }
+ }
+ __rmap_del(address);
+ spin_unlock(&mmn_lock);
+
+ return 1;
+}
+
+static void mmn_unmap(struct mmu_notifier *mn, unsigned long address)
+{
+ mmn_clear_young(mn, address);
+}
+
+static void mmn_release(struct mmu_notifier *mn)
+{
+ mmu_notifier_busy = 0;
+}
+
+static struct mmu_notifier_operations mmn_ops = {
+ .clear_young = mmn_clear_young,
+ .unmap = mmn_unmap,
+ .release = mmn_release,
+};
+
+static int mmn_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int busy;
+
+ if ((vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE)
+ return -EINVAL;
+
+ spin_lock(&mmn_lock);
+ busy = mmu_notifier_busy;
+ if (!busy)
+ mmu_notifier_busy = 1;
+ spin_unlock(&mmn_lock);
+ if (busy)
+ return -EBUSY;
+
+ vma->vm_flags |= VM_PFNMAP;
+ vma->vm_ops = &mmn_vm_ops;
+
+ mmu_notifier_init(&mmu_notifier, &mmn_ops, current->mm);
+ mmu_notifier_register(&mmu_notifier);
+
+ return 0;
+}
+
+static const struct file_operations mmn_fops =
+{
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .mmap = mmn_mmap,
+};
+
+static struct miscdevice mmn_miscdev =
+{
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mmn",
+ .fops = &mmn_fops
+};
+
+static int __init mmn_init(void)
+{
+ if (misc_register(&mmn_miscdev)) {
+ printk(KERN_ERR "mmn: unable to register device\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static void __exit mmn_exit(void)
+{
+ misc_deregister(&mmn_miscdev);
+}
+
+MODULE_DESCRIPTION("mmu_notifier skeleton driver");
+MODULE_LICENSE("GPL");
+
+module_init(mmn_init);
+module_exit(mmn_exit);
+
Index: linux-2.6/drivers/char/Kconfig
===================================================================
--- linux-2.6.orig/drivers/char/Kconfig
+++ linux-2.6/drivers/char/Kconfig
@@ -4,6 +4,10 @@
menu "Character devices"
+config MMU_NOTIFIER_SKEL
+ tristate "MMU Notifier skeleton driver"
+ default n
+
config VT
bool "Virtual terminal" if EMBEDDED
depends on !S390
Index: linux-2.6/drivers/char/Makefile
===================================================================
--- linux-2.6.orig/drivers/char/Makefile
+++ linux-2.6/drivers/char/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
+obj-$(CONFIG_MMU_NOTIFIER_SKEL) += mmu_notifier_skel.o
obj-$(CONFIG_MWAVE) += mwave/
obj-$(CONFIG_AGP) += agp/
next prev parent reply other threads:[~2008-02-19 8:45 UTC|newest]
Thread overview: 115+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-19 8:43 [patch] my mmu notifiers Nick Piggin
2008-02-19 8:44 ` Nick Piggin [this message]
2008-02-19 11:59 ` Robin Holt
2008-02-19 13:58 ` Andrea Arcangeli
2008-02-19 14:27 ` Jack Steiner
2008-02-19 23:04 ` Nick Piggin
2008-02-20 0:52 ` Andrea Arcangeli
2008-02-20 2:46 ` Robin Holt
2008-02-27 22:50 ` Christoph Lameter
2008-02-19 22:59 ` Nick Piggin
2008-02-20 0:46 ` Andrea Arcangeli
2008-02-27 22:55 ` Christoph Lameter
2008-02-19 23:11 ` Nick Piggin
2008-02-19 23:40 ` Jack Steiner
2008-02-21 4:42 ` Nick Piggin
2008-02-22 16:31 ` Jack Steiner
2008-02-20 1:09 ` Andrea Arcangeli
2008-02-20 10:39 ` [PATCH] mmu notifiers #v6 Andrea Arcangeli
2008-02-20 10:45 ` [PATCH] KVM swapping (+ seqlock fix) with " Andrea Arcangeli
2008-02-27 22:06 ` [PATCH] KVM swapping with mmu notifiers #v7 Andrea Arcangeli
2008-02-28 8:42 ` izik eidus
2008-02-20 11:33 ` [PATCH] mmu notifiers #v6 Robin Holt
2008-02-20 12:03 ` Andrea Arcangeli
2008-02-20 12:24 ` Robin Holt
2008-02-20 12:32 ` Andrea Arcangeli
2008-02-20 13:15 ` Robin Holt
2008-02-21 5:02 ` Nick Piggin
2008-02-20 14:41 ` Robin Holt
2008-02-20 15:34 ` Andrea Arcangeli
2008-02-20 21:03 ` Jack Steiner
2008-02-21 4:54 ` Nick Piggin
2008-02-21 14:40 ` Andrea Arcangeli
2008-02-21 16:10 ` Jack Steiner
2008-02-27 19:26 ` [PATCH] mmu notifiers #v7 Andrea Arcangeli
2008-02-27 20:04 ` Peter Zijlstra
2008-02-27 23:06 ` Christoph Lameter
2008-02-27 23:43 ` [kvm-devel] " Andrea Arcangeli
2008-02-28 0:08 ` Christoph Lameter
2008-02-28 0:21 ` Andrea Arcangeli
2008-02-28 0:24 ` Christoph Lameter
2008-02-28 19:48 ` Christoph Lameter
2008-02-28 21:52 ` Andrea Arcangeli
2008-02-28 22:00 ` Christoph Lameter
2008-02-28 23:17 ` Jack Steiner
2008-02-29 0:24 ` Andrea Arcangeli
2008-02-29 1:13 ` Christoph Lameter
2008-02-28 23:05 ` Christoph Lameter
2008-02-29 0:40 ` Andrea Arcangeli
2008-02-29 0:56 ` Andrew Morton
2008-02-29 1:03 ` Christoph Lameter
2008-02-29 13:09 ` Andrea Arcangeli
2008-02-29 19:46 ` Christoph Lameter
2008-03-02 15:54 ` [PATCH] mmu notifiers #v8 Andrea Arcangeli
2008-03-02 16:03 ` [PATCH] mmu notifiers #v8 + xpmem Andrea Arcangeli
2008-03-02 16:23 ` Peter Zijlstra
2008-03-03 3:29 ` [PATCH] mmu notifiers #v8 Nick Piggin
2008-03-03 12:51 ` Andrea Arcangeli
2008-03-03 13:10 ` Nick Piggin
2008-03-03 13:24 ` Andrea Arcangeli
2008-03-03 15:18 ` Jack Steiner
2008-03-03 16:59 ` Nick Piggin
2008-03-03 18:06 ` Jack Steiner
2008-03-03 18:09 ` Avi Kivity
2008-03-03 18:23 ` Jack Steiner
2008-03-03 18:45 ` Nick Piggin
2008-03-03 19:15 ` Jack Steiner
2008-03-04 10:35 ` Peter Zijlstra
2008-03-04 14:44 ` Jack Steiner
2008-03-03 19:02 ` Christoph Lameter
2008-03-03 19:01 ` Christoph Lameter
2008-03-03 21:15 ` Andrea Arcangeli
2008-03-05 0:37 ` Nick Piggin
2008-03-05 18:48 ` Christoph Lameter
2008-03-06 2:59 ` Nick Piggin
2008-03-03 3:33 ` Nick Piggin
2008-03-03 19:03 ` Christoph Lameter
2008-03-03 3:34 ` Nick Piggin
2008-03-03 19:04 ` Christoph Lameter
2008-03-03 3:39 ` Nick Piggin
2008-03-03 21:37 ` [PATCH] mmu notifiers #v9 Andrea Arcangeli
2008-03-03 22:05 ` [PATCH] KVM swapping with " Andrea Arcangeli
2008-03-04 0:44 ` izik eidus
2008-03-04 7:31 ` [RFC] Notifier for Externally Mapped Memory (EMM) Christoph Lameter
2008-03-04 7:34 ` [Early draft] Conversion of i_mmap_lock to semaphore Christoph Lameter
2008-03-04 13:30 ` [RFC] Notifier for Externally Mapped Memory (EMM) Andrea Arcangeli
2008-03-04 19:00 ` Christoph Lameter
2008-03-04 22:20 ` Andrea Arcangeli
2008-03-04 22:35 ` Christoph Lameter
2008-03-04 22:42 ` Peter Zijlstra
2008-03-04 23:14 ` Christoph Lameter
2008-03-04 23:25 ` Peter Zijlstra
2008-03-04 23:30 ` Peter Zijlstra
2008-03-05 5:09 ` Avi Kivity
2008-03-05 9:47 ` Robin Holt
2008-03-05 9:53 ` Avi Kivity
2008-03-05 10:02 ` [kvm-devel] " Dor Laor
2008-03-07 15:17 ` [PATCH] 2/4 move all invalidate_page outside of PT lock (#v9 was 1/4) Andrea Arcangeli
2008-03-07 15:23 ` [PATCH] 3/4 combine RCU with seqlock to allow mmu notifier methods to sleep " Andrea Arcangeli
2008-03-07 15:52 ` [PATCH] 4/4 i_mmap_lock spinlock2rwsem " Andrea Arcangeli
2008-03-07 20:03 ` Christoph Lameter
2008-03-19 21:27 ` Christoph Lameter
2008-03-07 16:52 ` [PATCH] 3/4 combine RCU with seqlock to allow mmu notifier methods to sleep " Peter Zijlstra
2008-03-07 17:50 ` Andrea Arcangeli
2008-03-07 18:01 ` Peter Zijlstra
2008-03-07 18:45 ` Andrea Arcangeli
2008-03-07 19:47 ` Andrea Arcangeli
2008-03-07 20:15 ` Christoph Lameter
2008-03-07 20:12 ` Christoph Lameter
2008-03-07 20:10 ` Christoph Lameter
2008-03-07 20:00 ` Christoph Lameter
2008-03-07 19:54 ` [PATCH] 2/4 move all invalidate_page outside of PT lock " Christoph Lameter
2008-03-04 13:21 ` [PATCH] KVM swapping with mmu notifiers #v9 Andrea Arcangeli
2008-02-21 4:47 ` [patch] my mmu notifiers Nick Piggin
2008-02-20 2:49 ` Robin Holt
2008-02-27 22:56 ` Christoph Lameter
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=20080219084450.GB22249@wotan.suse.de \
--to=npiggin@suse.de \
--cc=a.p.zijlstra@chello.nl \
--cc=akpm@linux-foundation.org \
--cc=andrea@qumranet.com \
--cc=avi@qumranet.com \
--cc=clameter@sgi.com \
--cc=daniel.blueman@quadrics.com \
--cc=general@lists.openfabrics.org \
--cc=holt@sgi.com \
--cc=izike@qumranet.com \
--cc=kanojsarcar@yahoo.com \
--cc=kvm-devel@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=rdreier@cisco.com \
--cc=steiner@sgi.com \
--cc=swise@opengridcomputing.com \
--subject='Re: [patch] my mmu notifier sample driver' \
/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
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).