OSDN Git Service

Merge tag 'timers-urgent-2023-09-02' of git://git.kernel.org/pub/scm/linux/kernel...
[tomoyo/tomoyo-test1.git] / mm / ksm.c
index d7b5b95..8d6aee0 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -242,6 +242,9 @@ static struct kmem_cache *rmap_item_cache;
 static struct kmem_cache *stable_node_cache;
 static struct kmem_cache *mm_slot_cache;
 
+/* The number of pages scanned */
+static unsigned long ksm_pages_scanned;
+
 /* The number of nodes in the stable tree */
 static unsigned long ksm_pages_shared;
 
@@ -278,6 +281,9 @@ static unsigned int zero_checksum __read_mostly;
 /* Whether to merge empty (zeroed) pages with actual zero pages */
 static bool ksm_use_zero_pages __read_mostly;
 
+/* The number of zero pages which is placed by KSM */
+unsigned long ksm_zero_pages;
+
 #ifdef CONFIG_NUMA
 /* Zeroed when merging across nodes is not allowed */
 static unsigned int ksm_merge_across_nodes = 1;
@@ -448,7 +454,8 @@ static int break_ksm_pmd_entry(pmd_t *pmd, unsigned long addr, unsigned long nex
                if (is_migration_entry(entry))
                        page = pfn_swap_entry_to_page(entry);
        }
-       ret = page && PageKsm(page);
+       /* return 1 if the page is an normal ksm page or KSM-placed zero page */
+       ret = (page && PageKsm(page)) || is_ksm_zero_pte(*pte);
        pte_unmap_unlock(pte, ptl);
        return ret;
 }
@@ -1229,8 +1236,14 @@ static int replace_page(struct vm_area_struct *vma, struct page *page,
                page_add_anon_rmap(kpage, vma, addr, RMAP_NONE);
                newpte = mk_pte(kpage, vma->vm_page_prot);
        } else {
-               newpte = pte_mkspecial(pfn_pte(page_to_pfn(kpage),
-                                              vma->vm_page_prot));
+               /*
+                * Use pte_mkdirty to mark the zero page mapped by KSM, and then
+                * we can easily track all KSM-placed zero pages by checking if
+                * the dirty bit in zero page's PTE is set.
+                */
+               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
@@ -2473,8 +2486,9 @@ static void ksm_do_scan(unsigned int scan_npages)
 {
        struct ksm_rmap_item *rmap_item;
        struct page *page;
+       unsigned int npages = scan_npages;
 
-       while (scan_npages-- && likely(!freezing(current))) {
+       while (npages-- && likely(!freezing(current))) {
                cond_resched();
                rmap_item = scan_get_next_rmap_item(&page);
                if (!rmap_item)
@@ -2482,6 +2496,8 @@ static void ksm_do_scan(unsigned int scan_npages)
                cmp_and_merge_page(page, rmap_item);
                put_page(page);
        }
+
+       ksm_pages_scanned += scan_npages - npages;
 }
 
 static int ksmd_should_run(void)
@@ -3091,7 +3107,7 @@ static void wait_while_offlining(void)
 #ifdef CONFIG_PROC_FS
 long ksm_process_profit(struct mm_struct *mm)
 {
-       return mm->ksm_merging_pages * PAGE_SIZE -
+       return (long)(mm->ksm_merging_pages + mm->ksm_zero_pages) * PAGE_SIZE -
                mm->ksm_rmap_items * sizeof(struct ksm_rmap_item);
 }
 #endif /* CONFIG_PROC_FS */
@@ -3322,6 +3338,13 @@ static ssize_t max_page_sharing_store(struct kobject *kobj,
 }
 KSM_ATTR(max_page_sharing);
 
+static ssize_t pages_scanned_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
+{
+       return sysfs_emit(buf, "%lu\n", ksm_pages_scanned);
+}
+KSM_ATTR_RO(pages_scanned);
+
 static ssize_t pages_shared_show(struct kobject *kobj,
                                 struct kobj_attribute *attr, char *buf)
 {
@@ -3360,12 +3383,19 @@ static ssize_t pages_volatile_show(struct kobject *kobj,
 }
 KSM_ATTR_RO(pages_volatile);
 
+static ssize_t ksm_zero_pages_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buf)
+{
+       return sysfs_emit(buf, "%ld\n", ksm_zero_pages);
+}
+KSM_ATTR_RO(ksm_zero_pages);
+
 static ssize_t general_profit_show(struct kobject *kobj,
                                   struct kobj_attribute *attr, char *buf)
 {
        long general_profit;
 
-       general_profit = ksm_pages_sharing * PAGE_SIZE -
+       general_profit = (ksm_pages_sharing + ksm_zero_pages) * PAGE_SIZE -
                                ksm_rmap_items * sizeof(struct ksm_rmap_item);
 
        return sysfs_emit(buf, "%ld\n", general_profit);
@@ -3423,10 +3453,12 @@ static struct attribute *ksm_attrs[] = {
        &sleep_millisecs_attr.attr,
        &pages_to_scan_attr.attr,
        &run_attr.attr,
+       &pages_scanned_attr.attr,
        &pages_shared_attr.attr,
        &pages_sharing_attr.attr,
        &pages_unshared_attr.attr,
        &pages_volatile_attr.attr,
+       &ksm_zero_pages_attr.attr,
        &full_scans_attr.attr,
 #ifdef CONFIG_NUMA
        &merge_across_nodes_attr.attr,