s390: Unmap early KASAN shadow on memory offlining
Teach the memory hotplug path to tear down KASAN shadow that was mapped during early boot when a memory block is offlined. Track for each sclp_mem whether its range was covered by the early KASAN shadow via an early_shadow_mapped flag. When such a block is deconfigured and removed via sclp_config_mem_store(), compute the corresponding shadow range and call vmemmap_free() to unmap the boot mapped shadow, then clear the flag. Using vmemmap_free() for the early shadow is safe despite the use of large mappings in the boot-time KASAN setup. The initial shadow is mapped with 1M and 2G pages, where possible. The minimum hotplug memory block size is 128M and always aligned (the identity mapping is at least 2G aligned), which corresponds to a 16M chunk of at least 1M aligned shadow. PMD-mapped 1M shadow pages therefore never need splitting, and PUD-mapped 2G shadow pages can now be split following the preceding changes. Relax the modify_pagetable() sanity check in vmem so that, with KASAN enabled, it may also operate on the KASAN shadow region in addition to the 1:1 mapping and vmemmap area. This allows the KASAN shadow unmapping to reuse the common vmem helpers. Signed-off-by: Vasily Gorbik <gor@linux.ibm.com> Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>pull/1354/merge
parent
6a35d02fec
commit
8543ecc0e0
|
|
@ -437,9 +437,15 @@ static int modify_pagetable(unsigned long start, unsigned long end, bool add,
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!PAGE_ALIGNED(start | end)))
|
if (WARN_ON_ONCE(!PAGE_ALIGNED(start | end)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
/* Don't mess with any tables not fully in 1:1 mapping & vmemmap area */
|
/* Don't mess with any tables not fully in 1:1 mapping, vmemmap & kasan area */
|
||||||
|
#ifdef CONFIG_KASAN
|
||||||
|
if (WARN_ON_ONCE(!(start >= KASAN_SHADOW_START && end <= KASAN_SHADOW_END) &&
|
||||||
|
end > __abs_lowcore))
|
||||||
|
return -EINVAL;
|
||||||
|
#else
|
||||||
if (WARN_ON_ONCE(end > __abs_lowcore))
|
if (WARN_ON_ONCE(end > __abs_lowcore))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
#endif
|
||||||
for (addr = start; addr < end; addr = next) {
|
for (addr = start; addr < end; addr = next) {
|
||||||
next = pgd_addr_end(addr, end);
|
next = pgd_addr_end(addr, end);
|
||||||
pgd = pgd_offset_k(addr);
|
pgd = pgd_offset_k(addr);
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@ struct sclp_mem {
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
unsigned int memmap_on_memory;
|
unsigned int memmap_on_memory;
|
||||||
unsigned int config;
|
unsigned int config;
|
||||||
|
#ifdef CONFIG_KASAN
|
||||||
|
unsigned int early_shadow_mapped;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sclp_mem_arg {
|
struct sclp_mem_arg {
|
||||||
|
|
@ -244,6 +247,16 @@ static ssize_t sclp_config_mem_store(struct kobject *kobj, struct kobj_attribute
|
||||||
put_device(&mem->dev);
|
put_device(&mem->dev);
|
||||||
sclp_mem_change_state(addr, block_size, 0);
|
sclp_mem_change_state(addr, block_size, 0);
|
||||||
__remove_memory(addr, block_size);
|
__remove_memory(addr, block_size);
|
||||||
|
#ifdef CONFIG_KASAN
|
||||||
|
if (sclp_mem->early_shadow_mapped) {
|
||||||
|
unsigned long start, end;
|
||||||
|
|
||||||
|
start = (unsigned long)kasan_mem_to_shadow(__va(addr));
|
||||||
|
end = start + (block_size >> KASAN_SHADOW_SCALE_SHIFT);
|
||||||
|
vmemmap_free(start, end, NULL);
|
||||||
|
sclp_mem->early_shadow_mapped = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
WRITE_ONCE(sclp_mem->config, 0);
|
WRITE_ONCE(sclp_mem->config, 0);
|
||||||
}
|
}
|
||||||
out_unlock:
|
out_unlock:
|
||||||
|
|
@ -316,6 +329,9 @@ static int sclp_create_mem(struct sclp_mem *sclp_mem, struct kset *kset,
|
||||||
|
|
||||||
sclp_mem->memmap_on_memory = memmap_on_memory;
|
sclp_mem->memmap_on_memory = memmap_on_memory;
|
||||||
sclp_mem->config = config;
|
sclp_mem->config = config;
|
||||||
|
#ifdef CONFIG_KASAN
|
||||||
|
sclp_mem->early_shadow_mapped = config;
|
||||||
|
#endif
|
||||||
sclp_mem->id = id;
|
sclp_mem->id = id;
|
||||||
kobject_init(&sclp_mem->kobj, &ktype);
|
kobject_init(&sclp_mem->kobj, &ktype);
|
||||||
rc = kobject_add(&sclp_mem->kobj, &kset->kobj, "memory%d", id);
|
rc = kobject_add(&sclp_mem->kobj, &kset->kobj, "memory%d", id);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue