1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
|
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Describes operations that can be performed on software-defined page table
* leaf entries. These are abstracted from the hardware page table entries
* themselves by the softleaf_t type, see mm_types.h.
*/
#ifndef _LINUX_LEAFOPS_H
#define _LINUX_LEAFOPS_H
#include <linux/mm_types.h>
#include <linux/swapops.h>
#include <linux/swap.h>
#ifdef CONFIG_MMU
/* Temporary until swp_entry_t eliminated. */
#define LEAF_TYPE_SHIFT SWP_TYPE_SHIFT
enum softleaf_type {
/* Fundamental types. */
SOFTLEAF_NONE,
SOFTLEAF_SWAP,
/* Migration types. */
SOFTLEAF_MIGRATION_READ,
SOFTLEAF_MIGRATION_READ_EXCLUSIVE,
SOFTLEAF_MIGRATION_WRITE,
/* Device types. */
SOFTLEAF_DEVICE_PRIVATE_READ,
SOFTLEAF_DEVICE_PRIVATE_WRITE,
SOFTLEAF_DEVICE_EXCLUSIVE,
/* H/W posion types. */
SOFTLEAF_HWPOISON,
/* Marker types. */
SOFTLEAF_MARKER,
};
/**
* softleaf_mk_none() - Create an empty ('none') leaf entry.
* Returns: empty leaf entry.
*/
static inline softleaf_t softleaf_mk_none(void)
{
return ((softleaf_t) { 0 });
}
/**
* softleaf_from_pte() - Obtain a leaf entry from a PTE entry.
* @pte: PTE entry.
*
* If @pte is present (therefore not a leaf entry) the function returns an empty
* leaf entry. Otherwise, it returns a leaf entry.
*
* Returns: Leaf entry.
*/
static inline softleaf_t softleaf_from_pte(pte_t pte)
{
softleaf_t arch_entry;
if (pte_present(pte) || pte_none(pte))
return softleaf_mk_none();
pte = pte_swp_clear_flags(pte);
arch_entry = __pte_to_swp_entry(pte);
/* Temporary until swp_entry_t eliminated. */
return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
}
/**
* softleaf_to_pte() - Obtain a PTE entry from a leaf entry.
* @entry: Leaf entry.
*
* This generates an architecture-specific PTE entry that can be utilised to
* encode the metadata the leaf entry encodes.
*
* Returns: Architecture-specific PTE entry encoding leaf entry.
*/
static inline pte_t softleaf_to_pte(softleaf_t entry)
{
/* Temporary until swp_entry_t eliminated. */
return swp_entry_to_pte(entry);
}
#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
/**
* softleaf_from_pmd() - Obtain a leaf entry from a PMD entry.
* @pmd: PMD entry.
*
* If @pmd is present (therefore not a leaf entry) the function returns an empty
* leaf entry. Otherwise, it returns a leaf entry.
*
* Returns: Leaf entry.
*/
static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
{
softleaf_t arch_entry;
if (pmd_present(pmd) || pmd_none(pmd))
return softleaf_mk_none();
if (pmd_swp_soft_dirty(pmd))
pmd = pmd_swp_clear_soft_dirty(pmd);
if (pmd_swp_uffd_wp(pmd))
pmd = pmd_swp_clear_uffd_wp(pmd);
arch_entry = __pmd_to_swp_entry(pmd);
/* Temporary until swp_entry_t eliminated. */
return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
}
#else
static inline softleaf_t softleaf_from_pmd(pmd_t pmd)
{
return softleaf_mk_none();
}
#endif
/**
* softleaf_is_none() - Is the leaf entry empty?
* @entry: Leaf entry.
*
* Empty entries are typically the result of a 'none' page table leaf entry
* being converted to a leaf entry.
*
* Returns: true if the entry is empty, false otherwise.
*/
static inline bool softleaf_is_none(softleaf_t entry)
{
return entry.val == 0;
}
/**
* softleaf_type() - Identify the type of leaf entry.
* @enntry: Leaf entry.
*
* Returns: the leaf entry type associated with @entry.
*/
static inline enum softleaf_type softleaf_type(softleaf_t entry)
{
unsigned int type_num;
if (softleaf_is_none(entry))
return SOFTLEAF_NONE;
type_num = entry.val >> LEAF_TYPE_SHIFT;
if (type_num < MAX_SWAPFILES)
return SOFTLEAF_SWAP;
switch (type_num) {
#ifdef CONFIG_MIGRATION
case SWP_MIGRATION_READ:
return SOFTLEAF_MIGRATION_READ;
case SWP_MIGRATION_READ_EXCLUSIVE:
return SOFTLEAF_MIGRATION_READ_EXCLUSIVE;
case SWP_MIGRATION_WRITE:
return SOFTLEAF_MIGRATION_WRITE;
#endif
#ifdef CONFIG_DEVICE_PRIVATE
case SWP_DEVICE_WRITE:
return SOFTLEAF_DEVICE_PRIVATE_WRITE;
case SWP_DEVICE_READ:
return SOFTLEAF_DEVICE_PRIVATE_READ;
case SWP_DEVICE_EXCLUSIVE:
return SOFTLEAF_DEVICE_EXCLUSIVE;
#endif
#ifdef CONFIG_MEMORY_FAILURE
case SWP_HWPOISON:
return SOFTLEAF_HWPOISON;
#endif
case SWP_PTE_MARKER:
return SOFTLEAF_MARKER;
}
/* Unknown entry type. */
VM_WARN_ON_ONCE(1);
return SOFTLEAF_NONE;
}
/**
* softleaf_is_swap() - Is this leaf entry a swap entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a swap entry, otherwise false.
*/
static inline bool softleaf_is_swap(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_SWAP;
}
/**
* softleaf_is_migration_write() - Is this leaf entry a writable migration entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a writable migration entry, otherwise
* false.
*/
static inline bool softleaf_is_migration_write(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_MIGRATION_WRITE;
}
/**
* softleaf_is_migration_read() - Is this leaf entry a readable migration entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a readable migration entry, otherwise
* false.
*/
static inline bool softleaf_is_migration_read(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_MIGRATION_READ;
}
/**
* softleaf_is_migration_read_exclusive() - Is this leaf entry an exclusive
* readable migration entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is an exclusive readable migration entry,
* otherwise false.
*/
static inline bool softleaf_is_migration_read_exclusive(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_MIGRATION_READ_EXCLUSIVE;
}
/**
* softleaf_is_migration() - Is this leaf entry a migration entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a migration entry, otherwise false.
*/
static inline bool softleaf_is_migration(softleaf_t entry)
{
switch (softleaf_type(entry)) {
case SOFTLEAF_MIGRATION_READ:
case SOFTLEAF_MIGRATION_READ_EXCLUSIVE:
case SOFTLEAF_MIGRATION_WRITE:
return true;
default:
return false;
}
}
/**
* softleaf_is_device_private_write() - Is this leaf entry a device private
* writable entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a device private writable entry, otherwise
* false.
*/
static inline bool softleaf_is_device_private_write(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_DEVICE_PRIVATE_WRITE;
}
/**
* softleaf_is_device_private() - Is this leaf entry a device private entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a device private entry, otherwise false.
*/
static inline bool softleaf_is_device_private(softleaf_t entry)
{
switch (softleaf_type(entry)) {
case SOFTLEAF_DEVICE_PRIVATE_WRITE:
case SOFTLEAF_DEVICE_PRIVATE_READ:
return true;
default:
return false;
}
}
/**
* softleaf_is_device_exclusive() - Is this leaf entry a device-exclusive entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a device-exclusive entry, otherwise false.
*/
static inline bool softleaf_is_device_exclusive(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_DEVICE_EXCLUSIVE;
}
/**
* softleaf_is_hwpoison() - Is this leaf entry a hardware poison entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a hardware poison entry, otherwise false.
*/
static inline bool softleaf_is_hwpoison(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_HWPOISON;
}
/**
* softleaf_is_marker() - Is this leaf entry a marker?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a marker entry, otherwise false.
*/
static inline bool softleaf_is_marker(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_MARKER;
}
/**
* softleaf_to_marker() - Obtain marker associated with leaf entry.
* @entry: Leaf entry, softleaf_is_marker(@entry) must return true.
*
* Returns: Marker associated with the leaf entry.
*/
static inline pte_marker softleaf_to_marker(softleaf_t entry)
{
VM_WARN_ON_ONCE(!softleaf_is_marker(entry));
return swp_offset(entry) & PTE_MARKER_MASK;
}
/**
* softleaf_has_pfn() - Does this leaf entry encode a valid PFN number?
* @entry: Leaf entry.
*
* A pfn swap entry is a special type of swap entry that always has a pfn stored
* in the swap offset. They can either be used to represent unaddressable device
* memory, to restrict access to a page undergoing migration or to represent a
* pfn which has been hwpoisoned and unmapped.
*
* Returns: true if the leaf entry encodes a PFN, otherwise false.
*/
static inline bool softleaf_has_pfn(softleaf_t entry)
{
/* Make sure the swp offset can always store the needed fields. */
BUILD_BUG_ON(SWP_TYPE_SHIFT < SWP_PFN_BITS);
if (softleaf_is_migration(entry))
return true;
if (softleaf_is_device_private(entry))
return true;
if (softleaf_is_device_exclusive(entry))
return true;
if (softleaf_is_hwpoison(entry))
return true;
return false;
}
/**
* softleaf_to_pfn() - Obtain PFN encoded within leaf entry.
* @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
*
* Returns: The PFN associated with the leaf entry.
*/
static inline unsigned long softleaf_to_pfn(softleaf_t entry)
{
VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
/* Temporary until swp_entry_t eliminated. */
return swp_offset(entry) & SWP_PFN_MASK;
}
/**
* softleaf_to_page() - Obtains struct page for PFN encoded within leaf entry.
* @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
*
* Returns: Pointer to the struct page associated with the leaf entry's PFN.
*/
static inline struct page *softleaf_to_page(softleaf_t entry)
{
struct page *page = pfn_to_page(softleaf_to_pfn(entry));
VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
/*
* Any use of migration entries may only occur while the
* corresponding page is locked
*/
VM_WARN_ON_ONCE(softleaf_is_migration(entry) && !PageLocked(page));
return page;
}
/**
* softleaf_to_folio() - Obtains struct folio for PFN encoded within leaf entry.
* @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
*
* Returns: Pointer to the struct folio associated with the leaf entry's PFN.
*/
static inline struct folio *softleaf_to_folio(softleaf_t entry)
{
struct folio *folio = pfn_folio(softleaf_to_pfn(entry));
VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
/*
* Any use of migration entries may only occur while the
* corresponding folio is locked.
*/
VM_WARN_ON_ONCE(softleaf_is_migration(entry) &&
!folio_test_locked(folio));
return folio;
}
/**
* softleaf_is_poison_marker() - Is this leaf entry a poison marker?
* @entry: Leaf entry.
*
* The poison marker is set via UFFDIO_POISON. Userfaultfd-specific.
*
* Returns: true if the leaf entry is a poison marker, otherwise false.
*/
static inline bool softleaf_is_poison_marker(softleaf_t entry)
{
if (!softleaf_is_marker(entry))
return false;
return softleaf_to_marker(entry) & PTE_MARKER_POISONED;
}
/**
* softleaf_is_guard_marker() - Is this leaf entry a guard region marker?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a guard marker, otherwise false.
*/
static inline bool softleaf_is_guard_marker(softleaf_t entry)
{
if (!softleaf_is_marker(entry))
return false;
return softleaf_to_marker(entry) & PTE_MARKER_GUARD;
}
/**
* softleaf_is_uffd_wp_marker() - Is this leaf entry a userfautlfd write protect
* marker?
* @entry: Leaf entry.
*
* Userfaultfd-specific.
*
* Returns: true if the leaf entry is a UFFD WP marker, otherwise false.
*/
static inline bool softleaf_is_uffd_wp_marker(softleaf_t entry)
{
if (!softleaf_is_marker(entry))
return false;
return softleaf_to_marker(entry) & PTE_MARKER_UFFD_WP;
}
#ifdef CONFIG_MIGRATION
/**
* softleaf_is_migration_young() - Does this migration entry contain an accessed
* bit?
* @entry: Leaf entry.
*
* If the architecture can support storing A/D bits in migration entries, this
* determines whether the accessed (or 'young') bit was set on the migrated page
* table entry.
*
* Returns: true if the entry contains an accessed bit, otherwise false.
*/
static inline bool softleaf_is_migration_young(softleaf_t entry)
{
VM_WARN_ON_ONCE(!softleaf_is_migration(entry));
if (migration_entry_supports_ad())
return swp_offset(entry) & SWP_MIG_YOUNG;
/* Keep the old behavior of aging page after migration */
return false;
}
/**
* softleaf_is_migration_dirty() - Does this migration entry contain a dirty bit?
* @entry: Leaf entry.
*
* If the architecture can support storing A/D bits in migration entries, this
* determines whether the dirty bit was set on the migrated page table entry.
*
* Returns: true if the entry contains a dirty bit, otherwise false.
*/
static inline bool softleaf_is_migration_dirty(softleaf_t entry)
{
VM_WARN_ON_ONCE(!softleaf_is_migration(entry));
if (migration_entry_supports_ad())
return swp_offset(entry) & SWP_MIG_DIRTY;
/* Keep the old behavior of clean page after migration */
return false;
}
#else /* CONFIG_MIGRATION */
static inline bool softleaf_is_migration_young(softleaf_t entry)
{
return false;
}
static inline bool softleaf_is_migration_dirty(softleaf_t entry)
{
return false;
}
#endif /* CONFIG_MIGRATION */
/**
* pte_is_marker() - Does the PTE entry encode a marker leaf entry?
* @pte: PTE entry.
*
* Returns: true if this PTE is a marker leaf entry, otherwise false.
*/
static inline bool pte_is_marker(pte_t pte)
{
return softleaf_is_marker(softleaf_from_pte(pte));
}
/**
* pte_is_uffd_wp_marker() - Does this PTE entry encode a userfaultfd write
* protect marker leaf entry?
* @pte: PTE entry.
*
* Returns: true if this PTE is a UFFD WP marker leaf entry, otherwise false.
*/
static inline bool pte_is_uffd_wp_marker(pte_t pte)
{
const softleaf_t entry = softleaf_from_pte(pte);
return softleaf_is_uffd_wp_marker(entry);
}
/**
* pte_is_uffd_marker() - Does this PTE entry encode a userfault-specific marker
* leaf entry?
* @entry: Leaf entry.
*
* It's useful to be able to determine which leaf entries encode UFFD-specific
* markers so we can handle these correctly.
*
* Returns: true if this PTE entry is a UFFD-specific marker, otherwise false.
*/
static inline bool pte_is_uffd_marker(pte_t pte)
{
const softleaf_t entry = softleaf_from_pte(pte);
if (!softleaf_is_marker(entry))
return false;
/* UFFD WP, poisoned swap entries are UFFD-handled. */
if (softleaf_is_uffd_wp_marker(entry))
return true;
if (softleaf_is_poison_marker(entry))
return true;
return false;
}
#if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_ARCH_ENABLE_THP_MIGRATION)
/**
* pmd_is_device_private_entry() - Check if PMD contains a device private swap
* entry.
* @pmd: The PMD to check.
*
* Returns true if the PMD contains a swap entry that represents a device private
* page mapping. This is used for zone device private pages that have been
* swapped out but still need special handling during various memory management
* operations.
*
* Return: true if PMD contains device private entry, false otherwise
*/
static inline bool pmd_is_device_private_entry(pmd_t pmd)
{
return softleaf_is_device_private(softleaf_from_pmd(pmd));
}
#else /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_ENABLE_THP_MIGRATION */
static inline bool pmd_is_device_private_entry(pmd_t pmd)
{
return false;
}
#endif /* CONFIG_ZONE_DEVICE && CONFIG_ARCH_ENABLE_THP_MIGRATION */
/**
* pmd_is_migration_entry() - Does this PMD entry encode a migration entry?
* @pmd: PMD entry.
*
* Returns: true if the PMD encodes a migration entry, otherwise false.
*/
static inline bool pmd_is_migration_entry(pmd_t pmd)
{
return softleaf_is_migration(softleaf_from_pmd(pmd));
}
/**
* pmd_is_valid_softleaf() - Is this PMD entry a valid leaf entry?
* @pmd: PMD entry.
*
* PMD leaf entries are valid only if they are device private or migration
* entries. This function asserts that a PMD leaf entry is valid in this
* respect.
*
* Returns: true if the PMD entry is a valid leaf entry, otherwise false.
*/
static inline bool pmd_is_valid_softleaf(pmd_t pmd)
{
const softleaf_t entry = softleaf_from_pmd(pmd);
/* Only device private, migration entries valid for PMD. */
return softleaf_is_device_private(entry) ||
softleaf_is_migration(entry);
}
#endif /* CONFIG_MMU */
#endif /* _LINUX_LEAFOPS_H */
|