From: Stanislav Kinsburskii <[email protected]> Sent: Tuesday,
March 3, 2026 4:24 PM
>
> Convert hv_call_deposit_pages() into a wrapper supporting arbitrary number
> of pages, and use it in the memory deposit code paths.
>
> Signed-off-by: Stanislav Kinsburskii <[email protected]>
> ---
> drivers/hv/hv_proc.c | 50
> +++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 49 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hv/hv_proc.c b/drivers/hv/hv_proc.c
> index 5f4fd9c3231c..0f84a70def30 100644
> --- a/drivers/hv/hv_proc.c
> +++ b/drivers/hv/hv_proc.c
> @@ -16,7 +16,7 @@
> #define HV_DEPOSIT_MAX (HV_HYP_PAGE_SIZE / sizeof(u64) - 1)
>
> /* Deposits exact number of pages. Must be called with interrupts enabled.
> */
> -int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> +static int __hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
> {
> struct page **pages, *page;
> int *counts;
> @@ -108,6 +108,54 @@ int hv_call_deposit_pages(int node, u64 partition_id,
> u32 num_pages)
> kfree(counts);
> return ret;
> }
> +
> +/**
> + * hv_call_deposit_pages - Deposit memory pages to a partition
> + * @node : NUMA node from which to allocate pages
> + * @partition_id: Target partition ID to deposit pages to
> + * @num_pages : Number of pages to deposit
> + *
> + * Deposits memory pages to the specified partition. The deposit is
> + * performed in chunks of HV_DEPOSIT_MAX pages to handle large requests
> + * efficiently.
> + *
> + * Return: 0 on success, negative error code on failure
For the failure case, a key fact seems to be that there's no attempt to
withdraw any pages that might have been successfully deposited. In
such failure case, the caller has no information about how many pages
were, or were not, deposited. The 2x for L1VH further muddies the
picture.
__hv_call_deposit_pages() apparently assumes that if the underlying
hypercall fails, none of the pages were deposited. So it frees all the
allocated pages. But I wonder if that's really true. The hypercall is
a rep hypercall, which can get partly through the list, return to the
guest, then restart where it left off. If there's a failure after a
restart, I wonder if the hypercall goes back and withdraws any
pages that were successfully deposited before the restart. The
restart behaves like a new invocation of the hypercall.
> + */
> +int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
Perhaps the num_pages parameter should be a u64. The u32 imposes
a limit of 8 Tbytes on the amount of memory that can be deposited
(allowing for the 2x multiplier for L1VH partitions). Azure has VM sizes
today with up to 30 Tbytes of memory, so it's certainly possible.
> +{
> + u32 done;
Same here. Use u64.
> + int ret = 0;
> +
> + /*
> + * Do a double deposit for L1VH. This reserves enough memory for
> + * Hypervisor Hot Restart (HHR).
> + *
> + * During HHR, every data structure must be recreated in the new
> + * ("proto") hypervisor. Memory is required by the proto hypervisor
> + * to do this work.
> + *
> + * For regular L1 partitions, more memory can be requested from the
> + * root during HHR by sending an asynchronous message. But this is
> + * not supported for L1VHs. A guest must not be allowed to block
> + * HHR by refusing to deposit more memory.
> + *
> + * So for L1VH a deposit is always required for both current needs
> + * and future HHR work.
> + */
> + if (hv_l1vh_partition())
> + num_pages *= 2;
> +
> + for (done = 0; done < num_pages; done += HV_DEPOSIT_MAX) {
> + u32 to_deposit = min(num_pages - done, HV_DEPOSIT_MAX);
> +
> + ret = __hv_call_deposit_pages(node, partition_id,
> + to_deposit);
> + if (ret)
> + break;
> + }
> +
> + return ret;
> +}
> EXPORT_SYMBOL_GPL(hv_call_deposit_pages);
>
> int hv_deposit_memory_node(int node, u64 partition_id,
>
>