summaryrefslogtreecommitdiff
path: root/arch/arm/mm/pgd.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mm/pgd.c')
-rw-r--r--arch/arm/mm/pgd.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index ad249e98a942..3e9503bb7bf5 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -17,6 +17,23 @@
#include "mm.h"
+DEFINE_SPINLOCK(pgd_lock);
+LIST_HEAD(pgd_list);
+
+static inline void pgd_list_add(pgd_t *pgd)
+{
+ struct page *page = virt_to_page(pgd);
+
+ list_add(&page->lru, &pgd_list);
+}
+
+static inline void pgd_list_del(pgd_t *pgd)
+{
+ struct page *page = virt_to_page(pgd);
+
+ list_del(&page->lru);
+}
+
/*
* need to get a 16k page for level 1
*/
@@ -26,6 +43,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
pud_t *new_pud, *init_pud;
pmd_t *new_pmd, *init_pmd;
pte_t *new_pte, *init_pte;
+ unsigned long flags;
new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2);
if (!new_pgd)
@@ -33,6 +51,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
memset(new_pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+ spin_lock_irqsave(&pgd_lock, flags);
/*
* Copy over the kernel and IO PGD entries
*/
@@ -43,6 +62,10 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
#if !defined(CONFIG_CPU_CACHE_V7) || !defined(CONFIG_SMP)
clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
#endif
+
+ pgd_list_add(new_pgd);
+ spin_unlock_irqrestore(&pgd_lock, flags);
+
if (!vectors_high()) {
/*
* On ARM, first page must always be allocated since it
@@ -75,6 +98,9 @@ no_pte:
no_pmd:
pud_free(mm, new_pud);
no_pud:
+ spin_lock_irqsave(&pgd_lock, flags);
+ pgd_list_del(new_pgd);
+ spin_unlock_irqrestore(&pgd_lock, flags);
free_pages((unsigned long)new_pgd, 2);
no_pgd:
return NULL;
@@ -86,10 +112,15 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
pud_t *pud;
pmd_t *pmd;
pgtable_t pte;
+ unsigned long flags;
if (!pgd_base)
return;
+ spin_lock_irqsave(&pgd_lock, flags);
+ pgd_list_del(pgd_base);
+ spin_unlock_irqrestore(&pgd_lock, flags);
+
pgd = pgd_base + pgd_index(0);
if (pgd_none_or_clear_bad(pgd))
goto no_pgd;