Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm: avoid gcc complaint about pointer casting

The migration code ends up temporarily stashing information of the wrong
type in unused fields of the newly allocated destination folio. That
all works fine, but gcc does complain about the pointer type mis-use:

mm/migrate.c: In function ‘__migrate_folio_extract’:
mm/migrate.c:1050:20: note: randstruct: casting between randomized structure pointer types (ssa): ‘struct anon_vma’ and ‘struct address_space’

1050 | *anon_vmap = (void *)dst->mapping;
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~

and gcc is actually right to complain since it really doesn't understand
that this is a very temporary special case where this is ok.

This could be fixed in different ways by just obfuscating the assignment
sufficiently that gcc doesn't see what is going on, but the truly
"proper C" way to do this is by explicitly using a union.

Using unions for type conversions like this is normally hugely ugly and
syntactically nasty, but this really is one of the few cases where we
want to make it clear that we're not doing type conversion, we're really
re-using the value bit-for-bit just using another type.

IOW, this should not become a common pattern, but in this one case using
that odd union is probably the best way to document to the compiler what
is conceptually going on here.

[ Side note: there are valid cases where we convert pointers to other
pointer types, notably the whole "folio vs page" situation, where the
types actually have fundamental commonalities.

The fact that the gcc note is limited to just randomized structures
means that we don't see equivalent warnings for those cases, but it
migth also mean that we miss other cases where we do play these kinds
of dodgy games, and this kind of explicit conversion might be a good
idea. ]

I verified that at least for an allmodconfig build on x86-64, this
generates the exact same code, apart from line numbers and assembler
comment changes.

Fixes: 64c8902ed441 ("migrate_pages: split unmap_and_move() to _unmap() and _move()")
Cc: Huang, Ying <ying.huang@intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+8 -2
+8 -2
mm/migrate.c
··· 1035 1035 * destination folio. This is safe because nobody is using them 1036 1036 * except us. 1037 1037 */ 1038 + union migration_ptr { 1039 + struct anon_vma *anon_vma; 1040 + struct address_space *mapping; 1041 + }; 1038 1042 static void __migrate_folio_record(struct folio *dst, 1039 1043 unsigned long page_was_mapped, 1040 1044 struct anon_vma *anon_vma) 1041 1045 { 1042 - dst->mapping = (void *)anon_vma; 1046 + union migration_ptr ptr = { .anon_vma = anon_vma }; 1047 + dst->mapping = ptr.mapping; 1043 1048 dst->private = (void *)page_was_mapped; 1044 1049 } 1045 1050 ··· 1052 1047 int *page_was_mappedp, 1053 1048 struct anon_vma **anon_vmap) 1054 1049 { 1055 - *anon_vmap = (void *)dst->mapping; 1050 + union migration_ptr ptr = { .mapping = dst->mapping }; 1051 + *anon_vmap = ptr.anon_vma; 1056 1052 *page_was_mappedp = (unsigned long)dst->private; 1057 1053 dst->mapping = NULL; 1058 1054 dst->private = NULL;