Skip to content

Commit 08b3acd

Browse files
davidhildenbrandmstsirkin
authored andcommitted
mm/memory_hotplug: Introduce offline_and_remove_memory()
virtio-mem wants to offline and remove a memory block once it unplugged all subblocks (e.g., using alloc_contig_range()). Let's provide an interface to do that from a driver. virtio-mem already supports to offline partially unplugged memory blocks. Offlining a fully unplugged memory block will not require to migrate any pages. All unplugged subblocks are PageOffline() and have a reference count of 0 - so offlining code will simply skip them. All we need is an interface to offline and remove the memory from kernel module context, where we don't have access to the memory block devices (esp. find_memory_block() and device_offline()) and the device hotplug lock. To keep things simple, allow to only work on a single memory block. Acked-by: Michal Hocko <[email protected]> Tested-by: Pankaj Gupta <[email protected]> Acked-by: Andrew Morton <[email protected]> Cc: Andrew Morton <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Pavel Tatashin <[email protected]> Cc: Wei Yang <[email protected]> Cc: Dan Williams <[email protected]> Cc: Qian Cai <[email protected]> Signed-off-by: David Hildenbrand <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent 8e5c921 commit 08b3acd

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

include/linux/memory_hotplug.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ extern void try_offline_node(int nid);
319319
extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
320320
extern int remove_memory(int nid, u64 start, u64 size);
321321
extern void __remove_memory(int nid, u64 start, u64 size);
322+
extern int offline_and_remove_memory(int nid, u64 start, u64 size);
322323

323324
#else
324325
static inline bool is_mem_section_removable(unsigned long pfn,

mm/memory_hotplug.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,4 +1821,41 @@ int remove_memory(int nid, u64 start, u64 size)
18211821
return rc;
18221822
}
18231823
EXPORT_SYMBOL_GPL(remove_memory);
1824+
1825+
/*
1826+
* Try to offline and remove a memory block. Might take a long time to
1827+
* finish in case memory is still in use. Primarily useful for memory devices
1828+
* that logically unplugged all memory (so it's no longer in use) and want to
1829+
* offline + remove the memory block.
1830+
*/
1831+
int offline_and_remove_memory(int nid, u64 start, u64 size)
1832+
{
1833+
struct memory_block *mem;
1834+
int rc = -EINVAL;
1835+
1836+
if (!IS_ALIGNED(start, memory_block_size_bytes()) ||
1837+
size != memory_block_size_bytes())
1838+
return rc;
1839+
1840+
lock_device_hotplug();
1841+
mem = find_memory_block(__pfn_to_section(PFN_DOWN(start)));
1842+
if (mem)
1843+
rc = device_offline(&mem->dev);
1844+
/* Ignore if the device is already offline. */
1845+
if (rc > 0)
1846+
rc = 0;
1847+
1848+
/*
1849+
* In case we succeeded to offline the memory block, remove it.
1850+
* This cannot fail as it cannot get onlined in the meantime.
1851+
*/
1852+
if (!rc) {
1853+
rc = try_remove_memory(nid, start, size);
1854+
WARN_ON_ONCE(rc);
1855+
}
1856+
unlock_device_hotplug();
1857+
1858+
return rc;
1859+
}
1860+
EXPORT_SYMBOL_GPL(offline_and_remove_memory);
18241861
#endif /* CONFIG_MEMORY_HOTREMOVE */

0 commit comments

Comments
 (0)