mm: introduce mapping AS_WORKINGSET flag From: Konstantin Khlebnikov This patch introduces new flag AS_WORKINGSET in mapping->flags. If it set reclaimer will activates all pages for this inode after first usage. Signed-off-by: Konstantin Khlebnikov --- include/linux/pagemap.h | 16 ++++++++++++++++ mm/vmscan.c | 15 ++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index cfaaa69..c15fc17 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -24,6 +24,7 @@ enum mapping_flags { AS_ENOSPC = __GFP_BITS_SHIFT + 1, /* ENOSPC on async write */ AS_MM_ALL_LOCKS = __GFP_BITS_SHIFT + 2, /* under mm_take_all_locks() */ AS_UNEVICTABLE = __GFP_BITS_SHIFT + 3, /* e.g., ramdisk, SHM_LOCK */ + AS_WORKINGSET = __GFP_BITS_SHIFT + 4, /* promote pages activation */ }; static inline void mapping_set_error(struct address_space *mapping, int error) @@ -53,6 +54,21 @@ static inline int mapping_unevictable(struct address_space *mapping) return !!mapping; } +static inline void mapping_set_workingset(struct address_space *mapping) +{ + set_bit(AS_WORKINGSET, &mapping->flags); +} + +static inline void mapping_clear_workingset(struct address_space *mapping) +{ + clear_bit(AS_WORKINGSET, &mapping->flags); +} + +static inline int mapping_test_workingset(struct address_space *mapping) +{ + return mapping && test_bit(AS_WORKINGSET, &mapping->flags); +} + static inline gfp_t mapping_gfp_mask(struct address_space * mapping) { return (__force gfp_t)mapping->flags & __GFP_BITS_MASK; diff --git a/mm/vmscan.c b/mm/vmscan.c index 57b9658..5ccbe8c 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -701,6 +701,7 @@ enum page_references { }; static enum page_references page_check_references(struct page *page, + struct address_space *mapping, struct mem_cgroup_zone *mz, struct scan_control *sc) { @@ -721,6 +722,13 @@ static enum page_references page_check_references(struct page *page, if (vm_flags & VM_LOCKED) return PAGEREF_RECLAIM; + /* + * Activate workingset page if referenced at least once. + */ + if (mapping_test_workingset(mapping) && + (referenced_ptes || referenced_page)) + return PAGEREF_ACTIVATE; + if (referenced_ptes) { if (PageAnon(page)) return PAGEREF_ACTIVATE; @@ -828,7 +836,9 @@ static unsigned long shrink_page_list(struct list_head *page_list, } } - references = page_check_references(page, mz, sc); + mapping = page_mapping(page); + + references = page_check_references(page, mapping, mz, sc); switch (references) { case PAGEREF_ACTIVATE: goto activate_locked; @@ -848,11 +858,10 @@ static unsigned long shrink_page_list(struct list_head *page_list, goto keep_locked; if (!add_to_swap(page)) goto activate_locked; + mapping = &swapper_space; may_enter_fs = 1; } - mapping = page_mapping(page); - /* * The page is mapped into the page tables of one or more * processes. Try to unmap it here.