From: kernel test robot <lkp@intel.com>
To: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
Cc: llvm@lists.linux.dev, oe-kbuild-all@lists.linux.dev
Subject: [kas:collapse/rfc-v1 27/76] mm/collapse.c:302:29: error: call to undeclared function 'folio_test_young'; ISO C99 and later do not support implicit function declarations
Date: Wed, 19 Aug 2026 03:35:48 +0800 [thread overview]
Message-ID: <202608190330.FdsN6Kj3-lkp@intel.com> (raw)
tree: https://git.kernel.org/pub/scm/linux/kernel/git/kas/linux.git collapse/rfc-v1
head: efac4ce42bf9ea34a32d1563fe3370ee837a751f
commit: cb521dbfccdeb167af52e321f0396a75be2796a9 [27/76] mm/collapse: scan a table for what a collapse could use
config: i386-buildonly-randconfig-002-20260818 (https://download.01.org/0day-ci/archive/20260819/202608190330.FdsN6Kj3-lkp@intel.com/config)
compiler: clang version 22.1.3 (https://github.com/llvm/llvm-project e9846648fd6183ee6d8cbdb4502213fcf902a211)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260819/202608190330.FdsN6Kj3-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608190330.FdsN6Kj3-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from mm/collapse.c:8:
In file included from include/linux/leafops.h:11:
include/linux/swapops.h:88:21: error: use of undeclared identifier 'MAX_SWAPFILES_SHIFT'
88 | ret.val = (type << SWP_TYPE_SHIFT) | (offset & SWP_OFFSET_MASK);
| ^~~~~~~~~~~~~~
include/linux/swapops.h:27:45: note: expanded from macro 'SWP_TYPE_SHIFT'
27 | #define SWP_TYPE_SHIFT (BITS_PER_XA_VALUE - MAX_SWAPFILES_SHIFT)
| ^~~~~~~~~~~~~~~~~~~
include/linux/swapops.h:88:49: error: use of undeclared identifier 'MAX_SWAPFILES_SHIFT'
88 | ret.val = (type << SWP_TYPE_SHIFT) | (offset & SWP_OFFSET_MASK);
| ^~~~~~~~~~~~~~~
include/linux/swapops.h:28:34: note: expanded from macro 'SWP_OFFSET_MASK'
28 | #define SWP_OFFSET_MASK ((1UL << SWP_TYPE_SHIFT) - 1)
| ^~~~~~~~~~~~~~
include/linux/swapops.h:27:45: note: expanded from macro 'SWP_TYPE_SHIFT'
27 | #define SWP_TYPE_SHIFT (BITS_PER_XA_VALUE - MAX_SWAPFILES_SHIFT)
| ^~~~~~~~~~~~~~~~~~~
include/linux/swapops.h:98:23: error: use of undeclared identifier 'MAX_SWAPFILES_SHIFT'
98 | return (entry.val >> SWP_TYPE_SHIFT);
| ^~~~~~~~~~~~~~
include/linux/swapops.h:27:45: note: expanded from macro 'SWP_TYPE_SHIFT'
27 | #define SWP_TYPE_SHIFT (BITS_PER_XA_VALUE - MAX_SWAPFILES_SHIFT)
| ^~~~~~~~~~~~~~~~~~~
include/linux/swapops.h:107:21: error: use of undeclared identifier 'MAX_SWAPFILES_SHIFT'
107 | return entry.val & SWP_OFFSET_MASK;
| ^~~~~~~~~~~~~~~
include/linux/swapops.h:28:34: note: expanded from macro 'SWP_OFFSET_MASK'
28 | #define SWP_OFFSET_MASK ((1UL << SWP_TYPE_SHIFT) - 1)
| ^~~~~~~~~~~~~~
include/linux/swapops.h:27:45: note: expanded from macro 'SWP_TYPE_SHIFT'
27 | #define SWP_TYPE_SHIFT (BITS_PER_XA_VALUE - MAX_SWAPFILES_SHIFT)
| ^~~~~~~~~~~~~~~~~~~
include/linux/swapops.h:173:19: error: use of undeclared identifier 'SWP_MIGRATION_READ'; did you mean 'THP_MIGRATION_FAIL'?
173 | return swp_entry(SWP_MIGRATION_READ, offset);
| ^~~~~~~~~~~~~~~~~~
| THP_MIGRATION_FAIL
include/linux/vm_event_item.h:62:3: note: 'THP_MIGRATION_FAIL' declared here
62 | THP_MIGRATION_FAIL,
| ^
In file included from mm/collapse.c:8:
In file included from include/linux/leafops.h:11:
include/linux/swapops.h:178:19: error: use of undeclared identifier 'SWP_MIGRATION_READ_EXCLUSIVE'
178 | return swp_entry(SWP_MIGRATION_READ_EXCLUSIVE, offset);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/swapops.h:183:19: error: use of undeclared identifier 'SWP_MIGRATION_WRITE'
183 | return swp_entry(SWP_MIGRATION_WRITE, offset);
| ^~~~~~~~~~~~~~~~~~~
include/linux/swapops.h:204:26: error: use of undeclared identifier 'MAX_SWAPFILES_SHIFT'
204 | swp_offset(entry) | SWP_MIG_YOUNG);
| ^~~~~~~~~~~~~
include/linux/swapops.h:66:29: note: expanded from macro 'SWP_MIG_YOUNG'
66 | #define SWP_MIG_YOUNG BIT(SWP_MIG_YOUNG_BIT)
| ^~~~~~~~~~~~~~~~~
include/linux/swapops.h:62:29: note: expanded from macro 'SWP_MIG_YOUNG_BIT'
62 | #define SWP_MIG_YOUNG_BIT (SWP_PFN_BITS)
| ^~~~~~~~~~~~
include/linux/swapops.h:40:11: note: expanded from macro 'SWP_PFN_BITS'
40 | SWP_TYPE_SHIFT)
| ^~~~~~~~~~~~~~
include/linux/swapops.h:27:45: note: expanded from macro 'SWP_TYPE_SHIFT'
27 | #define SWP_TYPE_SHIFT (BITS_PER_XA_VALUE - MAX_SWAPFILES_SHIFT)
| ^~~~~~~~~~~~~~~~~~~
include/linux/swapops.h:212:26: error: use of undeclared identifier 'MAX_SWAPFILES_SHIFT'
212 | swp_offset(entry) | SWP_MIG_DIRTY);
| ^~~~~~~~~~~~~
include/linux/swapops.h:67:29: note: expanded from macro 'SWP_MIG_DIRTY'
67 | #define SWP_MIG_DIRTY BIT(SWP_MIG_DIRTY_BIT)
| ^~~~~~~~~~~~~~~~~
include/linux/swapops.h:63:29: note: expanded from macro 'SWP_MIG_DIRTY_BIT'
63 | #define SWP_MIG_DIRTY_BIT (SWP_PFN_BITS + 1)
| ^~~~~~~~~~~~
include/linux/swapops.h:40:11: note: expanded from macro 'SWP_PFN_BITS'
40 | SWP_TYPE_SHIFT)
| ^~~~~~~~~~~~~~
include/linux/swapops.h:27:45: note: expanded from macro 'SWP_TYPE_SHIFT'
27 | #define SWP_TYPE_SHIFT (BITS_PER_XA_VALUE - MAX_SWAPFILES_SHIFT)
| ^~~~~~~~~~~~~~~~~~~
include/linux/swapops.h:260:19: error: use of undeclared identifier 'SWP_HWPOISON'; did you mean 'FOLL_HWPOISON'?
260 | return swp_entry(SWP_HWPOISON, page_to_pfn(page));
| ^~~~~~~~~~~~
| FOLL_HWPOISON
include/linux/mm_types.h:1904:2: note: 'FOLL_HWPOISON' declared here
1904 | FOLL_HWPOISON = 1 << 6,
| ^
In file included from mm/collapse.c:8:
In file included from include/linux/leafops.h:11:
include/linux/swapops.h:265:28: error: use of undeclared identifier 'SWP_HWPOISON'; did you mean 'FOLL_HWPOISON'?
265 | return swp_type(entry) == SWP_HWPOISON;
| ^~~~~~~~~~~~
| FOLL_HWPOISON
include/linux/mm_types.h:1904:2: note: 'FOLL_HWPOISON' declared here
1904 | FOLL_HWPOISON = 1 << 6,
| ^
In file included from mm/collapse.c:8:
In file included from include/linux/leafops.h:11:
include/linux/swapops.h:304:19: error: use of undeclared identifier 'SWP_PTE_MARKER'
304 | return swp_entry(SWP_PTE_MARKER, marker);
| ^~~~~~~~~~~~~~
>> mm/collapse.c:302:29: error: call to undeclared function 'folio_test_young'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
302 | (pte_young(pteval) || folio_test_young(folio) ||
| ^
13 errors generated.
vim +/folio_test_young +302 mm/collapse.c
102
103 /*
104 * Scan the PTEs between @start and @end and record what a collapse could use: a
105 * bit in cc->eligible_ptes for every PTE that may be a source. Returns
106 * SCAN_SUCCEED when every PTE in the range qualified, otherwise the reason one
107 * did not, and narrows cc->select_orders to what is still worth trying here.
108 */
109 static enum scan_result collapse_scan_table(struct vm_area_struct *vma,
110 pmd_t *pmd, unsigned long start,
111 unsigned long end,
112 struct collapse_control *cc)
113 {
114 const unsigned long pmd_addr = start & HPAGE_PMD_MASK;
115 unsigned int max_ptes_none, max_ptes_swap, max_ptes_shared;
116 int none_or_zero = 0, shared = 0, referenced = 0, unmapped = 0;
117 enum scan_result result, pmd_result = SCAN_SUCCEED;
118 unsigned int first_offset;
119 unsigned long addr;
120 pte_t *pte;
121 int i;
122
123 max_ptes_none = collapse_max_ptes_none(cc, vma, HPAGE_PMD_ORDER);
124 max_ptes_swap = collapse_max_ptes_swap(cc, HPAGE_PMD_ORDER);
125 max_ptes_shared = collapse_max_ptes_shared(cc, HPAGE_PMD_ORDER);
126
127 /*
128 * No page table lock: what this builds is advice, and the freeze settles
129 * every question it asks by re-reading the table under the lock and
130 * freezing each source to the count it expects. A racy read can only
131 * cost a candidate that the freeze then refuses, or miss one that the
132 * next pass finds. What it buys is that a fault in this range does not
133 * wait for a scan of the whole table.
134 *
135 * pte_offset_map() holds rcu_read_lock() until pte_unmap(), which is
136 * what keeps the table itself from being freed underneath the walk;
137 * mmap_lock keeps the VMA attached, without which free_pgtables() could
138 * free it without waiting for RCU at all. Nothing below here sleeps.
139 */
140 pte = pte_offset_map(pmd, start);
141 if (!pte) {
142 cc->progress++;
143 result = SCAN_NO_PTE_TABLE;
144 goto out_no_table;
145 }
146
147 /*
148 * The bitmap and the selection offsets stay relative to the table:
149 * natural-alignment math needs the table-absolute position, not the
150 * position within an arbitrarily placed VMA.
151 */
152 first_offset = (start - pmd_addr) >> PAGE_SHIFT;
153 for (i = first_offset, addr = start; addr < end;
154 i++, addr += PAGE_SIZE) {
155 pte_t pteval = ptep_get(pte + (i - first_offset));
156 struct folio *folio;
157 struct page *page;
158 int node;
159
160 cc->progress++;
161
162 if (pte_none_or_zero(pteval)) {
163 if (++none_or_zero > max_ptes_none &&
164 pmd_result == SCAN_SUCCEED) {
165 pmd_result = SCAN_EXCEED_NONE_PTE;
166 count_vm_event(THP_SCAN_EXCEED_NONE_PTE);
167 count_mthp_stat(HPAGE_PMD_ORDER,
168 MTHP_STAT_COLLAPSE_EXCEED_NONE);
169 }
170 continue;
171 }
172 if (!pte_present(pteval)) {
173 unmapped++;
174 if (collapse_exceeds_limit(unmapped, max_ptes_swap,
175 start, end)) {
176 result = SCAN_EXCEED_SWAP_PTE;
177 count_vm_event(THP_SCAN_EXCEED_SWAP_PTE);
178 count_mthp_stat(HPAGE_PMD_ORDER,
179 MTHP_STAT_COLLAPSE_EXCEED_SWAP);
180 goto out_table_refused;
181 }
182 /* Swap entries armed with uffd-wp are refused too */
183 if (pte_swp_uffd_any(pteval) &&
184 pmd_result == SCAN_SUCCEED)
185 pmd_result = SCAN_PTE_UFFD;
186 continue;
187 }
188 if (pte_uffd(pteval)) {
189 /*
190 * The huge PMD could be marked write protected when any
191 * of the small ones is, but that could deliver
192 * userfaults outside the registered range. Keep it
193 * simple and refuse the PTE.
194 */
195 if (pmd_result == SCAN_SUCCEED)
196 pmd_result = SCAN_PTE_UFFD;
197 continue;
198 }
199
200 page = vm_normal_page(vma, addr, pteval);
201 if (unlikely(!page) || unlikely(is_zone_device_page(page))) {
202 if (pmd_result == SCAN_SUCCEED)
203 pmd_result = SCAN_PAGE_NULL;
204 continue;
205 }
206 folio = page_folio(page);
207
208 /*
209 * A VM_DROPPABLE VMA keeps the lazyfree property across the
210 * collapse, so there is nothing to preserve by skipping.
211 */
212 if (cc->policy.skip_lazyfree &&
213 !(vma->vm_flags & VM_DROPPABLE) &&
214 folio_test_lazyfree(folio) && !pte_dirty(pteval)) {
215 if (pmd_result == SCAN_SUCCEED)
216 pmd_result = SCAN_PAGE_LAZYFREE;
217 continue;
218 }
219
220 if (!folio_test_anon(folio)) {
221 if (pmd_result == SCAN_SUCCEED)
222 pmd_result = SCAN_PAGE_ANON;
223 continue;
224 }
225
226 /*
227 * A page counts as shared if any part of its folio is, which
228 * bounds the cost of CoW-breaking rather than the count of it:
229 * collapse_faultin() unshares on !PageAnonExclusive(), a broader
230 * test -- a page whose fork co-mapper has exited is
231 * single-mapped, so not counted here, yet stays non-exclusive
232 * until a write reuses it. Those are the cheap ones, reused in
233 * place. A page that has to be copied is one this test catches,
234 * so the limit does bound the copying it is there to bound.
235 */
236 if (folio_maybe_mapped_shared(folio)) {
237 shared++;
238 if (collapse_exceeds_limit(shared, max_ptes_shared,
239 start, end)) {
240 result = SCAN_EXCEED_SHARED_PTE;
241 count_vm_event(THP_SCAN_EXCEED_SHARED_PTE);
242 count_mthp_stat(HPAGE_PMD_ORDER,
243 MTHP_STAT_COLLAPSE_EXCEED_SHARED);
244 goto out_table_refused;
245 }
246 }
247
248 /*
249 * Which node the sources are on decides where the destination is
250 * allocated: the one with the most of them wins.
251 */
252 node = folio_nid(folio);
253 if (collapse_scan_abort(node, cc)) {
254 result = SCAN_SCAN_ABORT;
255 goto out_table_refused;
256 }
257 cc->node_load[node]++;
258
259 /*
260 * Usually a folio somebody else is already isolating, whose
261 * reference the freeze would refuse anyway. Not exact: one
262 * still on a per-CPU add batch reads the same, and the freeze
263 * drains those before it starts.
264 */
265 if (!folio_test_lru(folio)) {
266 if (pmd_result == SCAN_SUCCEED)
267 pmd_result = SCAN_PAGE_LRU;
268 continue;
269 }
270 if (folio_test_locked(folio)) {
271 if (pmd_result == SCAN_SUCCEED)
272 pmd_result = SCAN_PAGE_LOCK;
273 continue;
274 }
275
276 /*
277 * A folio whose reference count its mappings do not account for
278 * -- a GUP pin, say -- is refused by the freeze, not here.
279 * folio_expected_ref_count() wants a folio that cannot change
280 * order while it is read, and this walk holds no page table lock
281 * and no folio lock, so a folio splitting underneath it would
282 * have the count read for the wrong size. A reference of our
283 * own would not help: it stops the folio being freed, not split.
284 *
285 * So leave it to the freeze, which reads the table under the
286 * lock and settles the question by freezing each source to the
287 * count it expects. What it costs is a window selected here and
288 * refused there.
289 */
290
291 /*
292 * Every check passed: this PTE can be a collapse source. The
293 * bit is set last, so a disqualified PTE leaves it clear.
294 */
295 __set_bit(i, cc->eligible_ptes);
296
297 /*
298 * Whether a range has to look used at all is the caller's
299 * policy, so only a caller that asks gathers the evidence.
300 */
301 if (cc->policy.require_referenced &&
> 302 (pte_young(pteval) || folio_test_young(folio) ||
303 folio_test_referenced(folio) ||
304 mmu_notifier_test_young(vma->vm_mm, addr)))
305 referenced++;
306 }
307
308 if (cc->policy.require_referenced &&
309 (!referenced || (unmapped && referenced < HPAGE_PMD_NR / 2)))
310 result = SCAN_LACK_REFERENCED_PAGE;
311 else
312 result = pmd_result;
313 pte_unmap(pte);
314 goto out;
315
316 out_table_refused:
317 /*
318 * The table is refused as a unit -- a limit the whole range exceeds, or
319 * pages on nodes too distant for one folio to serve them all -- so no
320 * window inside it is eligible either.
321 */
322 pte_unmap(pte);
323 out_no_table:
324 cc->select_orders = 0;
325 out:
326 /*
327 * A PMD candidate needs the whole table, so anything that disqualified a
328 * single PTE rules it out. Smaller windows that avoid the offending
329 * PTEs are still collapsible, so drop just that order and leave the rest
330 * to selection -- dropping it also lowers the order selection roots its
331 * windows at. MADV_COLLAPSE has no other order enabled, so it is left
332 * with none.
333 */
334 if (result != SCAN_SUCCEED)
335 cc->select_orders &= ~BIT(HPAGE_PMD_ORDER);
336
337 return result;
338 }
339
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
reply other threads:[~2026-08-18 19:36 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=202608190330.FdsN6Kj3-lkp@intel.com \
--to=lkp@intel.com \
--cc=kas@kernel.org \
--cc=llvm@lists.linux.dev \
--cc=oe-kbuild-all@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox