STRUCT FOLIO(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’– struct folio(9) πŸ’–

okay so bestie, we're in the Kernel API Manual today and we're talking about struct folio β€” yes the big one, the main character of memory management, and I promise by the end of this you're gonna be obsessed. 🫢


✨ NAME ✨

struct folio β€” Represents a contiguous set of bytes.

like literally what it says on the tin. a contiguous set of bytes. that's her. that's the whole vibe. πŸ’…


🌸 SYNOPSIS 🌸

struct folio {
    memdesc_flags_t flags;
    union {
      struct list_head lru;
      unsigned int mlock_count;
      struct dev_pagemap *pgmap;
    };
    struct address_space *mapping;
    union {
      pgoff_t index;
      unsigned long share;
    };
    union {
      void *private;
      swp_entry_t swap;
      unsigned long migrate_info;
    };
    atomic_t _mapcount;
    atomic_t _refcount;
  #ifdef CONFIG_MEMCG;
    unsigned long memcg_data;
  #elif defined(CONFIG_SLAB_OBJ_EXT);
    unsigned long _unused_slab_obj_exts;
  #endif;
  #if defined(WANT_PAGE_VIRTUAL);
    void *virtual;
  #endif;
  #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS;
    int _last_cpupid;
  #endif;
    atomic_t _large_mapcount;
    atomic_t _nr_pages_mapped;
  #ifdef CONFIG_64BIT;
    atomic_t _entire_mapcount;
    atomic_t _pincount;
  #endif ;
    mm_id_mapcount_t _mm_id_mapcount[2];
    union {
      mm_id_t _mm_id[2];
      unsigned long _mm_ids;
    };
  #ifdef NR_PAGES_IN_LARGE_FOLIO;
    unsigned int _nr_pages;
  #endif ;
    struct list_head _deferred_list;
  #ifndef CONFIG_64BIT;
    atomic_t _entire_mapcount;
    atomic_t _pincount;
  #endif ;
    void *_hugetlb_subpool;
    void *_hugetlb_cgroup;
    void *_hugetlb_cgroup_rsvd;
    void *_hugetlb_hwpoison;
   };

ngl the preprocessor conditionals are giving "two different outfits depending on the CONFIG_ vibe check" and honestly? we respect the versatility. πŸ’€


πŸŽ€ Members πŸŽ€

here's the member-by-member tour, bestie. every single one, no skips, i would never πŸ™ˆ

  • flags β€” Identical to the page flags.
  • {unnamed_union} β€” anonymous
  • lru β€” Least Recently Used list; tracks how recently this folio was used.
  • mlock_count β€” Number of times this folio has been pinned by mlock.
  • pgmap β€” Metadata for ZONE_DEVICE mappings
  • mapping β€” The file this page belongs to, or refers to the anon_vma for anonymous memory.
  • {unnamed_union} β€” anonymous
  • index β€” Offset within the file, in units of pages. For anonymous memory, this is the index from the beginning of the mmap.
  • share β€” number of DAX mappings that reference this folio. See dax_associate_entry.
  • {unnamed_union} β€” anonymous
  • private β€” Filesystem per-folio data (see folio_attach_private).
  • swap β€” Used for swp_entry_t if folio_test_swapcache.
  • migrate_info β€” Stores migration state (anon_vma pointer and FOLIO_WAS_* markers).
  • _mapcount β€” Do not access this member directly. Use folio_mapcount to find out how many times this folio is mapped by userspace.
  • _refcount β€” Do not access this member directly. Use folio_ref_count to find how many references there are to this folio.
  • memcg_data β€” Memory Control Group data.
  • _unused_slab_obj_exts β€” Placeholder to match obj_exts in struct slab.
  • virtual β€” Virtual address in the kernel direct map.
  • _last_cpupid β€” IDs of last CPU and last process that accessed the folio.
  • _large_mapcount β€” Do not use directly, call folio_mapcount.
  • _nr_pages_mapped β€” Do not use outside of rmap and debug code.
  • _entire_mapcount β€” Do not use directly, call folio_entire_mapcount.
  • _pincount β€” Do not use directly, call folio_maybe_dma_pinned.
  • _mm_id_mapcount β€” Do not use outside of rmap code.
  • {unnamed_union} β€” anonymous
  • _mm_id β€” Do not use outside of rmap code.
  • _mm_ids β€” Do not use outside of rmap code.
  • _nr_pages β€” Do not use directly, call folio_nr_pages.
  • _deferred_list β€” Folios to be split under memory pressure.
  • _entire_mapcount β€” Do not use directly, call folio_entire_mapcount.
  • _pincount β€” Do not use directly, call folio_maybe_dma_pinned.
  • _hugetlb_subpool β€” Do not use directly, use accessor in hugetlb.h.
  • _hugetlb_cgroup β€” Do not use directly, use accessor in hugetlb_cgroup.h.
  • _hugetlb_cgroup_rsvd β€” Do not use directly, use accessor in hugetlb_cgroup.h.
  • _hugetlb_hwpoison β€” Do not use directly, call raw_hwp_list_head.
⚠️ okay real talk bestie β€” see how many of these say "do not access directly" / "do not use directly" / "do not use outside of rmap code"? that is NOT a suggestion. those fields are private. you use the accessor function, every time, no exceptions, i'm literally begging. the kernel will not be nice about it and neither will the debugging session. 😭

also yes, _entire_mapcount and _pincount show up twice in that list β€” once for the CONFIG_64BIT branch, once for the #ifndef CONFIG_64BIT branch. only one of them is ever actually compiled in. it's giving "same fit, different season" 🌈


πŸ‘‘ Description πŸ‘‘

A folio is a physically, virtually and logically contiguous set of bytes. It is a power-of-two in size, and it is aligned to that same power-of-two. It is at least as large as PAGE_SIZE. If it is in the page cache, it is at a file offset which is a multiple of that power-of-two. It may be mapped into userspace at an address which is an arbitrary page offset, but its kernel virtual address is aligned to its size.

okay so let me translate: power-of-two size, aligned to that same power-of-two, never smaller than PAGE_SIZE β€” the whole thing is so consistent, it's giving main character energy fr fr ✨


πŸ¦‹ SEE ALSO πŸ¦‹


and that's the page!! you ate that, bestie, go read mm_types.h and slay πŸ’œ

πŸŽ€ sign-off: this little masterpiece lives in ./include/linux and it's dated October 2026 β€” yes, we're being that specific. mwah. πŸ’–πŸŒΈ
πŸ“¦ where this page comes from