diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h index cfce186f0c4e..e50acd1810c9 100644 --- a/include/linux/page_ext.h +++ b/include/linux/page_ext.h @@ -19,6 +19,9 @@ struct page_ext_operations { enum page_ext_flags { PAGE_EXT_OWNER, PAGE_EXT_OWNER_ALLOCATED, +#ifdef CONFIG_PAGE_EXTENSION_PAGE_FREE + PAGE_EXT_PG_FREE, +#endif #if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) PAGE_EXT_YOUNG, PAGE_EXT_IDLE, diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug index 46615e0bdb35..14e36729c3d6 100644 --- a/mm/Kconfig.debug +++ b/mm/Kconfig.debug @@ -8,6 +8,15 @@ config PAGE_EXTENSION by not allocating this extra memory according to boottime configuration. +config PAGE_EXTENSION_PAGE_FREE + bool "Add a flag in page_ext_flags to indicate if a page is free" + depends on PAGE_EXTENSION && QGKI + help + Add the PAGE_FREE flag in page_ext_flags, in order to indicate + whether a page from the buddy allocator is free or is in + use. This information can aid in debugging buddy allocator + related issues. + config DEBUG_PAGEALLOC bool "Debug page memory allocations" depends on DEBUG_KERNEL diff --git a/mm/page_owner.c b/mm/page_owner.c index 41a99cfe0b0d..35673f47d8af 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -29,6 +29,7 @@ struct page_owner { depot_stack_handle_t free_handle; int pid; u64 ts_nsec; + u64 free_ts_nsec; }; static bool page_owner_enabled = IS_ENABLED(CONFIG_PAGE_OWNER_ENABLE_DEFAULT); @@ -152,6 +153,7 @@ void __reset_page_owner(struct page *page, unsigned int order) struct page_ext *page_ext; depot_stack_handle_t handle = 0; struct page_owner *page_owner; + u64 free_ts_nsec = local_clock(); handle = save_stack(GFP_NOWAIT | __GFP_NOWARN); @@ -160,8 +162,12 @@ void __reset_page_owner(struct page *page, unsigned int order) return; for (i = 0; i < (1 << order); i++) { __clear_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags); +#ifdef CONFIG_PAGE_EXTENSION_PAGE_FREE + __set_bit(PAGE_EXT_PG_FREE, &page_ext->flags); +#endif page_owner = get_page_owner(page_ext); page_owner->free_handle = handle; + page_owner->free_ts_nsec = free_ts_nsec; page_ext = page_ext_next(page_ext); } } @@ -181,8 +187,13 @@ static inline void __set_page_owner_handle(struct page *page, page_owner->last_migrate_reason = -1; page_owner->pid = current->pid; page_owner->ts_nsec = local_clock(); + page_owner->free_ts_nsec = 0; + __set_bit(PAGE_EXT_OWNER, &page_ext->flags); __set_bit(PAGE_EXT_OWNER_ALLOCATED, &page_ext->flags); +#ifdef CONFIG_PAGE_EXTENSION_PAGE_FREE + __clear_bit(PAGE_EXT_PG_FREE, &page_ext->flags); +#endif page_ext = page_ext_next(page_ext); } @@ -247,6 +258,7 @@ void __copy_page_owner(struct page *oldpage, struct page *newpage) new_page_owner->handle = old_page_owner->handle; new_page_owner->pid = old_page_owner->pid; new_page_owner->ts_nsec = old_page_owner->ts_nsec; + new_page_owner->free_ts_nsec = old_page_owner->ts_nsec; /* * We don't clear the bit on the oldpage as it's going to be freed