From: Stanislav Kinsburskii <[email protected]> Sent: Thursday,
May 7, 2026 8:43 AM
>
> The bounds check inside the PFN-filling loop can return -EINVAL while
> interrupts are disabled via local_irq_save(), leaking IRQ state.
>
> Remove the check — it is redundant because the loop invariant
> (done + i < page_count == page_struct_count >> large_shift) guarantees
> (done + i) << large_shift < page_struct_count always holds.
>
> While here, fix type mismatches: change 'int done' to 'u64 done' and
> use u64 for loop and batch-size variables so they match the u64
> page_count they are compared against.
>
> Fixes: 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose
> /dev/mshv to VMMs")
> Signed-off-by: Stanislav Kinsburskii <[email protected]>
> ---
> drivers/hv/mshv_root_hv_call.c | 18 ++++++------------
> 1 file changed, 6 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
> index 129456bd72aba..cc580225e9e45 100644
> --- a/drivers/hv/mshv_root_hv_call.c
> +++ b/drivers/hv/mshv_root_hv_call.c
> @@ -1042,7 +1042,7 @@ int hv_call_modify_spa_host_access(u64 partition_id,
> struct page **pages,
> {
> struct hv_input_modify_sparse_spa_page_host_access *input_page;
> u64 status;
> - int done = 0;
> + u64 done = 0;
> unsigned long irq_flags, large_shift = 0;
> u64 page_count = page_struct_count;
> u16 code = acquire ? HVCALL_ACQUIRE_SPARSE_SPA_PAGE_HOST_ACCESS :
> @@ -1059,9 +1059,9 @@ int hv_call_modify_spa_host_access(u64 partition_id,
> struct page **pages,
> }
>
> while (done < page_count) {
> - ulong i, completed, remain = page_count - done;
> - int rep_count = min(remain,
> -
> HV_MODIFY_SPARSE_SPA_PAGE_HOST_ACCESS_MAX_PAGE_COUNT);
> + u64 i, completed, remain = page_count - done;
> + u64 rep_count = min_t(u64, remain,
> +
> HV_MODIFY_SPARSE_SPA_PAGE_HOST_ACCESS_MAX_PAGE_COUNT);
Why does this need to be "min_t()" instead of just "min()"? Needing min_t()
was the case in times past, but "min()" does a much better job now of handling
mixed integer types. There are a number of patches on LKML that are
replacing min_t() with min(). This change seems to be going the opposite
direction.
>
> local_irq_save(irq_flags);
> input_page = *this_cpu_ptr(hyperv_pcpu_input_arg);
> @@ -1075,15 +1075,9 @@ int hv_call_modify_spa_host_access(u64 partition_id,
> struct page **pages,
> input_page->flags = flags;
> input_page->host_access = host_access;
>
> - for (i = 0; i < rep_count; i++) {
> - u64 index = (done + i) << large_shift;
> -
> - if (index >= page_struct_count)
> - return -EINVAL;
> -
> + for (i = 0; i < rep_count; i++)
> input_page->spa_page_list[i] =
> - page_to_pfn(pages[index]);
> - }
> + page_to_pfn(pages[(done + i) << large_shift]);
>
> status = hv_do_rep_hypercall(code, rep_count, 0, input_page,
> NULL);
>
The "completed" local variable could be collapsed out by doing:
done += hv_repcomp(status)