Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/init.h>
0003 #include <linux/memblock.h>
0004 #include <linux/fs.h>
0005 #include <linux/sysfs.h>
0006 #include <linux/kobject.h>
0007 #include <linux/memory_hotplug.h>
0008 #include <linux/mm.h>
0009 #include <linux/mmzone.h>
0010 #include <linux/pagemap.h>
0011 #include <linux/rmap.h>
0012 #include <linux/mmu_notifier.h>
0013 #include <linux/page_ext.h>
0014 #include <linux/page_idle.h>
0015 
0016 #include "internal.h"
0017 
0018 #define BITMAP_CHUNK_SIZE   sizeof(u64)
0019 #define BITMAP_CHUNK_BITS   (BITMAP_CHUNK_SIZE * BITS_PER_BYTE)
0020 
0021 /*
0022  * Idle page tracking only considers user memory pages, for other types of
0023  * pages the idle flag is always unset and an attempt to set it is silently
0024  * ignored.
0025  *
0026  * We treat a page as a user memory page if it is on an LRU list, because it is
0027  * always safe to pass such a page to rmap_walk(), which is essential for idle
0028  * page tracking. With such an indicator of user pages we can skip isolated
0029  * pages, but since there are not usually many of them, it will hardly affect
0030  * the overall result.
0031  *
0032  * This function tries to get a user memory page by pfn as described above.
0033  */
0034 static struct page *page_idle_get_page(unsigned long pfn)
0035 {
0036     struct page *page = pfn_to_online_page(pfn);
0037 
0038     if (!page || !PageLRU(page) ||
0039         !get_page_unless_zero(page))
0040         return NULL;
0041 
0042     if (unlikely(!PageLRU(page))) {
0043         put_page(page);
0044         page = NULL;
0045     }
0046     return page;
0047 }
0048 
0049 static bool page_idle_clear_pte_refs_one(struct folio *folio,
0050                     struct vm_area_struct *vma,
0051                     unsigned long addr, void *arg)
0052 {
0053     DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, addr, 0);
0054     bool referenced = false;
0055 
0056     while (page_vma_mapped_walk(&pvmw)) {
0057         addr = pvmw.address;
0058         if (pvmw.pte) {
0059             /*
0060              * For PTE-mapped THP, one sub page is referenced,
0061              * the whole THP is referenced.
0062              */
0063             if (ptep_clear_young_notify(vma, addr, pvmw.pte))
0064                 referenced = true;
0065         } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
0066             if (pmdp_clear_young_notify(vma, addr, pvmw.pmd))
0067                 referenced = true;
0068         } else {
0069             /* unexpected pmd-mapped page? */
0070             WARN_ON_ONCE(1);
0071         }
0072     }
0073 
0074     if (referenced) {
0075         folio_clear_idle(folio);
0076         /*
0077          * We cleared the referenced bit in a mapping to this page. To
0078          * avoid interference with page reclaim, mark it young so that
0079          * folio_referenced() will return > 0.
0080          */
0081         folio_set_young(folio);
0082     }
0083     return true;
0084 }
0085 
0086 static void page_idle_clear_pte_refs(struct page *page)
0087 {
0088     struct folio *folio = page_folio(page);
0089 
0090     /*
0091      * Since rwc.try_lock is unused, rwc is effectively immutable, so we
0092      * can make it static to save some cycles and stack.
0093      */
0094     static struct rmap_walk_control rwc = {
0095         .rmap_one = page_idle_clear_pte_refs_one,
0096         .anon_lock = folio_lock_anon_vma_read,
0097     };
0098     bool need_lock;
0099 
0100     if (!folio_mapped(folio) || !folio_raw_mapping(folio))
0101         return;
0102 
0103     need_lock = !folio_test_anon(folio) || folio_test_ksm(folio);
0104     if (need_lock && !folio_trylock(folio))
0105         return;
0106 
0107     rmap_walk(folio, &rwc);
0108 
0109     if (need_lock)
0110         folio_unlock(folio);
0111 }
0112 
0113 static ssize_t page_idle_bitmap_read(struct file *file, struct kobject *kobj,
0114                      struct bin_attribute *attr, char *buf,
0115                      loff_t pos, size_t count)
0116 {
0117     u64 *out = (u64 *)buf;
0118     struct page *page;
0119     unsigned long pfn, end_pfn;
0120     int bit;
0121 
0122     if (pos % BITMAP_CHUNK_SIZE || count % BITMAP_CHUNK_SIZE)
0123         return -EINVAL;
0124 
0125     pfn = pos * BITS_PER_BYTE;
0126     if (pfn >= max_pfn)
0127         return 0;
0128 
0129     end_pfn = pfn + count * BITS_PER_BYTE;
0130     if (end_pfn > max_pfn)
0131         end_pfn = max_pfn;
0132 
0133     for (; pfn < end_pfn; pfn++) {
0134         bit = pfn % BITMAP_CHUNK_BITS;
0135         if (!bit)
0136             *out = 0ULL;
0137         page = page_idle_get_page(pfn);
0138         if (page) {
0139             if (page_is_idle(page)) {
0140                 /*
0141                  * The page might have been referenced via a
0142                  * pte, in which case it is not idle. Clear
0143                  * refs and recheck.
0144                  */
0145                 page_idle_clear_pte_refs(page);
0146                 if (page_is_idle(page))
0147                     *out |= 1ULL << bit;
0148             }
0149             put_page(page);
0150         }
0151         if (bit == BITMAP_CHUNK_BITS - 1)
0152             out++;
0153         cond_resched();
0154     }
0155     return (char *)out - buf;
0156 }
0157 
0158 static ssize_t page_idle_bitmap_write(struct file *file, struct kobject *kobj,
0159                       struct bin_attribute *attr, char *buf,
0160                       loff_t pos, size_t count)
0161 {
0162     const u64 *in = (u64 *)buf;
0163     struct page *page;
0164     unsigned long pfn, end_pfn;
0165     int bit;
0166 
0167     if (pos % BITMAP_CHUNK_SIZE || count % BITMAP_CHUNK_SIZE)
0168         return -EINVAL;
0169 
0170     pfn = pos * BITS_PER_BYTE;
0171     if (pfn >= max_pfn)
0172         return -ENXIO;
0173 
0174     end_pfn = pfn + count * BITS_PER_BYTE;
0175     if (end_pfn > max_pfn)
0176         end_pfn = max_pfn;
0177 
0178     for (; pfn < end_pfn; pfn++) {
0179         bit = pfn % BITMAP_CHUNK_BITS;
0180         if ((*in >> bit) & 1) {
0181             page = page_idle_get_page(pfn);
0182             if (page) {
0183                 page_idle_clear_pte_refs(page);
0184                 set_page_idle(page);
0185                 put_page(page);
0186             }
0187         }
0188         if (bit == BITMAP_CHUNK_BITS - 1)
0189             in++;
0190         cond_resched();
0191     }
0192     return (char *)in - buf;
0193 }
0194 
0195 static struct bin_attribute page_idle_bitmap_attr =
0196         __BIN_ATTR(bitmap, 0600,
0197                page_idle_bitmap_read, page_idle_bitmap_write, 0);
0198 
0199 static struct bin_attribute *page_idle_bin_attrs[] = {
0200     &page_idle_bitmap_attr,
0201     NULL,
0202 };
0203 
0204 static const struct attribute_group page_idle_attr_group = {
0205     .bin_attrs = page_idle_bin_attrs,
0206     .name = "page_idle",
0207 };
0208 
0209 static int __init page_idle_init(void)
0210 {
0211     int err;
0212 
0213     err = sysfs_create_group(mm_kobj, &page_idle_attr_group);
0214     if (err) {
0215         pr_err("page_idle: register sysfs failed\n");
0216         return err;
0217     }
0218     return 0;
0219 }
0220 subsys_initcall(page_idle_init);