STRUCT MM_WALK_OPS(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

✨ struct mm_walk_ops(9) β€” Kernel API Manual, but make it make sense ✨

okay bestie, so this page is literally the <rainbow>struct mm_walk_ops</rainbow> page β€” it's the one in the Kernel API Manual and it's all about the callback vibes for walk_page_range. it's giving "directory of who to call when the walker hits each level of the page tables" and ngl it eats πŸ’…


🌸 NAME 🌸

struct mm_walk_ops β€” literally the callbacks for walk_page_range. that's it, that's the whole mood 🫢


✨ SYNOPSIS ✨

bestie, here's the whole struct, copied exactly so we don't get it twisted:

struct mm_walk_ops {
    int (*pgd_entry)(pgd_t *pgd, unsigned long addr, unsigned long next,
struct mm_walk *walk);
    int (*p4d_entry)(p4d_t *p4d, unsigned long addr, unsigned long next,
struct mm_walk *walk);
    int (*pud_entry)(pud_t *pud, unsigned long addr, unsigned long next,
struct mm_walk *walk);
    int (*pmd_entry)(pmd_t *pmd, unsigned long addr, unsigned long next,
struct mm_walk *walk);
    int (*pte_entry)(pte_t *pte, unsigned long addr, unsigned long next,
struct mm_walk *walk);
    int (*pte_hole)(unsigned long addr, unsigned long next, int depth,
struct mm_walk *walk);
    int (*hugetlb_entry)(pte_t *pte, unsigned long hmask, unsigned long
addr, unsigned long next, struct mm_walk *walk);
    int (*test_walk)(unsigned long addr, unsigned long next, struct
mm_walk *walk);
    int (*pre_vma)(unsigned long start, unsigned long end, struct
mm_walk *walk);
    void (*post_vma)(struct mm_walk *walk);
    int (*install_pte)(unsigned long addr, unsigned long next, pte_t
*ptep, struct mm_walk *walk);
    enum page_walk_lock walk_lock;
 };

πŸŽ€ Members πŸŽ€

okay so every single one of these, in order, no skips, we are NOT skipping the boring parts (there are no boring parts, iykyk):

  • pgd_entry β€” if you set it, it gets called for each non-empty PGD (top-level) entry. main character of the levels fr 🌈
  • p4d_entry β€” if set, called for each non-empty P4D entry. slay.
  • pud_entry β€” if set, called for each non-empty PUD entry. yup, we're going all the way down πŸ’…
  • pmd_entry β€” if set, called for each non-empty PMD entry, and heads up bestie: this handler is required to be able to handle pmd_trans_huge pmds. they may simply choose to split_huge_page instead of handling it explicitly. so like, you can't just ghost the THPs, you gotta have a plan 😭
  • pte_entry β€” if set, called for each PTE (lowest-level) entry including empty ones, except if install_pte is set. and if install_pte is set, pte_entry is called only for existing PTEs. very much a "depends on the situation" vibe.
  • pte_hole β€” if set, called for each hole at all levels. depth is -1 if not known, and otherwise 0:PGD, 1:P4D, 2:PUD, 3:PMD. any folded depths (where PTRS_PER_P?D is equal to 1) are skipped. also! if install_pte is specified, this will not trigger for any populated ranges. so many little conditions but we keep them all πŸ’–
  • hugetlb_entry β€” if set, called for each hugetlb entry. this hook function is called with the vma lock held, in order to protect against a concurrent freeing of the pte_t* or the ptl. in some cases, the hook function needs to drop and retake the vma lock in order to avoid deadlocks while calling other functions. and in such cases the hook function must either refrain from accessing the pte or ptl after dropping the vma lock, or else revalidate those items after re-acquiring the vma lock and before accessing them. read that part twice bestie, that's a real lock-discipline moment, no cap πŸ”₯
  • test_walk β€” a caller-specific callback function to determine whether we walk over the current vma or not. the return values are literally the whole personality of this one:
    • returning 0 means "do page table walk over the current vma"
    • returning a negative value means "abort current page table walk right now"
    • returning 1 means "skip the current vma"

and quick note: this callback is not called when the caller passes in a single VMA, as for walk_page_vma.

  • pre_vma β€” if set, called before starting walk on a non-null vma. like a little pre-game πŸŽ€
  • post_vma β€” if set, called after a walk on a non-null vma, provided that pre_vma and the vma walk succeeded. conditional queen ✨
  • install_pte β€” if set, missing page table entries are installed and thus all levels are always walked in the specified range. this callback is then invoked at the PTE level (having split any THP pages prior), providing the PTE to install. if allocations fail, the walk is aborted. this operation is only available for userland memory. Not usable for hugetlb ranges. (say it with me: not usable for hugetlb ranges 🫢)
  • walk_lock β€” the lock setting for the walk, typed as enum page_walk_lock. it's a member, it's here, it's iconic.

πŸ’œ Description πŸ’œ

okay so the p?d_entry callbacks are called even if those levels are folded on a particular architecture/configuration. so even when the level is literally folded away, the callback still goes off. that's the whole point of the note. don't come for me, that's what it says πŸ’…


πŸ¦‹ SEE ALSO πŸ¦‹

  • Kernel file ./include/linux/pagewalk.h β€” struct mm_walk(9)
  • struct folio_walk(9)

lowkey your takeaway, bestie: this struct is a call list for the page table walk, every callback is optional but each one has rules, and the hugetlb_entry lock stuff is the part where you slow down and read πŸ™ˆ

πŸŽ€ that's the whole page!! source lives at ./include/linux, dated October 2026, and it's filed under struct mm_walk_ops(9). periodt πŸ’–βœ¨

πŸ“¦ where this page comes from