pgtable-frag.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Handling Page Tables through page fragments
  4. *
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/gfp.h>
  8. #include <linux/mm.h>
  9. #include <linux/percpu.h>
  10. #include <linux/hardirq.h>
  11. #include <linux/hugetlb.h>
  12. #include <asm/pgalloc.h>
  13. #include <asm/tlbflush.h>
  14. #include <asm/tlb.h>
  15. void pte_frag_destroy(void *pte_frag)
  16. {
  17. int count;
  18. struct ptdesc *ptdesc;
  19. ptdesc = virt_to_ptdesc(pte_frag);
  20. /* drop all the pending references */
  21. count = ((unsigned long)pte_frag & ~PAGE_MASK) >> PTE_FRAG_SIZE_SHIFT;
  22. /* We allow PTE_FRAG_NR fragments from a PTE page */
  23. if (atomic_sub_and_test(PTE_FRAG_NR - count, &ptdesc->pt_frag_refcount)) {
  24. pagetable_pte_dtor(ptdesc);
  25. pagetable_free(ptdesc);
  26. }
  27. }
  28. static pte_t *get_pte_from_cache(struct mm_struct *mm)
  29. {
  30. void *pte_frag, *ret;
  31. if (PTE_FRAG_NR == 1)
  32. return NULL;
  33. spin_lock(&mm->page_table_lock);
  34. ret = pte_frag_get(&mm->context);
  35. if (ret) {
  36. pte_frag = ret + PTE_FRAG_SIZE;
  37. /*
  38. * If we have taken up all the fragments mark PTE page NULL
  39. */
  40. if (((unsigned long)pte_frag & ~PAGE_MASK) == 0)
  41. pte_frag = NULL;
  42. pte_frag_set(&mm->context, pte_frag);
  43. }
  44. spin_unlock(&mm->page_table_lock);
  45. return (pte_t *)ret;
  46. }
  47. static pte_t *__alloc_for_ptecache(struct mm_struct *mm, int kernel)
  48. {
  49. void *ret = NULL;
  50. struct ptdesc *ptdesc;
  51. if (!kernel) {
  52. ptdesc = pagetable_alloc(PGALLOC_GFP | __GFP_ACCOUNT, 0);
  53. if (!ptdesc)
  54. return NULL;
  55. if (!pagetable_pte_ctor(ptdesc)) {
  56. pagetable_free(ptdesc);
  57. return NULL;
  58. }
  59. } else {
  60. ptdesc = pagetable_alloc(PGALLOC_GFP, 0);
  61. if (!ptdesc)
  62. return NULL;
  63. }
  64. atomic_set(&ptdesc->pt_frag_refcount, 1);
  65. ret = ptdesc_address(ptdesc);
  66. /*
  67. * if we support only one fragment just return the
  68. * allocated page.
  69. */
  70. if (PTE_FRAG_NR == 1)
  71. return ret;
  72. spin_lock(&mm->page_table_lock);
  73. /*
  74. * If we find ptdesc_page set, we return
  75. * the allocated page with single fragment
  76. * count.
  77. */
  78. if (likely(!pte_frag_get(&mm->context))) {
  79. atomic_set(&ptdesc->pt_frag_refcount, PTE_FRAG_NR);
  80. pte_frag_set(&mm->context, ret + PTE_FRAG_SIZE);
  81. }
  82. spin_unlock(&mm->page_table_lock);
  83. return (pte_t *)ret;
  84. }
  85. pte_t *pte_fragment_alloc(struct mm_struct *mm, int kernel)
  86. {
  87. pte_t *pte;
  88. pte = get_pte_from_cache(mm);
  89. if (pte)
  90. return pte;
  91. return __alloc_for_ptecache(mm, kernel);
  92. }
  93. static void pte_free_now(struct rcu_head *head)
  94. {
  95. struct ptdesc *ptdesc;
  96. ptdesc = container_of(head, struct ptdesc, pt_rcu_head);
  97. pagetable_pte_dtor(ptdesc);
  98. pagetable_free(ptdesc);
  99. }
  100. void pte_fragment_free(unsigned long *table, int kernel)
  101. {
  102. struct ptdesc *ptdesc = virt_to_ptdesc(table);
  103. if (pagetable_is_reserved(ptdesc))
  104. return free_reserved_ptdesc(ptdesc);
  105. BUG_ON(atomic_read(&ptdesc->pt_frag_refcount) <= 0);
  106. if (atomic_dec_and_test(&ptdesc->pt_frag_refcount)) {
  107. if (kernel)
  108. pagetable_free(ptdesc);
  109. else if (folio_test_clear_active(ptdesc_folio(ptdesc)))
  110. call_rcu(&ptdesc->pt_rcu_head, pte_free_now);
  111. else
  112. pte_free_now(&ptdesc->pt_rcu_head);
  113. }
  114. }
  115. #ifdef CONFIG_TRANSPARENT_HUGEPAGE
  116. void pte_free_defer(struct mm_struct *mm, pgtable_t pgtable)
  117. {
  118. struct folio *folio;
  119. folio = virt_to_folio(pgtable);
  120. folio_set_active(folio);
  121. pte_fragment_free((unsigned long *)pgtable, 0);
  122. }
  123. #endif /* CONFIG_TRANSPARENT_HUGEPAGE */