From: Christoph Lameter <clameter@sgi.com>
To: akpm@linux-foundation.org
Cc: Andrea Arcangeli <andrea@qumranet.com>
Cc: Robin Holt <holt@sgi.com>, Avi Kivity <avi@qumranet.com>,
Izik Eidus <izike@qumranet.com>
Cc: kvm-devel@lists.sourceforge.net
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: steiner@sgi.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org
Cc: daniel.blueman@quadrics.com
Subject: [patch 6/6] mmu_rmap_notifier: Skeleton for complex driver that uses its own rmaps
Date: Fri, 08 Feb 2008 14:06:22 -0800 [thread overview]
Message-ID: <20080208220657.029243317@sgi.com> (raw)
In-Reply-To: 20080208220616.089936205@sgi.com
[-- Attachment #1: mmu_rmap_skeleton --]
[-- Type: text/plain, Size: 7832 bytes --]
The skeleton for the rmap notifier leaves the invalidate_page method of
the mmu_notifier empty and hooks a new invalidate_page callback into the
global chain for mmu_rmap_notifiers.
There are seveal simplifications in here to avoid making this too complex.
The reverse maps need to consit of references to vma f.e.
Signed-off-by: Christoph Lameter <clameter@sgi.com>
---
Documentation/mmu_notifier/skeleton_rmap.c | 265 +++++++++++++++++++++++++++++
1 file changed, 265 insertions(+)
Index: linux-2.6/Documentation/mmu_notifier/skeleton_rmap.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/Documentation/mmu_notifier/skeleton_rmap.c 2008-02-08 13:25:28.000000000 -0800
@@ -0,0 +1,265 @@
+#include <linux/mm.h>
+#include <linux/mmu_notifier.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+
+/*
+ * Skeleton for an mmu notifier with rmap callbacks and sleeping during
+ * invalidate_page.
+ *
+ * (C) 2008 Silicon Graphics, Inc.
+ * Christoph Lameter <clameter@sgi.com>
+ *
+ * Note that the locking is fairly basic. One can add various optimizations
+ * here and there. There is a single lock for an address space which should be
+ * satisfactory for most cases. If not then the lock can be split like the
+ * pte_lock in Linux. It is most likely best to place the locks in the
+ * page table structure or into whatever the external mmu uses to
+ * track the mappings.
+ */
+
+struct my_mmu {
+ /* MMU notifier specific fields */
+ struct mmu_notifier notifier;
+ spinlock_t lock; /* Protects counter and invidual zaps */
+ int invalidates; /* Number of active range_invalidate */
+
+ /* Rmap support */
+ struct list_head list; /* rmap list of my_mmu structs */
+ unsigned long base;
+};
+
+/*
+ * Called with m->lock held
+ */
+static void my_mmu_insert_page(struct my_mmu *m,
+ unsigned long address, unsigned long pfn)
+{
+ /* Must be provided */
+ printk(KERN_INFO "insert page %p address=%lx pfn=%ld\n",
+ m, address, pfn);
+}
+
+/*
+ * Called with m->lock held
+ */
+static void my_mmu_zap_range(struct my_mmu *m,
+ unsigned long start, unsigned long end, int atomic)
+{
+ /* Must be provided */
+ printk(KERN_INFO "zap range %p address=%lx-%lx atomic=%d\n",
+ m, start, end, atomic);
+}
+
+/*
+ * Called with m->lock held (optional but usually required to
+ * protect data structures of the driver).
+ */
+static void my_mmu_zap_page(struct my_mmu *m, unsigned long address)
+{
+ /* Must be provided */
+ printk(KERN_INFO "zap page %p address=%lx\n", m, address);
+}
+
+/*
+ * Increment and decrement of the number of range invalidates
+ */
+static inline void inc_active(struct my_mmu *m)
+{
+ spin_lock(&m->lock);
+ m->invalidates++;
+ spin_unlock(&m->lock);
+}
+
+static inline void dec_active(struct my_mmu *m)
+{
+ spin_lock(&m->lock);
+ m->invalidates--;
+ spin_unlock(&m->lock);
+}
+
+static void my_mmu_invalidate_range_begin(struct mmu_notifier *mn,
+ struct mm_struct *mm, unsigned long start, unsigned long end,
+ int atomic)
+{
+ struct my_mmu *m = container_of(mn, struct my_mmu, notifier);
+
+ inc_active(m); /* Holds off new references */
+ my_mmu_zap_range(m, start, end, atomic);
+}
+
+static void my_mmu_invalidate_range_end(struct mmu_notifier *mn,
+ struct mm_struct *mm, unsigned long start, unsigned long end,
+ int atomic)
+{
+ struct my_mmu *m = container_of(mn, struct my_mmu, notifier);
+
+ dec_active(m); /* Enables new references */
+}
+
+/*
+ * Populate a page.
+ *
+ * A return value of-EAGAIN means please retry this operation.
+ *
+ * Acuisition of mmap_sem can be omitted if the caller already holds
+ * the semaphore.
+ */
+struct page *my_mmu_populate_page(struct my_mmu *m,
+ struct vm_area_struct *vma,
+ unsigned long address, int write)
+{
+ struct page *page = ERR_PTR(-EAGAIN);
+ int err;
+
+ /*
+ * No need to do anything if a range invalidate is running
+ * Could use a wait queue here to avoid returning -EAGAIN.
+ */
+ if (m->invalidates)
+ goto out;
+
+ down_read(&vma->vm_mm->mmap_sem);
+ err = get_user_pages(current, vma->vm_mm, address, 1,
+ write, 1, &page, NULL);
+
+ up_read(&vma->vm_mm->mmap_sem);
+ if (err < 0) {
+ page = ERR_PTR(err);
+ goto out;
+ }
+ lock_page(page);
+
+ /*
+ * The page is now locked and we are holding a refcount on it.
+ * So things are tied down. Now we can check the page status.
+ */
+ if (page_mapped(page)) {
+ /* Could do some preprocessing here. Can sleep */
+ spin_lock(&m->lock);
+ if (!m->invalidates)
+ my_mmu_insert_page(m, address, page_to_pfn(page));
+ spin_unlock(&m->lock);
+ /* Could do some postprocessing here. Can sleep */
+ }
+ unlock_page(page);
+ put_page(page);
+out:
+ return page;
+}
+
+/*
+ * All other threads accessing this mm_struct must have terminated by now.
+ */
+static void my_mmu_release(struct mmu_notifier *mn, struct mm_struct *mm)
+{
+ struct my_mmu *m = container_of(mn, struct my_mmu, notifier);
+
+ my_mmu_zap_range(m, 0, TASK_SIZE, 0);
+ /* No concurrent processes thus no worries about RCU */
+ list_del(&m->list);
+ kfree(m);
+ printk(KERN_INFO "MMU Notifier terminating\n");
+}
+
+static struct mmu_notifier_ops my_mmu_ops = {
+ my_mmu_release,
+ NULL, /* No aging function */
+ NULL, /* No atomic invalidate_page function */
+ my_mmu_invalidate_range_begin,
+ my_mmu_invalidate_range_end
+};
+
+/* Rmap specific fields */
+static LIST_HEAD(my_mmu_list);
+static struct rw_semaphore listlock;
+
+/*
+ * This function must be called to activate callbacks from a process
+ */
+int my_mmu_attach_to_process(struct mm_struct *mm)
+{
+ struct my_mmu *m = kzalloc(sizeof(struct my_mmu), GFP_KERNEL);
+
+ if (!m)
+ return -ENOMEM;
+
+ m->notifier.ops = &my_mmu_ops;
+ spin_lock_init(&m->lock);
+
+ /*
+ * mmap_sem handling can be omitted if it is guaranteed that
+ * the context from which my_mmu_attach_to_process is called
+ * is already holding a writelock on mmap_sem.
+ */
+ down_write(&mm->mmap_sem);
+ mmu_notifier_register(&m->notifier, mm);
+ up_write(&mm->mmap_sem);
+ down_write(&listlock);
+ list_add(&m->list, &my_mmu_list);
+ up_write(&listlock);
+
+ /*
+ * RCU sync is expensive but necessary if we need to guarantee
+ * that multiple threads running on other cpus have seen the
+ * notifier changes.
+ */
+ synchronize_rcu();
+ return 0;
+}
+
+
+static void my_sleeping_invalidate_page(struct my_mmu *m, unsigned long address)
+{
+ /* Must be provided */
+ spin_lock(&m->lock); /* Only taken to ensure mmu data integrity */
+ my_mmu_zap_page(m, address);
+ spin_unlock(&m->lock);
+ printk(KERN_INFO "Sleeping invalidate_page %p address=%lx\n",
+ m, address);
+}
+
+static unsigned long my_mmu_find_addr(struct my_mmu *m, struct page *page)
+{
+ /* Determine the address of a page in a mmu segment */
+ return -EFAULT;
+}
+
+/*
+ * A reference must be held on the page passed and the page passed
+ * must be locked. No spinlocks are held. invalidate_page() is held
+ * off by us holding the page lock.
+ */
+static void my_mmu_rmap_invalidate_page(struct mmu_rmap_notifier *mrn,
+ struct page *page)
+{
+ struct my_mmu *m;
+
+ BUG_ON(!PageLocked(page));
+ down_read(&listlock);
+ list_for_each_entry(m, &my_mmu_list, list) {
+ unsigned long address = my_mmu_find_addr(m, page);
+
+ if (address != -EFAULT)
+ my_sleeping_invalidate_page(m, address);
+ }
+ up_read(&listlock);
+}
+
+static struct mmu_rmap_notifier_ops my_mmu_rmap_ops = {
+ .invalidate_page = my_mmu_rmap_invalidate_page
+};
+
+static struct mmu_rmap_notifier my_mmu_rmap_notifier = {
+ .ops = &my_mmu_rmap_ops
+};
+
+static int __init my_mmu_init(void)
+{
+ mmu_rmap_notifier_register(&my_mmu_rmap_notifier);
+ return 0;
+}
+
+late_initcall(my_mmu_init);
+
--
next prev parent reply other threads:[~2008-02-08 22:07 UTC|newest]
Thread overview: 82+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-08 22:06 [patch 0/6] MMU Notifiers V6 Christoph Lameter
2008-02-08 22:06 ` [patch 1/6] mmu_notifier: Core code Christoph Lameter
2008-02-08 22:06 ` [patch 2/6] mmu_notifier: Callbacks to invalidate address ranges Christoph Lameter
2008-02-08 22:06 ` [patch 3/6] mmu_notifier: invalidate_page callbacks Christoph Lameter
2008-02-08 22:06 ` [patch 4/6] mmu_notifier: Skeleton driver for a simple mmu_notifier Christoph Lameter
2008-02-08 22:06 ` [patch 5/6] mmu_notifier: Support for drivers with revers maps (f.e. for XPmem) Christoph Lameter
2008-02-08 22:06 ` Christoph Lameter [this message]
2008-02-08 22:23 ` [patch 0/6] MMU Notifiers V6 Andrew Morton
2008-02-08 23:32 ` Christoph Lameter
2008-02-08 23:36 ` Robin Holt
2008-02-08 23:41 ` Christoph Lameter
2008-02-08 23:43 ` Robin Holt
2008-02-08 23:56 ` Andrew Morton
2008-02-09 0:05 ` Christoph Lameter
2008-02-09 0:12 ` [ofa-general] " Roland Dreier
2008-02-09 0:16 ` Christoph Lameter
2008-02-09 0:22 ` Roland Dreier
2008-02-09 0:36 ` Christoph Lameter
2008-02-09 1:24 ` Andrea Arcangeli
2008-02-09 1:27 ` Christoph Lameter
2008-02-09 1:56 ` Andrea Arcangeli
2008-02-09 2:16 ` Christoph Lameter
2008-02-09 12:55 ` Rik van Riel
2008-02-09 21:46 ` Christoph Lameter
2008-02-11 22:40 ` Demand paging for memory regions (was Re: MMU Notifiers V6) Roland Dreier
2008-02-12 22:01 ` Steve Wise
2008-02-12 22:10 ` Christoph Lameter
2008-02-12 22:41 ` [ofa-general] Re: Demand paging for memory regions Roland Dreier
2008-02-12 23:14 ` Felix Marti
2008-02-13 0:57 ` Christoph Lameter
2008-02-14 15:09 ` Steve Wise
2008-02-14 15:53 ` Robin Holt
2008-02-14 16:23 ` Steve Wise
2008-02-14 17:48 ` Caitlin Bestler
2008-02-14 19:39 ` Christoph Lameter
2008-02-14 20:17 ` Caitlin Bestler
2008-02-14 20:20 ` Christoph Lameter
2008-02-14 22:43 ` Caitlin Bestler
2008-02-14 22:48 ` Christoph Lameter
2008-02-15 1:26 ` Caitlin Bestler
2008-02-15 2:37 ` Christoph Lameter
2008-02-15 18:09 ` Caitlin Bestler
2008-02-15 18:45 ` Christoph Lameter
2008-02-15 18:53 ` Caitlin Bestler
2008-02-15 20:02 ` Christoph Lameter
2008-02-15 20:14 ` Caitlin Bestler
2008-02-15 22:50 ` Christoph Lameter
2008-02-15 23:50 ` Caitlin Bestler
2008-02-12 23:23 ` Jason Gunthorpe
2008-02-13 1:01 ` Christoph Lameter
2008-02-13 1:26 ` Jason Gunthorpe
2008-02-13 1:45 ` Steve Wise
2008-02-13 2:35 ` Christoph Lameter
2008-02-13 3:25 ` Jason Gunthorpe
2008-02-13 3:56 ` Patrick Geoffray
2008-02-13 4:26 ` Jason Gunthorpe
2008-02-13 4:47 ` Patrick Geoffray
2008-02-13 18:51 ` Christoph Lameter
2008-02-13 19:51 ` Jason Gunthorpe
2008-02-13 20:36 ` Christoph Lameter
2008-02-13 4:09 ` Christian Bell
2008-02-13 19:00 ` Christoph Lameter
2008-02-13 19:46 ` Christian Bell
2008-02-13 20:32 ` Christoph Lameter
2008-02-13 22:44 ` Kanoj Sarcar
2008-02-13 23:02 ` Christoph Lameter
2008-02-13 23:43 ` Kanoj Sarcar
2008-02-13 23:48 ` Jesse Barnes
2008-02-14 0:56 ` [ofa-general] " Andrea Arcangeli
2008-02-14 19:35 ` Christoph Lameter
2008-02-13 23:23 ` Pete Wyckoff
2008-02-14 0:01 ` Jason Gunthorpe
2008-02-27 22:11 ` Christoph Lameter
2008-02-13 1:55 ` Christian Bell
2008-02-13 2:19 ` Christoph Lameter
2008-02-13 0:56 ` Christoph Lameter
2008-02-13 12:11 ` Christoph Raisch
2008-02-13 19:02 ` Christoph Lameter
2008-02-09 0:12 ` [patch 0/6] MMU Notifiers V6 Andrew Morton
2008-02-09 0:18 ` Christoph Lameter
2008-02-13 14:31 ` Jack Steiner
-- strict thread matches above, loose matches on Subject: below --
2008-02-15 6:48 [patch 0/6] MMU Notifiers V7 Christoph Lameter
2008-02-15 6:49 ` [patch 6/6] mmu_rmap_notifier: Skeleton for complex driver that uses its own rmaps 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=20080208220657.029243317@sgi.com \
--to=clameter@sgi.com \
--cc=akpm@linux-foundation.org \
--cc=andrea@qumranet.com \
/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