>>> Keir Fraser <keir@xxxxxxxxxxxxx> 10.01.07 12:28 >>>
>On 10/1/07 11:14, "Jan Beulich" <jbeulich@xxxxxxxxxx> wrote:
>
>>> Is it actually safe to circumvent tlb_remove_page()? It does rather more
>>> than just free_page()! That's why I used a ForeignPage hook when writing the
>>> i386 code. It's certainly *not* safe to assume that whoever wrote that part
>>> of the x86/64 port understood all the ramifications of what they were doing.
>>
>> Not really, as I understand it - it either frees the page (when the TLB is in
>> fast
>> mode) or inserts the page into the gather list, bumping the contained pages
>> count and freeing all of them and flushing the hardware TLBs if exceeding the
>> threshold - the latter step is otherwise done from tlb_finish_mmu().
>
>Presumably this gathering happens because it may not be safe to free the
>pages without having first flushed the TLBs? Freeing the page with no TLB
>flush management at all would be a bad idea in that case.
>
>And I said that sync'ing with i386 is a good general rule. I trust the code
>a lot more. :-)
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
Index: sle10-sp1-2007-01-10/arch/x86_64/mm/pageattr-xen.c
===================================================================
--- sle10-sp1-2007-01-10.orig/arch/x86_64/mm/pageattr-xen.c 2007-01-10
13:44:37.000000000 +0100
+++ sle10-sp1-2007-01-10/arch/x86_64/mm/pageattr-xen.c 2007-01-10
14:07:10.000000000 +0100
@@ -164,6 +164,18 @@ void _arch_exit_mmap(struct mm_struct *m
mm_unpin(mm);
}
+struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ struct page *pte;
+
+ pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
+ if (pte) {
+ SetPageForeign(pte, pte_free);
+ set_page_count(pte, 1);
+ }
+ return pte;
+}
+
void pte_free(struct page *pte)
{
unsigned long va = (unsigned long)__va(page_to_pfn(pte)<<PAGE_SHIFT);
@@ -171,6 +183,10 @@ void pte_free(struct page *pte)
if (!pte_write(*virt_to_ptep(va)))
BUG_ON(HYPERVISOR_update_va_mapping(
va, pfn_pte(page_to_pfn(pte), PAGE_KERNEL), 0));
+
+ ClearPageForeign(pte);
+ set_page_count(pte, 1);
+
__free_page(pte);
}
#endif /* CONFIG_XEN */
Index: sle10-sp1-2007-01-10/include/asm-x86_64/mach-xen/asm/pgalloc.h
===================================================================
--- sle10-sp1-2007-01-10.orig/include/asm-x86_64/mach-xen/asm/pgalloc.h
2007-01-10 10:09:53.000000000 +0100
+++ sle10-sp1-2007-01-10/include/asm-x86_64/mach-xen/asm/pgalloc.h
2007-01-10 14:33:04.000000000 +0100
@@ -64,42 +64,35 @@ static inline void pgd_populate(struct m
}
}
-static inline void pmd_free(pmd_t *pmd)
+extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
+extern void pte_free(struct page *pte);
+
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{
- pte_t *ptep = virt_to_ptep(pmd);
+ struct page *pg;
- if (!pte_write(*ptep)) {
- BUG_ON(HYPERVISOR_update_va_mapping(
- (unsigned long)pmd,
- pfn_pte(virt_to_phys(pmd)>>PAGE_SHIFT, PAGE_KERNEL),
- 0));
- }
- free_page((unsigned long)pmd);
+ pg = pte_alloc_one(mm, addr);
+ return pg ? page_address(pg) : NULL;
}
-static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+static inline void pmd_free(pmd_t *pmd)
{
- pmd_t *pmd = (pmd_t *) get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
- return pmd;
+ BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
+ pte_free(virt_to_page(pmd));
}
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
- pud_t *pud = (pud_t *) get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
- return pud;
+ struct page *pg;
+
+ pg = pte_alloc_one(mm, addr);
+ return pg ? page_address(pg) : NULL;
}
static inline void pud_free(pud_t *pud)
{
- pte_t *ptep = virt_to_ptep(pud);
-
- if (!pte_write(*ptep)) {
- BUG_ON(HYPERVISOR_update_va_mapping(
- (unsigned long)pud,
- pfn_pte(virt_to_phys(pud)>>PAGE_SHIFT, PAGE_KERNEL),
- 0));
- }
- free_page((unsigned long)pud);
+ BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
+ pte_free(virt_to_page(pud));
}
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
@@ -167,14 +160,6 @@ static inline pte_t *pte_alloc_one_kerne
return pte;
}
-static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long
address)
-{
- struct page *pte;
-
- pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
- return pte;
-}
-
/* Should really implement gc for free page table pages. This could be
done with a reference count in struct page. */
@@ -185,14 +170,8 @@ static inline void pte_free_kernel(pte_t
free_page((unsigned long)pte);
}
-extern void pte_free(struct page *pte);
-
-//#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
-//#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
-//#define __pud_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
-
-#define __pte_free_tlb(tlb,x) pte_free((x))
-#define __pmd_free_tlb(tlb,x) pmd_free((x))
-#define __pud_free_tlb(tlb,x) pud_free((x))
+#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
+#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
+#define __pud_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x))
#endif /* _X86_64_PGALLOC_H */
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|