Skip to content

Commit a7e6c70

Browse files
committed
x86, memremap: fix altmap accounting at free
Commit 24b6d41 "mm: pass the vmem_altmap to vmemmap_free" converted the vmemmap_free() path to pass the altmap argument all the way through the call chain rather than looking it up based on the page. Unfortunately that ends up over freeing altmap allocated pages in some cases since free_pagetable() is used to free both memmap space and pte space, where only the memmap stored in huge pages uses altmap allocations. Given that altmap allocations for memmap space are special cased in vmemmap_populate_hugepages() add a symmetric / special case free_hugepage_table() to handle altmap freeing, and cleanup the unneeded passing of altmap to leaf functions that do not require it. Without this change the sanity check accounting in devm_memremap_pages_release() will throw a warning with the following signature. nd_pmem pfn10.1: devm_memremap_pages_release: failed to free all reserved pages WARNING: CPU: 44 PID: 3539 at kernel/memremap.c:310 devm_memremap_pages_release+0x1c7/0x220 CPU: 44 PID: 3539 Comm: ndctl Tainted: G L 4.16.0-rc1-linux-stable rib#7 RIP: 0010:devm_memremap_pages_release+0x1c7/0x220 [..] Call Trace: release_nodes+0x225/0x270 device_release_driver_internal+0x15d/0x210 bus_remove_device+0xe2/0x160 device_del+0x130/0x310 ? klist_release+0x56/0x100 ? nd_region_notify+0xc0/0xc0 [libnvdimm] device_unregister+0x16/0x60 This was missed in testing since not all configurations will trigger this warning. Fixes: 24b6d41 ("mm: pass the vmem_altmap to vmemmap_free") Reported-by: Jane Chu <jane.chu@oracle.com> Cc: Ross Zwisler <ross.zwisler@linux.intel.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 0cbfeef commit a7e6c70

1 file changed

Lines changed: 28 additions & 32 deletions

File tree

arch/x86/mm/init_64.c

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -800,17 +800,11 @@ int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
800800

801801
#define PAGE_INUSE 0xFD
802802

803-
static void __meminit free_pagetable(struct page *page, int order,
804-
struct vmem_altmap *altmap)
803+
static void __meminit free_pagetable(struct page *page, int order)
805804
{
806805
unsigned long magic;
807806
unsigned int nr_pages = 1 << order;
808807

809-
if (altmap) {
810-
vmem_altmap_free(altmap, nr_pages);
811-
return;
812-
}
813-
814808
/* bootmem page has reserved flag */
815809
if (PageReserved(page)) {
816810
__ClearPageReserved(page);
@@ -826,8 +820,16 @@ static void __meminit free_pagetable(struct page *page, int order,
826820
free_pages((unsigned long)page_address(page), order);
827821
}
828822

829-
static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd,
823+
static void __meminit free_hugepage_table(struct page *page,
830824
struct vmem_altmap *altmap)
825+
{
826+
if (altmap)
827+
vmem_altmap_free(altmap, PMD_SIZE / PAGE_SIZE);
828+
else
829+
free_pagetable(page, get_order(PMD_SIZE));
830+
}
831+
832+
static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
831833
{
832834
pte_t *pte;
833835
int i;
@@ -839,14 +841,13 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd,
839841
}
840842

841843
/* free a pte talbe */
842-
free_pagetable(pmd_page(*pmd), 0, altmap);
844+
free_pagetable(pmd_page(*pmd), 0);
843845
spin_lock(&init_mm.page_table_lock);
844846
pmd_clear(pmd);
845847
spin_unlock(&init_mm.page_table_lock);
846848
}
847849

848-
static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud,
849-
struct vmem_altmap *altmap)
850+
static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud)
850851
{
851852
pmd_t *pmd;
852853
int i;
@@ -858,14 +859,13 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud,
858859
}
859860

860861
/* free a pmd talbe */
861-
free_pagetable(pud_page(*pud), 0, altmap);
862+
free_pagetable(pud_page(*pud), 0);
862863
spin_lock(&init_mm.page_table_lock);
863864
pud_clear(pud);
864865
spin_unlock(&init_mm.page_table_lock);
865866
}
866867

867-
static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d,
868-
struct vmem_altmap *altmap)
868+
static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d)
869869
{
870870
pud_t *pud;
871871
int i;
@@ -877,15 +877,15 @@ static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d,
877877
}
878878

879879
/* free a pud talbe */
880-
free_pagetable(p4d_page(*p4d), 0, altmap);
880+
free_pagetable(p4d_page(*p4d), 0);
881881
spin_lock(&init_mm.page_table_lock);
882882
p4d_clear(p4d);
883883
spin_unlock(&init_mm.page_table_lock);
884884
}
885885

886886
static void __meminit
887887
remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
888-
struct vmem_altmap *altmap, bool direct)
888+
bool direct)
889889
{
890890
unsigned long next, pages = 0;
891891
pte_t *pte;
@@ -916,7 +916,7 @@ remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
916916
* freed when offlining, or simplely not in use.
917917
*/
918918
if (!direct)
919-
free_pagetable(pte_page(*pte), 0, altmap);
919+
free_pagetable(pte_page(*pte), 0);
920920

921921
spin_lock(&init_mm.page_table_lock);
922922
pte_clear(&init_mm, addr, pte);
@@ -939,7 +939,7 @@ remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
939939

940940
page_addr = page_address(pte_page(*pte));
941941
if (!memchr_inv(page_addr, PAGE_INUSE, PAGE_SIZE)) {
942-
free_pagetable(pte_page(*pte), 0, altmap);
942+
free_pagetable(pte_page(*pte), 0);
943943

944944
spin_lock(&init_mm.page_table_lock);
945945
pte_clear(&init_mm, addr, pte);
@@ -974,9 +974,8 @@ remove_pmd_table(pmd_t *pmd_start, unsigned long addr, unsigned long end,
974974
if (IS_ALIGNED(addr, PMD_SIZE) &&
975975
IS_ALIGNED(next, PMD_SIZE)) {
976976
if (!direct)
977-
free_pagetable(pmd_page(*pmd),
978-
get_order(PMD_SIZE),
979-
altmap);
977+
free_hugepage_table(pmd_page(*pmd),
978+
altmap);
980979

981980
spin_lock(&init_mm.page_table_lock);
982981
pmd_clear(pmd);
@@ -989,9 +988,8 @@ remove_pmd_table(pmd_t *pmd_start, unsigned long addr, unsigned long end,
989988
page_addr = page_address(pmd_page(*pmd));
990989
if (!memchr_inv(page_addr, PAGE_INUSE,
991990
PMD_SIZE)) {
992-
free_pagetable(pmd_page(*pmd),
993-
get_order(PMD_SIZE),
994-
altmap);
991+
free_hugepage_table(pmd_page(*pmd),
992+
altmap);
995993

996994
spin_lock(&init_mm.page_table_lock);
997995
pmd_clear(pmd);
@@ -1003,8 +1001,8 @@ remove_pmd_table(pmd_t *pmd_start, unsigned long addr, unsigned long end,
10031001
}
10041002

10051003
pte_base = (pte_t *)pmd_page_vaddr(*pmd);
1006-
remove_pte_table(pte_base, addr, next, altmap, direct);
1007-
free_pte_table(pte_base, pmd, altmap);
1004+
remove_pte_table(pte_base, addr, next, direct);
1005+
free_pte_table(pte_base, pmd);
10081006
}
10091007

10101008
/* Call free_pmd_table() in remove_pud_table(). */
@@ -1033,8 +1031,7 @@ remove_pud_table(pud_t *pud_start, unsigned long addr, unsigned long end,
10331031
IS_ALIGNED(next, PUD_SIZE)) {
10341032
if (!direct)
10351033
free_pagetable(pud_page(*pud),
1036-
get_order(PUD_SIZE),
1037-
altmap);
1034+
get_order(PUD_SIZE));
10381035

10391036
spin_lock(&init_mm.page_table_lock);
10401037
pud_clear(pud);
@@ -1048,8 +1045,7 @@ remove_pud_table(pud_t *pud_start, unsigned long addr, unsigned long end,
10481045
if (!memchr_inv(page_addr, PAGE_INUSE,
10491046
PUD_SIZE)) {
10501047
free_pagetable(pud_page(*pud),
1051-
get_order(PUD_SIZE),
1052-
altmap);
1048+
get_order(PUD_SIZE));
10531049

10541050
spin_lock(&init_mm.page_table_lock);
10551051
pud_clear(pud);
@@ -1062,7 +1058,7 @@ remove_pud_table(pud_t *pud_start, unsigned long addr, unsigned long end,
10621058

10631059
pmd_base = pmd_offset(pud, 0);
10641060
remove_pmd_table(pmd_base, addr, next, direct, altmap);
1065-
free_pmd_table(pmd_base, pud, altmap);
1061+
free_pmd_table(pmd_base, pud);
10661062
}
10671063

10681064
if (direct)
@@ -1094,7 +1090,7 @@ remove_p4d_table(p4d_t *p4d_start, unsigned long addr, unsigned long end,
10941090
* to adapt for boot-time switching between 4 and 5 level page tables.
10951091
*/
10961092
if (CONFIG_PGTABLE_LEVELS == 5)
1097-
free_pud_table(pud_base, p4d, altmap);
1093+
free_pud_table(pud_base, p4d);
10981094
}
10991095

11001096
if (direct)

0 commit comments

Comments
 (0)