aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/pageattr.c')
-rw-r--r--arch/x86/mm/pageattr.c63
1 files changed, 47 insertions, 16 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 4540e8880cd9..ac9c7797b632 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -52,6 +52,7 @@ static DEFINE_SPINLOCK(cpa_lock);
52#define CPA_FLUSHTLB 1 52#define CPA_FLUSHTLB 1
53#define CPA_ARRAY 2 53#define CPA_ARRAY 2
54#define CPA_PAGES_ARRAY 4 54#define CPA_PAGES_ARRAY 4
55#define CPA_FREE_PAGETABLES 8
55 56
56#ifdef CONFIG_PROC_FS 57#ifdef CONFIG_PROC_FS
57static unsigned long direct_pages_count[PG_LEVEL_NUM]; 58static unsigned long direct_pages_count[PG_LEVEL_NUM];
@@ -723,10 +724,13 @@ static int split_large_page(struct cpa_data *cpa, pte_t *kpte,
723 return 0; 724 return 0;
724} 725}
725 726
726static bool try_to_free_pte_page(pte_t *pte) 727static bool try_to_free_pte_page(struct cpa_data *cpa, pte_t *pte)
727{ 728{
728 int i; 729 int i;
729 730
731 if (!(cpa->flags & CPA_FREE_PAGETABLES))
732 return false;
733
730 for (i = 0; i < PTRS_PER_PTE; i++) 734 for (i = 0; i < PTRS_PER_PTE; i++)
731 if (!pte_none(pte[i])) 735 if (!pte_none(pte[i]))
732 return false; 736 return false;
@@ -735,10 +739,13 @@ static bool try_to_free_pte_page(pte_t *pte)
735 return true; 739 return true;
736} 740}
737 741
738static bool try_to_free_pmd_page(pmd_t *pmd) 742static bool try_to_free_pmd_page(struct cpa_data *cpa, pmd_t *pmd)
739{ 743{
740 int i; 744 int i;
741 745
746 if (!(cpa->flags & CPA_FREE_PAGETABLES))
747 return false;
748
742 for (i = 0; i < PTRS_PER_PMD; i++) 749 for (i = 0; i < PTRS_PER_PMD; i++)
743 if (!pmd_none(pmd[i])) 750 if (!pmd_none(pmd[i]))
744 return false; 751 return false;
@@ -759,7 +766,9 @@ static bool try_to_free_pud_page(pud_t *pud)
759 return true; 766 return true;
760} 767}
761 768
762static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end) 769static bool unmap_pte_range(struct cpa_data *cpa, pmd_t *pmd,
770 unsigned long start,
771 unsigned long end)
763{ 772{
764 pte_t *pte = pte_offset_kernel(pmd, start); 773 pte_t *pte = pte_offset_kernel(pmd, start);
765 774
@@ -770,22 +779,23 @@ static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end)
770 pte++; 779 pte++;
771 } 780 }
772 781
773 if (try_to_free_pte_page((pte_t *)pmd_page_vaddr(*pmd))) { 782 if (try_to_free_pte_page(cpa, (pte_t *)pmd_page_vaddr(*pmd))) {
774 pmd_clear(pmd); 783 pmd_clear(pmd);
775 return true; 784 return true;
776 } 785 }
777 return false; 786 return false;
778} 787}
779 788
780static void __unmap_pmd_range(pud_t *pud, pmd_t *pmd, 789static void __unmap_pmd_range(struct cpa_data *cpa, pud_t *pud, pmd_t *pmd,
781 unsigned long start, unsigned long end) 790 unsigned long start, unsigned long end)
782{ 791{
783 if (unmap_pte_range(pmd, start, end)) 792 if (unmap_pte_range(cpa, pmd, start, end))
784 if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud))) 793 if (try_to_free_pmd_page(cpa, (pmd_t *)pud_page_vaddr(*pud)))
785 pud_clear(pud); 794 pud_clear(pud);
786} 795}
787 796
788static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end) 797static void unmap_pmd_range(struct cpa_data *cpa, pud_t *pud,
798 unsigned long start, unsigned long end)
789{ 799{
790 pmd_t *pmd = pmd_offset(pud, start); 800 pmd_t *pmd = pmd_offset(pud, start);
791 801
@@ -796,7 +806,7 @@ static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end)
796 unsigned long next_page = (start + PMD_SIZE) & PMD_MASK; 806 unsigned long next_page = (start + PMD_SIZE) & PMD_MASK;
797 unsigned long pre_end = min_t(unsigned long, end, next_page); 807 unsigned long pre_end = min_t(unsigned long, end, next_page);
798 808
799 __unmap_pmd_range(pud, pmd, start, pre_end); 809 __unmap_pmd_range(cpa, pud, pmd, start, pre_end);
800 810
801 start = pre_end; 811 start = pre_end;
802 pmd++; 812 pmd++;
@@ -809,7 +819,8 @@ static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end)
809 if (pmd_large(*pmd)) 819 if (pmd_large(*pmd))
810 pmd_clear(pmd); 820 pmd_clear(pmd);
811 else 821 else
812 __unmap_pmd_range(pud, pmd, start, start + PMD_SIZE); 822 __unmap_pmd_range(cpa, pud, pmd,
823 start, start + PMD_SIZE);
813 824
814 start += PMD_SIZE; 825 start += PMD_SIZE;
815 pmd++; 826 pmd++;
@@ -819,17 +830,19 @@ static void unmap_pmd_range(pud_t *pud, unsigned long start, unsigned long end)
819 * 4K leftovers? 830 * 4K leftovers?
820 */ 831 */
821 if (start < end) 832 if (start < end)
822 return __unmap_pmd_range(pud, pmd, start, end); 833 return __unmap_pmd_range(cpa, pud, pmd, start, end);
823 834
824 /* 835 /*
825 * Try again to free the PMD page if haven't succeeded above. 836 * Try again to free the PMD page if haven't succeeded above.
826 */ 837 */
827 if (!pud_none(*pud)) 838 if (!pud_none(*pud))
828 if (try_to_free_pmd_page((pmd_t *)pud_page_vaddr(*pud))) 839 if (try_to_free_pmd_page(cpa, (pmd_t *)pud_page_vaddr(*pud)))
829 pud_clear(pud); 840 pud_clear(pud);
830} 841}
831 842
832static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end) 843static void __unmap_pud_range(struct cpa_data *cpa, pgd_t *pgd,
844 unsigned long start,
845 unsigned long end)
833{ 846{
834 pud_t *pud = pud_offset(pgd, start); 847 pud_t *pud = pud_offset(pgd, start);
835 848
@@ -840,7 +853,7 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
840 unsigned long next_page = (start + PUD_SIZE) & PUD_MASK; 853 unsigned long next_page = (start + PUD_SIZE) & PUD_MASK;
841 unsigned long pre_end = min_t(unsigned long, end, next_page); 854 unsigned long pre_end = min_t(unsigned long, end, next_page);
842 855
843 unmap_pmd_range(pud, start, pre_end); 856 unmap_pmd_range(cpa, pud, start, pre_end);
844 857
845 start = pre_end; 858 start = pre_end;
846 pud++; 859 pud++;
@@ -854,7 +867,7 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
854 if (pud_large(*pud)) 867 if (pud_large(*pud))
855 pud_clear(pud); 868 pud_clear(pud);
856 else 869 else
857 unmap_pmd_range(pud, start, start + PUD_SIZE); 870 unmap_pmd_range(cpa, pud, start, start + PUD_SIZE);
858 871
859 start += PUD_SIZE; 872 start += PUD_SIZE;
860 pud++; 873 pud++;
@@ -864,7 +877,7 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
864 * 2M leftovers? 877 * 2M leftovers?
865 */ 878 */
866 if (start < end) 879 if (start < end)
867 unmap_pmd_range(pud, start, end); 880 unmap_pmd_range(cpa, pud, start, end);
868 881
869 /* 882 /*
870 * No need to try to free the PUD page because we'll free it in 883 * No need to try to free the PUD page because we'll free it in
@@ -872,6 +885,24 @@ static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
872 */ 885 */
873} 886}
874 887
888static void unmap_pud_range(pgd_t *pgd, unsigned long start, unsigned long end)
889{
890 struct cpa_data cpa = {
891 .flags = CPA_FREE_PAGETABLES,
892 };
893
894 __unmap_pud_range(&cpa, pgd, start, end);
895}
896
897void unmap_pud_range_nofree(pgd_t *pgd, unsigned long start, unsigned long end)
898{
899 struct cpa_data cpa = {
900 .flags = 0,
901 };
902
903 __unmap_pud_range(&cpa, pgd, start, end);
904}
905
875static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end) 906static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end)
876{ 907{
877 pgd_t *pgd_entry = root + pgd_index(addr); 908 pgd_t *pgd_entry = root + pgd_index(addr);