Skip to content

Commit 0003e2a

Browse files
sean-jcbonzini
authored andcommitted
mm: Add AS_UNMOVABLE to mark mapping as completely unmovable
Add an "unmovable" flag for mappings that cannot be migrated under any circumstance. KVM will use the flag for its upcoming GUEST_MEMFD support, which will not support compaction/migration, at least not in the foreseeable future. Test AS_UNMOVABLE under folio lock as already done for the async compaction/dirty folio case, as the mapping can be removed by truncation while compaction is running. To avoid having to lock every folio with a mapping, assume/require that unmovable mappings are also unevictable, and have mapping_set_unmovable() also set AS_UNEVICTABLE. Cc: Matthew Wilcox <willy@infradead.org> Co-developed-by: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20231027182217.3615211-15-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 5a47555 commit 0003e2a

3 files changed

Lines changed: 51 additions & 13 deletions

File tree

include/linux/pagemap.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ enum mapping_flags {
203203
/* writeback related tags are not used */
204204
AS_NO_WRITEBACK_TAGS = 5,
205205
AS_LARGE_FOLIO_SUPPORT = 6,
206-
AS_RELEASE_ALWAYS, /* Call ->release_folio(), even if no private data */
206+
AS_RELEASE_ALWAYS = 7, /* Call ->release_folio(), even if no private data */
207+
AS_UNMOVABLE = 8, /* The mapping cannot be moved, ever */
207208
};
208209

209210
/**
@@ -289,6 +290,22 @@ static inline void mapping_clear_release_always(struct address_space *mapping)
289290
clear_bit(AS_RELEASE_ALWAYS, &mapping->flags);
290291
}
291292

293+
static inline void mapping_set_unmovable(struct address_space *mapping)
294+
{
295+
/*
296+
* It's expected unmovable mappings are also unevictable. Compaction
297+
* migrate scanner (isolate_migratepages_block()) relies on this to
298+
* reduce page locking.
299+
*/
300+
set_bit(AS_UNEVICTABLE, &mapping->flags);
301+
set_bit(AS_UNMOVABLE, &mapping->flags);
302+
}
303+
304+
static inline bool mapping_unmovable(struct address_space *mapping)
305+
{
306+
return test_bit(AS_UNMOVABLE, &mapping->flags);
307+
}
308+
292309
static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
293310
{
294311
return mapping->gfp_mask;

mm/compaction.c

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
883883

884884
/* Time to isolate some pages for migration */
885885
for (; low_pfn < end_pfn; low_pfn++) {
886+
bool is_dirty, is_unevictable;
886887

887888
if (skip_on_failure && low_pfn >= next_skip_pfn) {
888889
/*
@@ -1080,8 +1081,10 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
10801081
if (!folio_test_lru(folio))
10811082
goto isolate_fail_put;
10821083

1084+
is_unevictable = folio_test_unevictable(folio);
1085+
10831086
/* Compaction might skip unevictable pages but CMA takes them */
1084-
if (!(mode & ISOLATE_UNEVICTABLE) && folio_test_unevictable(folio))
1087+
if (!(mode & ISOLATE_UNEVICTABLE) && is_unevictable)
10851088
goto isolate_fail_put;
10861089

10871090
/*
@@ -1093,26 +1096,42 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
10931096
if ((mode & ISOLATE_ASYNC_MIGRATE) && folio_test_writeback(folio))
10941097
goto isolate_fail_put;
10951098

1096-
if ((mode & ISOLATE_ASYNC_MIGRATE) && folio_test_dirty(folio)) {
1097-
bool migrate_dirty;
1099+
is_dirty = folio_test_dirty(folio);
1100+
1101+
if (((mode & ISOLATE_ASYNC_MIGRATE) && is_dirty) ||
1102+
(mapping && is_unevictable)) {
1103+
bool migrate_dirty = true;
1104+
bool is_unmovable;
10981105

10991106
/*
11001107
* Only folios without mappings or that have
1101-
* a ->migrate_folio callback are possible to
1102-
* migrate without blocking. However, we may
1103-
* be racing with truncation, which can free
1104-
* the mapping. Truncation holds the folio lock
1105-
* until after the folio is removed from the page
1106-
* cache so holding it ourselves is sufficient.
1108+
* a ->migrate_folio callback are possible to migrate
1109+
* without blocking.
1110+
*
1111+
* Folios from unmovable mappings are not migratable.
1112+
*
1113+
* However, we can be racing with truncation, which can
1114+
* free the mapping that we need to check. Truncation
1115+
* holds the folio lock until after the folio is removed
1116+
* from the page so holding it ourselves is sufficient.
1117+
*
1118+
* To avoid locking the folio just to check unmovable,
1119+
* assume every unmovable folio is also unevictable,
1120+
* which is a cheaper test. If our assumption goes
1121+
* wrong, it's not a correctness bug, just potentially
1122+
* wasted cycles.
11071123
*/
11081124
if (!folio_trylock(folio))
11091125
goto isolate_fail_put;
11101126

11111127
mapping = folio_mapping(folio);
1112-
migrate_dirty = !mapping ||
1113-
mapping->a_ops->migrate_folio;
1128+
if ((mode & ISOLATE_ASYNC_MIGRATE) && is_dirty) {
1129+
migrate_dirty = !mapping ||
1130+
mapping->a_ops->migrate_folio;
1131+
}
1132+
is_unmovable = mapping && mapping_unmovable(mapping);
11141133
folio_unlock(folio);
1115-
if (!migrate_dirty)
1134+
if (!migrate_dirty || is_unmovable)
11161135
goto isolate_fail_put;
11171136
}
11181137

mm/migrate.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,8 @@ static int move_to_new_folio(struct folio *dst, struct folio *src,
956956

957957
if (!mapping)
958958
rc = migrate_folio(mapping, dst, src, mode);
959+
else if (mapping_unmovable(mapping))
960+
rc = -EOPNOTSUPP;
959961
else if (mapping->a_ops->migrate_folio)
960962
/*
961963
* Most folios have a mapping and most filesystems

0 commit comments

Comments
 (0)