From: <graff.yang@gmail.com>
To: dhowells@redhat.com, tj@kernel.org, linux-kernel@vger.kernel.org
Cc: akpm@linux-foundation.org,
uclinux-dist-devel@blackfin.uclinux.org,
Graff Yang <graff.yang@gmail.com>
Subject: [PATCH] mm/nommu.c:Dynamic alloc/free percpu area for nommu
Date: Fri, 19 Mar 2010 17:02:04 +0800 [thread overview]
Message-ID: <1268989324-7575-1-git-send-email-graff.yang@gmail.com> (raw)
From: Graff Yang <graff.yang@gmail.com>
This patch supports dynamic alloc/free percpu area for nommu arch like
blackfin.
It allocates contiguous pages in funtion pcpu_get_vm_areas() instead of
getting none contiguous pages then vmap it in mmu arch.
As we can not get the real page structure through vmalloc_to_page(), so
it also modified the nommu version vmalloc_to_page()/vmalloc_to_pfn().
Signed-off-by: Graff Yang <graff.yang@gmail.com>
---
mm/nommu.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 112 insertions(+), 2 deletions(-)
diff --git a/mm/nommu.c b/mm/nommu.c
index 605ace8..98bbdf4 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -255,13 +255,15 @@ EXPORT_SYMBOL(vmalloc_user);
struct page *vmalloc_to_page(const void *addr)
{
- return virt_to_page(addr);
+ return (struct page *)
+ (virt_to_page(addr)->index) ? : virt_to_page(addr);
}
EXPORT_SYMBOL(vmalloc_to_page);
unsigned long vmalloc_to_pfn(const void *addr)
{
- return page_to_pfn(virt_to_page(addr));
+ return page_to_pfn((struct page *)
+ (virt_to_page(addr)->index) ? : virt_to_page(addr));
}
EXPORT_SYMBOL(vmalloc_to_pfn);
@@ -2000,3 +2002,111 @@ int nommu_shrink_inode_mappings(struct inode *inode, size_t size,
up_write(&nommu_region_sem);
return 0;
}
+
+#ifdef CONFIG_SMP
+int map_kernel_range_noflush(unsigned long addr, unsigned long size,
+ pgprot_t prot, struct page **pages)
+{
+ int i, nr_page = size >> PAGE_SHIFT;
+ for (i = 0; i < nr_page; i++, addr += PAGE_SIZE)
+ virt_to_page(addr)->index = (pgoff_t)pages[i];
+ return size >> PAGE_SHIFT;
+}
+
+void unmap_kernel_range_noflush(unsigned long addr, unsigned long size)
+{
+ int i, nr_page = size >> PAGE_SHIFT;
+ for (i = 0; i < nr_page; i++, addr += PAGE_SIZE)
+ virt_to_page(addr)->index = 0;
+}
+
+struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
+ const size_t *sizes, int nr_vms,
+ size_t align, gfp_t gfp_mask)
+{
+ struct vm_struct **vms;
+ int area, area2, first_area, last_area;
+ unsigned long start, end, first_start, last_end;
+ void *base;
+
+ gfp_mask &= GFP_RECLAIM_MASK;
+
+ /* verify parameters and allocate data structures */
+ BUG_ON(align & ~PAGE_MASK || !is_power_of_2(align));
+ first_area = last_area = 0;
+ for (area = 0; area < nr_vms; area++) {
+ start = offsets[area];
+ end = start + sizes[area];
+
+ /* is everything aligned properly? */
+ BUG_ON(!IS_ALIGNED(offsets[area], align));
+ BUG_ON(!IS_ALIGNED(sizes[area], align));
+
+ if (end < offsets[first_area])
+ first_area = area;
+
+ /* detect the area with the highest address */
+ if (start > offsets[last_area])
+ last_area = area;
+
+ for (area2 = 0; area2 < nr_vms; area2++) {
+ unsigned long start2 = offsets[area2];
+ unsigned long end2 = start2 + sizes[area2];
+
+ if (area2 == area)
+ continue;
+
+ BUG_ON(start2 >= start && start2 < end);
+ BUG_ON(end2 <= end && end2 > start);
+ }
+ }
+ first_start = offsets[first_area];
+ last_end = offsets[last_area] + sizes[last_area];
+
+ vms = kzalloc(sizeof(vms[0]) * nr_vms, gfp_mask);
+ if (!vms)
+ goto err_free;
+
+ for (area = 0; area < nr_vms; area++) {
+ vms[area] = kzalloc(sizeof(struct vm_struct), gfp_mask);
+ if (!vms[area])
+ goto err_free;
+ }
+
+ base = kmalloc(last_end - first_start, GFP_KERNEL | __GFP_COMP);
+ if (!base)
+ goto err_free;
+
+ for (area = 0; area < nr_vms; area++) {
+ struct vm_struct *vm = vms[area];
+
+ vm->flags = VM_ALLOC;
+ vm->addr = base + offsets[area];
+ vm->size = sizes[area];
+ vm->caller = NULL;
+ }
+ return vms;
+
+err_free:
+ for (area = 0; area < nr_vms; area++) {
+ if (vms)
+ kfree(vms[area]);
+ }
+ kfree(vms);
+ return NULL;
+}
+
+void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
+{
+ int area;
+ void *vaddr = (void *)(-1UL);
+ for (area = 0; area < nr_vms; area++)
+ if (vms[area]) {
+ if (vms[area]->addr < vaddr)
+ vaddr = vms[area]->addr;
+ kfree(vms[area]);
+ }
+ kfree(vms);
+ vfree(vaddr);
+}
+#endif
--
1.6.4.4
next reply other threads:[~2010-03-19 9:03 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-03-19 9:02 graff.yang [this message]
2010-03-20 4:06 ` [PATCH] mm/nommu.c:Dynamic alloc/free percpu area for nommu Tejun Heo
2010-03-22 2:33 ` graff yang
2010-04-01 10:20 ` Tejun Heo
2010-04-06 9:28 ` Sonic Zhang
2010-04-08 2:43 ` Tejun Heo
2010-04-08 9:40 ` Sonic Zhang
2010-04-08 23:33 ` Tejun Heo
2010-03-22 4:14 ` [Uclinux-dist-devel] [PATCH] mm/nommu.c:Dynamic alloc/freepercpu " Zhang, Sonic
2010-03-22 11:50 ` [PATCH] mm/nommu.c:Dynamic alloc/free percpu " David Howells
2010-03-23 2:33 ` graff yang
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=1268989324-7575-1-git-send-email-graff.yang@gmail.com \
--to=graff.yang@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=dhowells@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=tj@kernel.org \
--cc=uclinux-dist-devel@blackfin.uclinux.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.