Back to home page

LXR

 
 

    


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