[v9,3/5] ksm: add ksm zero pages for each process

Message ID 20230524055800.20498-1-yang.yang29@zte.com.cn
State New
Headers
Series ksm: support tracking KSM-placed zero-pages |

Commit Message

Yang Yang May 24, 2023, 5:58 a.m. UTC
  From: xu xin <xu.xin16@zte.com.cn>

As the number of ksm zero pages is not included in ksm_merging_pages per
process when enabling use_zero_pages, it's unclear of how many actual
pages are merged by KSM. To let users accurately estimate their memory
demands when unsharing KSM zero-pages, it's necessary to show KSM zero-
pages per process. In addition, it help users to know the actual KSM
profit because KSM-placed zero pages are also benefit from KSM.

since unsharing zero pages placed by KSM accurately is achieved, then
tracking empty pages merging and unmerging is not a difficult thing any
longer.

Since we already have /proc/<pid>/ksm_stat, just add the information of
'ksm_zero_pages' in it.

Signed-off-by: xu xin <xu.xin16@zte.com.cn>
Cc: Claudio Imbrenda <imbrenda@linux.ibm.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Xuexin Jiang <jiang.xuexin@zte.com.cn>
Cc: Xiaokai Ran <ran.xiaokai@zte.com.cn>
Cc: Yang Yang <yang.yang29@zte.com.cn>
---
 fs/proc/base.c           | 1 +
 include/linux/ksm.h      | 6 ++++--
 include/linux/mm_types.h | 9 +++++++--
 mm/khugepaged.c          | 2 +-
 mm/ksm.c                 | 1 +
 mm/memory.c              | 4 ++--
 6 files changed, 16 insertions(+), 7 deletions(-)
  

Comments

David Hildenbrand May 24, 2023, 7:24 a.m. UTC | #1
On 24.05.23 07:58, Yang Yang wrote:
> From: xu xin <xu.xin16@zte.com.cn>
> 
> As the number of ksm zero pages is not included in ksm_merging_pages per
> process when enabling use_zero_pages, it's unclear of how many actual
> pages are merged by KSM. To let users accurately estimate their memory
> demands when unsharing KSM zero-pages, it's necessary to show KSM zero-
> pages per process. In addition, it help users to know the actual KSM
> profit because KSM-placed zero pages are also benefit from KSM.
> 
> since unsharing zero pages placed by KSM accurately is achieved, then
> tracking empty pages merging and unmerging is not a difficult thing any
> longer.
> 
> Since we already have /proc/<pid>/ksm_stat, just add the information of
> 'ksm_zero_pages' in it.
> 
> Signed-off-by: xu xin <xu.xin16@zte.com.cn>
> Cc: Claudio Imbrenda <imbrenda@linux.ibm.com>
> Cc: David Hildenbrand <david@redhat.com>
> Cc: Xuexin Jiang <jiang.xuexin@zte.com.cn>
> Cc: Xiaokai Ran <ran.xiaokai@zte.com.cn>
> Cc: Yang Yang <yang.yang29@zte.com.cn>
> ---

[...]

>   static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index 306a3d1a0fa6..14f781509812 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -777,7 +777,7 @@ struct mm_struct {
>   #ifdef CONFIG_KSM
>   		/*
>   		 * Represent how many pages of this process are involved in KSM
> -		 * merging.
> +		 * merging (not including ksm_zero_pages).
>   		 */
>   		unsigned long ksm_merging_pages;
>   		/*
> @@ -785,7 +785,12 @@ struct mm_struct {
>   		 * including merged and not merged.
>   		 */
>   		unsigned long ksm_rmap_items;
> -#endif
> +		/*
> +		 * Represent how many empty pages are merged with kernel zero
> +		 * pages when enabling KSM use_zero_pages.

"zero page" ? Only some archs have multiple ones, and it's rather an 
implementation detail.

> +		 */
> +		unsigned long ksm_zero_pages;
> +#endif /* CONFIG_KSM */
>   #ifdef CONFIG_LRU_GEN
>   		struct {

Reviewed-by: David Hildenbrand <david@redhat.com>
  
kernel test robot May 25, 2023, 3:36 a.m. UTC | #2
Hi Yang,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]
[also build test ERROR on linus/master v6.4-rc3 next-20230524]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yang-Yang/ksm-count-all-zero-pages-placed-by-KSM/20230524-153333
base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link:    https://lore.kernel.org/r/20230524055800.20498-1-yang.yang29%40zte.com.cn
patch subject: [PATCH v9 3/5] ksm: add ksm zero pages for each process
config: powerpc-allnoconfig
compiler: powerpc-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/c9da8338fa8f95db948cd4d826053d8f6cbcf19c
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Yang-Yang/ksm-count-all-zero-pages-placed-by-KSM/20230524-153333
        git checkout c9da8338fa8f95db948cd4d826053d8f6cbcf19c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 ~/bin/make.cross W=1 O=build_dir ARCH=powerpc olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 ~/bin/make.cross W=1 O=build_dir ARCH=powerpc SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202305251051.ulf3fOSD-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   mm/memory.c: In function 'zap_pte_range':
>> mm/memory.c:1419:60: warning: passing argument 1 of 'ksm_notify_unmap_zero_page' makes integer from pointer without a cast [-Wint-conversion]
    1419 |                                 ksm_notify_unmap_zero_page(mm, ptent);
         |                                                            ^~
         |                                                            |
         |                                                            struct mm_struct *
   In file included from mm/memory.c:56:
   include/linux/ksm.h:116:53: note: expected 'pte_t' {aka 'long unsigned int'} but argument is of type 'struct mm_struct *'
     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
         |                                               ~~~~~~^~~
>> mm/memory.c:1419:33: error: too many arguments to function 'ksm_notify_unmap_zero_page'
    1419 |                                 ksm_notify_unmap_zero_page(mm, ptent);
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/ksm.h:116:20: note: declared here
     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
   mm/memory.c: In function 'wp_page_copy':
   mm/memory.c:3125:52: warning: passing argument 1 of 'ksm_notify_unmap_zero_page' makes integer from pointer without a cast [-Wint-conversion]
    3125 |                         ksm_notify_unmap_zero_page(mm, vmf->orig_pte);
         |                                                    ^~
         |                                                    |
         |                                                    struct mm_struct *
   include/linux/ksm.h:116:53: note: expected 'pte_t' {aka 'long unsigned int'} but argument is of type 'struct mm_struct *'
     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
         |                                               ~~~~~~^~~
   mm/memory.c:3125:25: error: too many arguments to function 'ksm_notify_unmap_zero_page'
    3125 |                         ksm_notify_unmap_zero_page(mm, vmf->orig_pte);
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/ksm.h:116:20: note: declared here
     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/ksm_notify_unmap_zero_page +1419 mm/memory.c

  1376	
  1377	static unsigned long zap_pte_range(struct mmu_gather *tlb,
  1378					struct vm_area_struct *vma, pmd_t *pmd,
  1379					unsigned long addr, unsigned long end,
  1380					struct zap_details *details)
  1381	{
  1382		struct mm_struct *mm = tlb->mm;
  1383		int force_flush = 0;
  1384		int rss[NR_MM_COUNTERS];
  1385		spinlock_t *ptl;
  1386		pte_t *start_pte;
  1387		pte_t *pte;
  1388		swp_entry_t entry;
  1389	
  1390		tlb_change_page_size(tlb, PAGE_SIZE);
  1391	again:
  1392		init_rss_vec(rss);
  1393		start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
  1394		pte = start_pte;
  1395		flush_tlb_batched_pending(mm);
  1396		arch_enter_lazy_mmu_mode();
  1397		do {
  1398			pte_t ptent = *pte;
  1399			struct page *page;
  1400	
  1401			if (pte_none(ptent))
  1402				continue;
  1403	
  1404			if (need_resched())
  1405				break;
  1406	
  1407			if (pte_present(ptent)) {
  1408				unsigned int delay_rmap;
  1409	
  1410				page = vm_normal_page(vma, addr, ptent);
  1411				if (unlikely(!should_zap_page(details, page)))
  1412					continue;
  1413				ptent = ptep_get_and_clear_full(mm, addr, pte,
  1414								tlb->fullmm);
  1415				tlb_remove_tlb_entry(tlb, pte, addr);
  1416				zap_install_uffd_wp_if_needed(vma, addr, pte, details,
  1417							      ptent);
  1418				if (unlikely(!page)) {
> 1419					ksm_notify_unmap_zero_page(mm, ptent);
  1420					continue;
  1421				}
  1422	
  1423				delay_rmap = 0;
  1424				if (!PageAnon(page)) {
  1425					if (pte_dirty(ptent)) {
  1426						set_page_dirty(page);
  1427						if (tlb_delay_rmap(tlb)) {
  1428							delay_rmap = 1;
  1429							force_flush = 1;
  1430						}
  1431					}
  1432					if (pte_young(ptent) && likely(vma_has_recency(vma)))
  1433						mark_page_accessed(page);
  1434				}
  1435				rss[mm_counter(page)]--;
  1436				if (!delay_rmap) {
  1437					page_remove_rmap(page, vma, false);
  1438					if (unlikely(page_mapcount(page) < 0))
  1439						print_bad_pte(vma, addr, ptent, page);
  1440				}
  1441				if (unlikely(__tlb_remove_page(tlb, page, delay_rmap))) {
  1442					force_flush = 1;
  1443					addr += PAGE_SIZE;
  1444					break;
  1445				}
  1446				continue;
  1447			}
  1448	
  1449			entry = pte_to_swp_entry(ptent);
  1450			if (is_device_private_entry(entry) ||
  1451			    is_device_exclusive_entry(entry)) {
  1452				page = pfn_swap_entry_to_page(entry);
  1453				if (unlikely(!should_zap_page(details, page)))
  1454					continue;
  1455				/*
  1456				 * Both device private/exclusive mappings should only
  1457				 * work with anonymous page so far, so we don't need to
  1458				 * consider uffd-wp bit when zap. For more information,
  1459				 * see zap_install_uffd_wp_if_needed().
  1460				 */
  1461				WARN_ON_ONCE(!vma_is_anonymous(vma));
  1462				rss[mm_counter(page)]--;
  1463				if (is_device_private_entry(entry))
  1464					page_remove_rmap(page, vma, false);
  1465				put_page(page);
  1466			} else if (!non_swap_entry(entry)) {
  1467				/* Genuine swap entry, hence a private anon page */
  1468				if (!should_zap_cows(details))
  1469					continue;
  1470				rss[MM_SWAPENTS]--;
  1471				if (unlikely(!free_swap_and_cache(entry)))
  1472					print_bad_pte(vma, addr, ptent, NULL);
  1473			} else if (is_migration_entry(entry)) {
  1474				page = pfn_swap_entry_to_page(entry);
  1475				if (!should_zap_page(details, page))
  1476					continue;
  1477				rss[mm_counter(page)]--;
  1478			} else if (pte_marker_entry_uffd_wp(entry)) {
  1479				/*
  1480				 * For anon: always drop the marker; for file: only
  1481				 * drop the marker if explicitly requested.
  1482				 */
  1483				if (!vma_is_anonymous(vma) &&
  1484				    !zap_drop_file_uffd_wp(details))
  1485					continue;
  1486			} else if (is_hwpoison_entry(entry) ||
  1487				   is_swapin_error_entry(entry)) {
  1488				if (!should_zap_cows(details))
  1489					continue;
  1490			} else {
  1491				/* We should have covered all the swap entry types */
  1492				WARN_ON_ONCE(1);
  1493			}
  1494			pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
  1495			zap_install_uffd_wp_if_needed(vma, addr, pte, details, ptent);
  1496		} while (pte++, addr += PAGE_SIZE, addr != end);
  1497	
  1498		add_mm_rss_vec(mm, rss);
  1499		arch_leave_lazy_mmu_mode();
  1500	
  1501		/* Do the actual TLB flush before dropping ptl */
  1502		if (force_flush) {
  1503			tlb_flush_mmu_tlbonly(tlb);
  1504			tlb_flush_rmaps(tlb, vma);
  1505		}
  1506		pte_unmap_unlock(start_pte, ptl);
  1507	
  1508		/*
  1509		 * If we forced a TLB flush (either due to running out of
  1510		 * batch buffers or because we needed to flush dirty TLB
  1511		 * entries before releasing the ptl), free the batched
  1512		 * memory too. Restart if we didn't do everything.
  1513		 */
  1514		if (force_flush) {
  1515			force_flush = 0;
  1516			tlb_flush_mmu(tlb);
  1517		}
  1518	
  1519		if (addr != end) {
  1520			cond_resched();
  1521			goto again;
  1522		}
  1523	
  1524		return addr;
  1525	}
  1526
  
kernel test robot May 25, 2023, 6:56 a.m. UTC | #3
Hi Yang,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]
[also build test ERROR on linus/master v6.4-rc3 next-20230525]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yang-Yang/ksm-count-all-zero-pages-placed-by-KSM/20230524-153333
base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link:    https://lore.kernel.org/r/20230524055800.20498-1-yang.yang29%40zte.com.cn
patch subject: [PATCH v9 3/5] ksm: add ksm zero pages for each process
config: nios2-defconfig
compiler: nios2-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/c9da8338fa8f95db948cd4d826053d8f6cbcf19c
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Yang-Yang/ksm-count-all-zero-pages-placed-by-KSM/20230524-153333
        git checkout c9da8338fa8f95db948cd4d826053d8f6cbcf19c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 ~/bin/make.cross W=1 O=build_dir ARCH=nios2 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 ~/bin/make.cross W=1 O=build_dir ARCH=nios2 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202305251415.OLELa7qJ-lkp@intel.com/

All errors (new ones prefixed by >>):

   mm/memory.c: In function 'zap_pte_range':
>> mm/memory.c:1419:60: error: incompatible type for argument 1 of 'ksm_notify_unmap_zero_page'
    1419 |                                 ksm_notify_unmap_zero_page(mm, ptent);
         |                                                            ^~
         |                                                            |
         |                                                            struct mm_struct *
   In file included from mm/memory.c:56:
   include/linux/ksm.h:116:53: note: expected 'pte_t' but argument is of type 'struct mm_struct *'
     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
         |                                               ~~~~~~^~~
   mm/memory.c:1419:33: error: too many arguments to function 'ksm_notify_unmap_zero_page'
    1419 |                                 ksm_notify_unmap_zero_page(mm, ptent);
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/ksm.h:116:20: note: declared here
     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
   mm/memory.c: In function 'wp_page_copy':
   mm/memory.c:3125:52: error: incompatible type for argument 1 of 'ksm_notify_unmap_zero_page'
    3125 |                         ksm_notify_unmap_zero_page(mm, vmf->orig_pte);
         |                                                    ^~
         |                                                    |
         |                                                    struct mm_struct *
   include/linux/ksm.h:116:53: note: expected 'pte_t' but argument is of type 'struct mm_struct *'
     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
         |                                               ~~~~~~^~~
   mm/memory.c:3125:25: error: too many arguments to function 'ksm_notify_unmap_zero_page'
    3125 |                         ksm_notify_unmap_zero_page(mm, vmf->orig_pte);
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/ksm.h:116:20: note: declared here
     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/ksm_notify_unmap_zero_page +1419 mm/memory.c

  1376	
  1377	static unsigned long zap_pte_range(struct mmu_gather *tlb,
  1378					struct vm_area_struct *vma, pmd_t *pmd,
  1379					unsigned long addr, unsigned long end,
  1380					struct zap_details *details)
  1381	{
  1382		struct mm_struct *mm = tlb->mm;
  1383		int force_flush = 0;
  1384		int rss[NR_MM_COUNTERS];
  1385		spinlock_t *ptl;
  1386		pte_t *start_pte;
  1387		pte_t *pte;
  1388		swp_entry_t entry;
  1389	
  1390		tlb_change_page_size(tlb, PAGE_SIZE);
  1391	again:
  1392		init_rss_vec(rss);
  1393		start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
  1394		pte = start_pte;
  1395		flush_tlb_batched_pending(mm);
  1396		arch_enter_lazy_mmu_mode();
  1397		do {
  1398			pte_t ptent = *pte;
  1399			struct page *page;
  1400	
  1401			if (pte_none(ptent))
  1402				continue;
  1403	
  1404			if (need_resched())
  1405				break;
  1406	
  1407			if (pte_present(ptent)) {
  1408				unsigned int delay_rmap;
  1409	
  1410				page = vm_normal_page(vma, addr, ptent);
  1411				if (unlikely(!should_zap_page(details, page)))
  1412					continue;
  1413				ptent = ptep_get_and_clear_full(mm, addr, pte,
  1414								tlb->fullmm);
  1415				tlb_remove_tlb_entry(tlb, pte, addr);
  1416				zap_install_uffd_wp_if_needed(vma, addr, pte, details,
  1417							      ptent);
  1418				if (unlikely(!page)) {
> 1419					ksm_notify_unmap_zero_page(mm, ptent);
  1420					continue;
  1421				}
  1422	
  1423				delay_rmap = 0;
  1424				if (!PageAnon(page)) {
  1425					if (pte_dirty(ptent)) {
  1426						set_page_dirty(page);
  1427						if (tlb_delay_rmap(tlb)) {
  1428							delay_rmap = 1;
  1429							force_flush = 1;
  1430						}
  1431					}
  1432					if (pte_young(ptent) && likely(vma_has_recency(vma)))
  1433						mark_page_accessed(page);
  1434				}
  1435				rss[mm_counter(page)]--;
  1436				if (!delay_rmap) {
  1437					page_remove_rmap(page, vma, false);
  1438					if (unlikely(page_mapcount(page) < 0))
  1439						print_bad_pte(vma, addr, ptent, page);
  1440				}
  1441				if (unlikely(__tlb_remove_page(tlb, page, delay_rmap))) {
  1442					force_flush = 1;
  1443					addr += PAGE_SIZE;
  1444					break;
  1445				}
  1446				continue;
  1447			}
  1448	
  1449			entry = pte_to_swp_entry(ptent);
  1450			if (is_device_private_entry(entry) ||
  1451			    is_device_exclusive_entry(entry)) {
  1452				page = pfn_swap_entry_to_page(entry);
  1453				if (unlikely(!should_zap_page(details, page)))
  1454					continue;
  1455				/*
  1456				 * Both device private/exclusive mappings should only
  1457				 * work with anonymous page so far, so we don't need to
  1458				 * consider uffd-wp bit when zap. For more information,
  1459				 * see zap_install_uffd_wp_if_needed().
  1460				 */
  1461				WARN_ON_ONCE(!vma_is_anonymous(vma));
  1462				rss[mm_counter(page)]--;
  1463				if (is_device_private_entry(entry))
  1464					page_remove_rmap(page, vma, false);
  1465				put_page(page);
  1466			} else if (!non_swap_entry(entry)) {
  1467				/* Genuine swap entry, hence a private anon page */
  1468				if (!should_zap_cows(details))
  1469					continue;
  1470				rss[MM_SWAPENTS]--;
  1471				if (unlikely(!free_swap_and_cache(entry)))
  1472					print_bad_pte(vma, addr, ptent, NULL);
  1473			} else if (is_migration_entry(entry)) {
  1474				page = pfn_swap_entry_to_page(entry);
  1475				if (!should_zap_page(details, page))
  1476					continue;
  1477				rss[mm_counter(page)]--;
  1478			} else if (pte_marker_entry_uffd_wp(entry)) {
  1479				/*
  1480				 * For anon: always drop the marker; for file: only
  1481				 * drop the marker if explicitly requested.
  1482				 */
  1483				if (!vma_is_anonymous(vma) &&
  1484				    !zap_drop_file_uffd_wp(details))
  1485					continue;
  1486			} else if (is_hwpoison_entry(entry) ||
  1487				   is_swapin_error_entry(entry)) {
  1488				if (!should_zap_cows(details))
  1489					continue;
  1490			} else {
  1491				/* We should have covered all the swap entry types */
  1492				WARN_ON_ONCE(1);
  1493			}
  1494			pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
  1495			zap_install_uffd_wp_if_needed(vma, addr, pte, details, ptent);
  1496		} while (pte++, addr += PAGE_SIZE, addr != end);
  1497	
  1498		add_mm_rss_vec(mm, rss);
  1499		arch_leave_lazy_mmu_mode();
  1500	
  1501		/* Do the actual TLB flush before dropping ptl */
  1502		if (force_flush) {
  1503			tlb_flush_mmu_tlbonly(tlb);
  1504			tlb_flush_rmaps(tlb, vma);
  1505		}
  1506		pte_unmap_unlock(start_pte, ptl);
  1507	
  1508		/*
  1509		 * If we forced a TLB flush (either due to running out of
  1510		 * batch buffers or because we needed to flush dirty TLB
  1511		 * entries before releasing the ptl), free the batched
  1512		 * memory too. Restart if we didn't do everything.
  1513		 */
  1514		if (force_flush) {
  1515			force_flush = 0;
  1516			tlb_flush_mmu(tlb);
  1517		}
  1518	
  1519		if (addr != end) {
  1520			cond_resched();
  1521			goto again;
  1522		}
  1523	
  1524		return addr;
  1525	}
  1526
  
xu May 29, 2023, 1:48 a.m. UTC | #4
Already fixed in PACTH v10.

>Hi Yang,
>
>kernel test robot noticed the following build errors:
>
>[auto build test ERROR on akpm-mm/mm-everything]
>[also build test ERROR on linus/master v6.4-rc3 next-20230525]
>[If your patch is applied to the wrong git tree, kindly drop us a note.
>And when submitting patch, we suggest to use '--base' as documented in
>https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
>url:    https://github.com/intel-lab-lkp/linux/commits/Yang-Yang/ksm-count-all-zero-pages-placed-by-KSM/20230524-153333
>base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
>patch link:    https://lore.kernel.org/r/20230524055800.20498-1-yang.yang29%40zte.com.cn
>patch subject: [PATCH v9 3/5] ksm: add ksm zero pages for each process
>config: nios2-defconfig
>compiler: nios2-linux-gcc (GCC) 12.1.0
>reproduce (this is a W=1 build):
>        mkdir -p ~/bin
>        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>        chmod +x ~/bin/make.cross
>        # https://github.com/intel-lab-lkp/linux/commit/c9da8338fa8f95db948cd4d826053d8f6cbcf19c
>        git remote add linux-review https://github.com/intel-lab-lkp/linux
>        git fetch --no-tags linux-review Yang-Yang/ksm-count-all-zero-pages-placed-by-KSM/20230524-153333
>        git checkout c9da8338fa8f95db948cd4d826053d8f6cbcf19c
>        # save the config file
>        mkdir build_dir && cp config build_dir/.config
>        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 ~/bin/make.cross W=1 O=build_dir ARCH=nios2 olddefconfig
>        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 ~/bin/make.cross W=1 O=build_dir ARCH=nios2 SHELL=/bin/bash
>
>If you fix the issue, kindly add following tag where applicable
>| Reported-by: kernel test robot <lkp@intel.com>
>| Closes: https://lore.kernel.org/oe-kbuild-all/202305251415.OLELa7qJ-lkp@intel.com/
>
>All errors (new ones prefixed by >>):
>
>   mm/memory.c: In function 'zap_pte_range':
>>> mm/memory.c:1419:60: error: incompatible type for argument 1 of 'ksm_notify_unmap_zero_page'
>    1419 |                                 ksm_notify_unmap_zero_page(mm, ptent);
>         |                                                            ^~
>         |                                                            |
>         |                                                            struct mm_struct *
>   In file included from mm/memory.c:56:
>   include/linux/ksm.h:116:53: note: expected 'pte_t' but argument is of type 'struct mm_struct *'
>     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
>         |                                               ~~~~~~^~~
>   mm/memory.c:1419:33: error: too many arguments to function 'ksm_notify_unmap_zero_page'
>    1419 |                                 ksm_notify_unmap_zero_page(mm, ptent);
>         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~
>   include/linux/ksm.h:116:20: note: declared here
>     116 | static inline void ksm_notify_unmap_zero_page(pte_t pte)
>         |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~
  

Patch

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 05452c3b9872..e407a34a46e8 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3209,6 +3209,7 @@  static int proc_pid_ksm_stat(struct seq_file *m, struct pid_namespace *ns,
 		seq_printf(m, "ksm_rmap_items %lu\n", mm->ksm_rmap_items);
 		seq_printf(m, "ksm_merging_pages %lu\n", mm->ksm_merging_pages);
 		seq_printf(m, "ksm_process_profit %ld\n", ksm_process_profit(mm));
+		seq_printf(m, "ksm_zero_pages %lu\n", mm->ksm_zero_pages);
 		mmput(mm);
 	}
 
diff --git a/include/linux/ksm.h b/include/linux/ksm.h
index f2d98c53cfec..0e6f04ac3f2b 100644
--- a/include/linux/ksm.h
+++ b/include/linux/ksm.h
@@ -35,10 +35,12 @@  void __ksm_exit(struct mm_struct *mm);
 
 extern unsigned long ksm_zero_pages;
 
-static inline void ksm_notify_unmap_zero_page(pte_t pte)
+static inline void ksm_notify_unmap_zero_page(struct mm_struct *mm, pte_t pte)
 {
-	if (is_ksm_zero_pte(pte))
+	if (is_ksm_zero_pte(pte)) {
 		ksm_zero_pages--;
+		mm->ksm_zero_pages--;
+	}
 }
 
 static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm)
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 306a3d1a0fa6..14f781509812 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -777,7 +777,7 @@  struct mm_struct {
 #ifdef CONFIG_KSM
 		/*
 		 * Represent how many pages of this process are involved in KSM
-		 * merging.
+		 * merging (not including ksm_zero_pages).
 		 */
 		unsigned long ksm_merging_pages;
 		/*
@@ -785,7 +785,12 @@  struct mm_struct {
 		 * including merged and not merged.
 		 */
 		unsigned long ksm_rmap_items;
-#endif
+		/*
+		 * Represent how many empty pages are merged with kernel zero
+		 * pages when enabling KSM use_zero_pages.
+		 */
+		unsigned long ksm_zero_pages;
+#endif /* CONFIG_KSM */
 #ifdef CONFIG_LRU_GEN
 		struct {
 			/* this mm_struct is on lru_gen_mm_list */
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index e417a928ef8d..85dc2e922f64 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -712,7 +712,7 @@  static void __collapse_huge_page_copy_succeeded(pte_t *pte,
 				spin_lock(ptl);
 				ptep_clear(vma->vm_mm, address, _pte);
 				spin_unlock(ptl);
-				ksm_notify_unmap_zero_page(pteval);
+				ksm_notify_unmap_zero_page(vma->vm_mm, pteval);
 			}
 		} else {
 			src_page = pte_page(pteval);
diff --git a/mm/ksm.c b/mm/ksm.c
index d3ed90159322..07a6fe7d7c99 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1231,6 +1231,7 @@  static int replace_page(struct vm_area_struct *vma, struct page *page,
 		 */
 		newpte = pte_mkdirty(pte_mkspecial(pfn_pte(page_to_pfn(kpage), vma->vm_page_prot)));
 		ksm_zero_pages++;
+		mm->ksm_zero_pages++;
 		/*
 		 * We're replacing an anonymous page with a zero page, which is
 		 * not anonymous. We need to do proper accounting otherwise we
diff --git a/mm/memory.c b/mm/memory.c
index 09c31160af4e..26bb291c1c72 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1416,7 +1416,7 @@  static unsigned long zap_pte_range(struct mmu_gather *tlb,
 			zap_install_uffd_wp_if_needed(vma, addr, pte, details,
 						      ptent);
 			if (unlikely(!page)) {
-				ksm_notify_unmap_zero_page(ptent);
+				ksm_notify_unmap_zero_page(mm, ptent);
 				continue;
 			}
 
@@ -3122,7 +3122,7 @@  static vm_fault_t wp_page_copy(struct vm_fault *vmf)
 				inc_mm_counter(mm, MM_ANONPAGES);
 			}
 		} else {
-			ksm_notify_unmap_zero_page(vmf->orig_pte);
+			ksm_notify_unmap_zero_page(mm, vmf->orig_pte);
 			inc_mm_counter(mm, MM_ANONPAGES);
 		}
 		flush_cache_page(vma, vmf->address, pte_pfn(vmf->orig_pte));