mm: multi-gen LRU: minimal implementation
[linux-2.6-microblaze.git] / include / linux / mm_inline.h
index 2ff7039..f2b2296 100644 (file)
@@ -121,6 +121,33 @@ static inline int lru_gen_from_seq(unsigned long seq)
        return seq % MAX_NR_GENS;
 }
 
+static inline int lru_hist_from_seq(unsigned long seq)
+{
+       return seq % NR_HIST_GENS;
+}
+
+static inline int lru_tier_from_refs(int refs)
+{
+       VM_WARN_ON_ONCE(refs > BIT(LRU_REFS_WIDTH));
+
+       /* see the comment in folio_lru_refs() */
+       return order_base_2(refs + 1);
+}
+
+static inline int folio_lru_refs(struct folio *folio)
+{
+       unsigned long flags = READ_ONCE(folio->flags);
+       bool workingset = flags & BIT(PG_workingset);
+
+       /*
+        * Return the number of accesses beyond PG_referenced, i.e., N-1 if the
+        * total number of accesses is N>1, since N=0,1 both map to the first
+        * tier. lru_tier_from_refs() will account for this off-by-one. Also see
+        * the comment on MAX_NR_TIERS.
+        */
+       return ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + workingset;
+}
+
 static inline int folio_lru_gen(struct folio *folio)
 {
        unsigned long flags = READ_ONCE(folio->flags);
@@ -173,6 +200,15 @@ static inline void lru_gen_update_size(struct lruvec *lruvec, struct folio *foli
                __update_lru_size(lruvec, lru, zone, -delta);
                return;
        }
+
+       /* promotion */
+       if (!lru_gen_is_active(lruvec, old_gen) && lru_gen_is_active(lruvec, new_gen)) {
+               __update_lru_size(lruvec, lru, zone, -delta);
+               __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta);
+       }
+
+       /* demotion requires isolation, e.g., lru_deactivate_fn() */
+       VM_WARN_ON_ONCE(lru_gen_is_active(lruvec, old_gen) && !lru_gen_is_active(lruvec, new_gen));
 }
 
 static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio, bool reclaiming)