Skip to contentSkip to conversation

mm: make 'highmem' symbol ro_after_init

PATCH In review Ard Biesheuvel 4 participants 5 messages Jan 24, 2022 – Jan 28, 2022

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 mm: make 'highmem' symbol ro_after_init

The 'highmem' variable is only set at boot, so we can make it ro_after_init and prevent it from being corrupted inadvertently, or from ending up in a contended cacheline.

---
 mm/memory.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/memory.c +1 -1
index c125c4969913..50e82cb94ccc 100644
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(mem_map);
  * highstart_pfn must be the same; there must be no gap between ZONE_NORMAL
  * and ZONE_HIGHMEM.
  */
-void *high_memory;
+void *high_memory __ro_after_init;
 EXPORT_SYMBOL(high_memory);
 
 /*
Signature · 1 line
2.30.2
#1 lore raw

mm/memory.c EXPORT_SYMBOL(mem_map); · line 112

Quoted 13 lines · Ard Biesheuvel
mm/memory.c +1 -1
index c125c4969913..50e82cb94ccc 100644
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(mem_map);
  * highstart_pfn must be the same; there must be no gap between ZONE_NORMAL
  * and ZONE_HIGHMEM.
  */
-void *high_memory;
+void *high_memory __ro_after_init;
 EXPORT_SYMBOL(high_memory);
 
 /*

Same should be true for the mm/nommu.c variant?

#2 lore raw
In reply to Ard Biesheuvel
Quoted 3 lines · Ard Biesheuvel

The 'highmem' variable is only set at boot, so we can make it ro_after_init and prevent it from being corrupted inadvertently, or from ending up in a contended cacheline.

I'm not against this patch, but it'd be nice to go further and remove it entirely for !CONFIG_HIGHMEM builds? Adding something like

static inline bool is_high_pfn(unsigned long pfn)
{

#ifdef CONFIG_HIGHMEM
	return pfn <= max_low_pfn;
#else
	return false;

#endif
}

static inline bool is_high_phys(phys_addr_t pa)

{
	return is_high_pfn(pa / PAGE_SIZE);
}

static inline bool is_high_addr(void *addr)

{
	return is_high_phys(virt_to_phys(addr));
}

should be all the primitives you need, from a quick grep.

Quoted 22 lines
---
 mm/memory.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/memory.c +1 -1
index c125c4969913..50e82cb94ccc 100644
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(mem_map);
  * highstart_pfn must be the same; there must be no gap between ZONE_NORMAL
  * and ZONE_HIGHMEM.
  */
-void *high_memory;
+void *high_memory __ro_after_init;
 EXPORT_SYMBOL(high_memory);
 
 /*
Signature · 1 line
2.30.2
reviewer Acked-by on v1 1/1
#3 lore raw
In reply to Ard Biesheuvel
Quoted 5 lines · Ard Biesheuvel

The 'highmem' variable is only set at boot, so we can make it ro_after_init and prevent it from being corrupted inadvertently, or from ending up in a contended cacheline.

Quoted 21 lines
---
 mm/memory.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/memory.c +1 -1
index c125c4969913..50e82cb94ccc 100644
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(mem_map);
  * highstart_pfn must be the same; there must be no gap between ZONE_NORMAL
  * and ZONE_HIGHMEM.
  */
-void *high_memory;
+void *high_memory __ro_after_init;
 EXPORT_SYMBOL(high_memory);
 
 /*
Signature · 1 line
2.30.2
Signature · 2 lines
Sincerely yours,
Mike.
#4 lore raw
Quoted 26 lines · Mike Rapoport
Quoted 5 lines · Ard Biesheuvel

The 'highmem' variable is only set at boot, so we can make it ro_after_init and prevent it from being corrupted inadvertently, or from ending up in a contended cacheline.

Quoted 16 lines
---
 mm/memory.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/memory.c +1 -1
index c125c4969913..50e82cb94ccc 100644
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(mem_map);
  * highstart_pfn must be the same; there must be no gap between ZONE_NORMAL
  * and ZONE_HIGHMEM.
  */
-void *high_memory;
+void *high_memory __ro_after_init;
 EXPORT_SYMBOL(high_memory);
 
Quoted 6 lines
Quoted 5 lines
mm/memory.c +0 -1
 /*
--

2.30.2

This turns out to break CONFIG_MEMORY_HOTPLUG on x86, as it updates max_pfn, max_low_pfn and high_memory after init.

So probably best to make all of those __read_mostly instead.