summaryrefslogtreecommitdiff
path: root/mm/memory.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-05-15 09:18:09 -0700
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-05-15 09:18:09 -0700
commite9d00e5cb88db3f2d29aa89938e90e4011b735f2 (patch)
tree8bc8fc903daf71fa0cf697a5400c04feeb1fd38a /mm/memory.c
parent7c9d187e950db8c6fbccc9e260b2ed6779845f6d (diff)
This improves on the page table TLB shootdown. Almost there.
Diffstat (limited to 'mm/memory.c')
-rw-r--r--mm/memory.c48
1 files changed, 20 insertions, 28 deletions
diff --git a/mm/memory.c b/mm/memory.c
index 20ac82241412..8de16cbed3d5 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -72,28 +72,10 @@ static inline void copy_cow_page(struct page * from, struct page * to, unsigned
mem_map_t * mem_map;
/*
- * Called by TLB shootdown
- */
-void __free_pte(pte_t pte)
-{
- struct page *page;
- unsigned long pfn = pte_pfn(pte);
- if (!pfn_valid(pfn))
- return;
- page = pfn_to_page(pfn);
- if (PageReserved(page))
- return;
- if (pte_dirty(pte))
- set_page_dirty(page);
- free_page_and_swap_cache(page);
-}
-
-
-/*
* Note: this doesn't free the actual pages themselves. That
* has been handled earlier when unmapping all the memory regions.
*/
-static inline void free_one_pmd(pmd_t * dir)
+static inline void free_one_pmd(mmu_gather_t *tlb, pmd_t * dir)
{
struct page *pte;
@@ -106,10 +88,10 @@ static inline void free_one_pmd(pmd_t * dir)
}
pte = pmd_page(*dir);
pmd_clear(dir);
- pte_free(pte);
+ pte_free_tlb(tlb, pte);
}
-static inline void free_one_pgd(pgd_t * dir)
+static inline void free_one_pgd(mmu_gather_t *tlb, pgd_t * dir)
{
int j;
pmd_t * pmd;
@@ -125,9 +107,9 @@ static inline void free_one_pgd(pgd_t * dir)
pgd_clear(dir);
for (j = 0; j < PTRS_PER_PMD ; j++) {
prefetchw(pmd+j+(PREFETCH_STRIDE/16));
- free_one_pmd(pmd+j);
+ free_one_pmd(tlb, pmd+j);
}
- pmd_free(pmd);
+ pmd_free_tlb(tlb, pmd);
}
/*
@@ -136,13 +118,13 @@ static inline void free_one_pgd(pgd_t * dir)
*
* Must be called with pagetable lock held.
*/
-void clear_page_tables(struct mm_struct *mm, unsigned long first, int nr)
+void clear_page_tables(mmu_gather_t *tlb, unsigned long first, int nr)
{
- pgd_t * page_dir = mm->pgd;
+ pgd_t * page_dir = tlb->mm->pgd;
page_dir += first;
do {
- free_one_pgd(page_dir);
+ free_one_pgd(tlb, page_dir);
page_dir++;
} while (--nr);
@@ -362,8 +344,18 @@ static void zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address,
if (pte_none(pte))
continue;
if (pte_present(pte)) {
- /* This will eventually call __free_pte on the pte. */
- tlb_remove_page(tlb, ptep, address + offset);
+ unsigned long pfn = pte_pfn(pte);
+
+ pte_clear(ptep);
+ pfn = pte_pfn(pte);
+ if (pfn_valid(pfn)) {
+ struct page *page = pfn_to_page(pfn);
+ if (!PageReserved(page)) {
+ if (pte_dirty(pte))
+ set_page_dirty(page);
+ tlb_remove_page(tlb, page);
+ }
+ }
} else {
free_swap_and_cache(pte_to_swp_entry(pte));
pte_clear(ptep);