Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
Pull virtio updates from Michael Tsirkin: - virtio-mem: paravirtualized memory hotplug - support doorbell mapping for vdpa - config interrupt support in ifc - fixes all over the place * tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (40 commits) vhost/test: fix up after API change virtio_mem: convert device block size into 64bit virtio-mem: drop unnecessary initialization ifcvf: implement config interrupt in IFCVF vhost: replace -1 with VHOST_FILE_UNBIND in ioctls vhost_vdpa: Support config interrupt in vdpa ifcvf: ignore continuous setting same status value virtio-mem: Don't rely on implicit compiler padding for requests virtio-mem: Try to unplug the complete online memory block first virtio-mem: Use -ETXTBSY as error code if the device is busy virtio-mem: Unplug subblocks right-to-left virtio-mem: Drop manual check for already present memory virtio-mem: Add parent resource for all added "System RAM" virtio-mem: Better retry handling virtio-mem: Offline and remove completely unplugged memory blocks mm/memory_hotplug: Introduce offline_and_remove_memory() virtio-mem: Allow to offline partially unplugged memory blocks mm: Allow to offline unmovable PageOffline() pages via MEM_GOING_OFFLINE virtio-mem: Paravirtualized memory hotunplug part 2 virtio-mem: Paravirtualized memory hotunplug part 1 ...
This commit is contained in:
@@ -1201,11 +1201,17 @@ struct zone *test_pages_in_a_zone(unsigned long start_pfn,
|
||||
|
||||
/*
|
||||
* Scan pfn range [start,end) to find movable/migratable pages (LRU pages,
|
||||
* non-lru movable pages and hugepages). We scan pfn because it's much
|
||||
* easier than scanning over linked list. This function returns the pfn
|
||||
* of the first found movable page if it's found, otherwise 0.
|
||||
* non-lru movable pages and hugepages). Will skip over most unmovable
|
||||
* pages (esp., pages that can be skipped when offlining), but bail out on
|
||||
* definitely unmovable pages.
|
||||
*
|
||||
* Returns:
|
||||
* 0 in case a movable page is found and movable_pfn was updated.
|
||||
* -ENOENT in case no movable page was found.
|
||||
* -EBUSY in case a definitely unmovable page was found.
|
||||
*/
|
||||
static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
|
||||
static int scan_movable_pages(unsigned long start, unsigned long end,
|
||||
unsigned long *movable_pfn)
|
||||
{
|
||||
unsigned long pfn;
|
||||
|
||||
@@ -1217,18 +1223,30 @@ static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
|
||||
continue;
|
||||
page = pfn_to_page(pfn);
|
||||
if (PageLRU(page))
|
||||
return pfn;
|
||||
goto found;
|
||||
if (__PageMovable(page))
|
||||
return pfn;
|
||||
goto found;
|
||||
|
||||
/*
|
||||
* PageOffline() pages that are not marked __PageMovable() and
|
||||
* have a reference count > 0 (after MEM_GOING_OFFLINE) are
|
||||
* definitely unmovable. If their reference count would be 0,
|
||||
* they could at least be skipped when offlining memory.
|
||||
*/
|
||||
if (PageOffline(page) && page_count(page))
|
||||
return -EBUSY;
|
||||
|
||||
if (!PageHuge(page))
|
||||
continue;
|
||||
head = compound_head(page);
|
||||
if (page_huge_active(head))
|
||||
return pfn;
|
||||
goto found;
|
||||
skip = compound_nr(head) - (page - head);
|
||||
pfn += skip - 1;
|
||||
}
|
||||
return -ENOENT;
|
||||
found:
|
||||
*movable_pfn = pfn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1491,7 +1509,8 @@ static int __ref __offline_pages(unsigned long start_pfn,
|
||||
}
|
||||
|
||||
do {
|
||||
for (pfn = start_pfn; pfn;) {
|
||||
pfn = start_pfn;
|
||||
do {
|
||||
if (signal_pending(current)) {
|
||||
ret = -EINTR;
|
||||
reason = "signal backoff";
|
||||
@@ -1501,14 +1520,19 @@ static int __ref __offline_pages(unsigned long start_pfn,
|
||||
cond_resched();
|
||||
lru_add_drain_all();
|
||||
|
||||
pfn = scan_movable_pages(pfn, end_pfn);
|
||||
if (pfn) {
|
||||
ret = scan_movable_pages(pfn, end_pfn, &pfn);
|
||||
if (!ret) {
|
||||
/*
|
||||
* TODO: fatal migration failures should bail
|
||||
* out
|
||||
*/
|
||||
do_migrate_range(pfn, end_pfn);
|
||||
}
|
||||
} while (!ret);
|
||||
|
||||
if (ret != -ENOENT) {
|
||||
reason = "unmovable page";
|
||||
goto failed_removal_isolated;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1774,4 +1798,41 @@ int remove_memory(int nid, u64 start, u64 size)
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(remove_memory);
|
||||
|
||||
/*
|
||||
* Try to offline and remove a memory block. Might take a long time to
|
||||
* finish in case memory is still in use. Primarily useful for memory devices
|
||||
* that logically unplugged all memory (so it's no longer in use) and want to
|
||||
* offline + remove the memory block.
|
||||
*/
|
||||
int offline_and_remove_memory(int nid, u64 start, u64 size)
|
||||
{
|
||||
struct memory_block *mem;
|
||||
int rc = -EINVAL;
|
||||
|
||||
if (!IS_ALIGNED(start, memory_block_size_bytes()) ||
|
||||
size != memory_block_size_bytes())
|
||||
return rc;
|
||||
|
||||
lock_device_hotplug();
|
||||
mem = find_memory_block(__pfn_to_section(PFN_DOWN(start)));
|
||||
if (mem)
|
||||
rc = device_offline(&mem->dev);
|
||||
/* Ignore if the device is already offline. */
|
||||
if (rc > 0)
|
||||
rc = 0;
|
||||
|
||||
/*
|
||||
* In case we succeeded to offline the memory block, remove it.
|
||||
* This cannot fail as it cannot get onlined in the meantime.
|
||||
*/
|
||||
if (!rc) {
|
||||
rc = try_remove_memory(nid, start, size);
|
||||
WARN_ON_ONCE(rc);
|
||||
}
|
||||
unlock_device_hotplug();
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(offline_and_remove_memory);
|
||||
#endif /* CONFIG_MEMORY_HOTREMOVE */
|
||||
|
@@ -8285,6 +8285,19 @@ struct page *has_unmovable_pages(struct zone *zone, struct page *page,
|
||||
if ((flags & MEMORY_OFFLINE) && PageHWPoison(page))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* We treat all PageOffline() pages as movable when offlining
|
||||
* to give drivers a chance to decrement their reference count
|
||||
* in MEM_GOING_OFFLINE in order to indicate that these pages
|
||||
* can be offlined as there are no direct references anymore.
|
||||
* For actually unmovable PageOffline() where the driver does
|
||||
* not support this, we will fail later when trying to actually
|
||||
* move these pages that still have a reference count > 0.
|
||||
* (false negatives in this function only)
|
||||
*/
|
||||
if ((flags & MEMORY_OFFLINE) && PageOffline(page))
|
||||
continue;
|
||||
|
||||
if (__PageMovable(page) || PageLRU(page))
|
||||
continue;
|
||||
|
||||
@@ -8516,6 +8529,7 @@ done:
|
||||
pfn_max_align_up(end), migratetype);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(alloc_contig_range);
|
||||
|
||||
static int __alloc_contig_pages(unsigned long start_pfn,
|
||||
unsigned long nr_pages, gfp_t gfp_mask)
|
||||
@@ -8631,6 +8645,7 @@ void free_contig_range(unsigned long pfn, unsigned int nr_pages)
|
||||
}
|
||||
WARN(count != 0, "%d pages are still in use!\n", count);
|
||||
}
|
||||
EXPORT_SYMBOL(free_contig_range);
|
||||
|
||||
/*
|
||||
* The zone indicated has a new number of managed_pages; batch sizes and percpu
|
||||
@@ -8703,6 +8718,17 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
|
||||
offlined_pages++;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* At this point all remaining PageOffline() pages have a
|
||||
* reference count of 0 and can simply be skipped.
|
||||
*/
|
||||
if (PageOffline(page)) {
|
||||
BUG_ON(page_count(page));
|
||||
BUG_ON(PageBuddy(page));
|
||||
pfn++;
|
||||
offlined_pages++;
|
||||
continue;
|
||||
}
|
||||
|
||||
BUG_ON(page_count(page));
|
||||
BUG_ON(!PageBuddy(page));
|
||||
|
@@ -151,6 +151,7 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
|
||||
* a bit mask)
|
||||
* MEMORY_OFFLINE - isolate to offline (!allocate) memory
|
||||
* e.g., skip over PageHWPoison() pages
|
||||
* and PageOffline() pages.
|
||||
* REPORT_FAILURE - report details about the failure to
|
||||
* isolate the range
|
||||
*
|
||||
@@ -259,6 +260,14 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
|
||||
else if ((flags & MEMORY_OFFLINE) && PageHWPoison(page))
|
||||
/* A HWPoisoned page cannot be also PageBuddy */
|
||||
pfn++;
|
||||
else if ((flags & MEMORY_OFFLINE) && PageOffline(page) &&
|
||||
!page_count(page))
|
||||
/*
|
||||
* The responsible driver agreed to skip PageOffline()
|
||||
* pages when offlining memory by dropping its
|
||||
* reference in MEM_GOING_OFFLINE.
|
||||
*/
|
||||
pfn++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user