Skip to content

Commit 8852ebf

Browse files
mhklinuxliuw
authored andcommitted
hv_balloon: Enable hot-add for memblock sizes > 128 MiB
The Hyper-V balloon driver supports hot-add of memory in addition to ballooning. Current code hot-adds in fixed size chunks of 128 MiB (fixed constant HA_CHUNK in the code). While this works in Hyper-V VMs with 64 GiB or less or memory where the Linux memblock size is 128 MiB, the hot-add fails for larger memblock sizes because add_memory() expects memory to be added in chunks that match the memblock size. Messages like the following are reported when Linux has a 256 MiB memblock size: [ 312.668859] Block size [0x10000000] unaligned hotplug range: start 0x310000000, size 0x8000000 [ 312.668880] hv_balloon: hot_add memory failed error is -22 [ 312.668984] hv_balloon: Memory hot add failed Larger memblock sizes are usually used in VMs with more than 64 GiB of memory, depending on the alignment of the VM's physical address space. Fix this problem by having the Hyper-V balloon driver determine the Linux memblock size, and process hot-add requests in that chunk size instead of a fixed 128 MiB. Also update the hot-add alignment requested of the Hyper-V host to match the memblock size. The code changes look significant, but in fact are just a simple text substitution of a new global variable for the previous HA_CHUNK constant. No algorithms are changed except to initialize the new global variable and to calculate the alignment value to pass to Hyper-V. Testing with memblock sizes of 256 MiB and 2 GiB shows correct operation. Reviewed-by: David Hildenbrand <[email protected]> Signed-off-by: Michael Kelley <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Wei Liu <[email protected]> Message-ID: <[email protected]>
1 parent bb3ca38 commit 8852ebf

File tree

1 file changed

+43
-21
lines changed

1 file changed

+43
-21
lines changed

drivers/hv/hv_balloon.c

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/notifier.h>
2626
#include <linux/percpu_counter.h>
2727
#include <linux/page_reporting.h>
28+
#include <linux/sizes.h>
2829

2930
#include <linux/hyperv.h>
3031
#include <asm/hyperv-tlfs.h>
@@ -425,11 +426,11 @@ struct dm_info_msg {
425426
* The range start_pfn : end_pfn specifies the range
426427
* that the host has asked us to hot add. The range
427428
* start_pfn : ha_end_pfn specifies the range that we have
428-
* currently hot added. We hot add in multiples of 128M
429-
* chunks; it is possible that we may not be able to bring
430-
* online all the pages in the region. The range
429+
* currently hot added. We hot add in chunks equal to the
430+
* memory block size; it is possible that we may not be able
431+
* to bring online all the pages in the region. The range
431432
* covered_start_pfn:covered_end_pfn defines the pages that can
432-
* be brough online.
433+
* be brought online.
433434
*/
434435

435436
struct hv_hotadd_state {
@@ -505,8 +506,11 @@ enum hv_dm_state {
505506

506507
static __u8 recv_buffer[HV_HYP_PAGE_SIZE];
507508
static __u8 balloon_up_send_buffer[HV_HYP_PAGE_SIZE];
509+
510+
static unsigned long ha_pages_in_chunk;
511+
#define HA_BYTES_IN_CHUNK (ha_pages_in_chunk << PAGE_SHIFT)
512+
508513
#define PAGES_IN_2M (2 * 1024 * 1024 / PAGE_SIZE)
509-
#define HA_CHUNK (128 * 1024 * 1024 / PAGE_SIZE)
510514

511515
struct hv_dynmem_device {
512516
struct hv_device *dev;
@@ -724,21 +728,21 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
724728
unsigned long processed_pfn;
725729
unsigned long total_pfn = pfn_count;
726730

727-
for (i = 0; i < (size/HA_CHUNK); i++) {
728-
start_pfn = start + (i * HA_CHUNK);
731+
for (i = 0; i < (size/ha_pages_in_chunk); i++) {
732+
start_pfn = start + (i * ha_pages_in_chunk);
729733

730734
scoped_guard(spinlock_irqsave, &dm_device.ha_lock) {
731-
has->ha_end_pfn += HA_CHUNK;
732-
processed_pfn = umin(total_pfn, HA_CHUNK);
735+
has->ha_end_pfn += ha_pages_in_chunk;
736+
processed_pfn = umin(total_pfn, ha_pages_in_chunk);
733737
total_pfn -= processed_pfn;
734-
has->covered_end_pfn += processed_pfn;
738+
has->covered_end_pfn += processed_pfn;
735739
}
736740

737741
reinit_completion(&dm_device.ol_waitevent);
738742

739743
nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn));
740744
ret = add_memory(nid, PFN_PHYS((start_pfn)),
741-
(HA_CHUNK << PAGE_SHIFT), MHP_MERGE_RESOURCE);
745+
HA_BYTES_IN_CHUNK, MHP_MERGE_RESOURCE);
742746

743747
if (ret) {
744748
pr_err("hot_add memory failed error is %d\n", ret);
@@ -753,7 +757,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
753757
do_hot_add = false;
754758
}
755759
scoped_guard(spinlock_irqsave, &dm_device.ha_lock) {
756-
has->ha_end_pfn -= HA_CHUNK;
760+
has->ha_end_pfn -= ha_pages_in_chunk;
757761
has->covered_end_pfn -= processed_pfn;
758762
}
759763
break;
@@ -829,9 +833,9 @@ static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
829833
* our current limit; extend it.
830834
*/
831835
if ((start_pfn + pfn_cnt) > has->end_pfn) {
832-
/* Extend the region by multiples of HA_CHUNK */
836+
/* Extend the region by multiples of ha_pages_in_chunk */
833837
residual = (start_pfn + pfn_cnt - has->end_pfn);
834-
has->end_pfn += ALIGN(residual, HA_CHUNK);
838+
has->end_pfn += ALIGN(residual, ha_pages_in_chunk);
835839
}
836840

837841
ret = 1;
@@ -897,12 +901,12 @@ static unsigned long handle_pg_range(unsigned long pg_start,
897901
* We have some residual hot add range
898902
* that needs to be hot added; hot add
899903
* it now. Hot add a multiple of
900-
* HA_CHUNK that fully covers the pages
904+
* ha_pages_in_chunk that fully covers the pages
901905
* we have.
902906
*/
903907
size = (has->end_pfn - has->ha_end_pfn);
904908
if (pfn_cnt <= size) {
905-
size = ALIGN(pfn_cnt, HA_CHUNK);
909+
size = ALIGN(pfn_cnt, ha_pages_in_chunk);
906910
} else {
907911
pfn_cnt = size;
908912
}
@@ -1003,8 +1007,8 @@ static void hot_add_req(struct work_struct *dummy)
10031007
* that need to be hot-added while ensuring the alignment
10041008
* and size requirements of Linux as it relates to hot-add.
10051009
*/
1006-
rg_start = ALIGN_DOWN(pg_start, HA_CHUNK);
1007-
rg_sz = ALIGN(pfn_cnt, HA_CHUNK);
1010+
rg_start = ALIGN_DOWN(pg_start, ha_pages_in_chunk);
1011+
rg_sz = ALIGN(pfn_cnt, ha_pages_in_chunk);
10081012
}
10091013

10101014
if (do_hot_add)
@@ -1807,10 +1811,13 @@ static int balloon_connect_vsp(struct hv_device *dev)
18071811
cap_msg.caps.cap_bits.hot_add = hot_add_enabled();
18081812

18091813
/*
1810-
* Specify our alignment requirements as it relates
1811-
* memory hot-add. Specify 128MB alignment.
1814+
* Specify our alignment requirements for memory hot-add. The value is
1815+
* the log base 2 of the number of megabytes in a chunk. For example,
1816+
* with 256 MiB chunks, the value is 8. The number of MiB in a chunk
1817+
* must be a power of 2.
18121818
*/
1813-
cap_msg.caps.cap_bits.hot_add_alignment = 7;
1819+
cap_msg.caps.cap_bits.hot_add_alignment =
1820+
ilog2(HA_BYTES_IN_CHUNK / SZ_1M);
18141821

18151822
/*
18161823
* Currently the host does not use these
@@ -1960,8 +1967,23 @@ static int balloon_probe(struct hv_device *dev,
19601967
hot_add = false;
19611968

19621969
#ifdef CONFIG_MEMORY_HOTPLUG
1970+
/*
1971+
* Hot-add must operate in chunks that are of size equal to the
1972+
* memory block size because that's what the core add_memory()
1973+
* interface requires. The Hyper-V interface requires that the memory
1974+
* block size be a power of 2, which is guaranteed by the check in
1975+
* memory_dev_init().
1976+
*/
1977+
ha_pages_in_chunk = memory_block_size_bytes() / PAGE_SIZE;
19631978
do_hot_add = hot_add;
19641979
#else
1980+
/*
1981+
* Without MEMORY_HOTPLUG, the guest returns a failure status for all
1982+
* hot add requests from Hyper-V, and the chunk size is used only to
1983+
* specify alignment to Hyper-V as required by the host/guest protocol.
1984+
* Somewhat arbitrarily, use 128 MiB.
1985+
*/
1986+
ha_pages_in_chunk = SZ_128M / PAGE_SIZE;
19651987
do_hot_add = false;
19661988
#endif
19671989
dm_device.dev = dev;

0 commit comments

Comments
 (0)