From: "Doru Blânzeanu" <dblanzeanu@linux.microsoft.com>
To: wei.liu@kernel.org
Cc: Linux on Hyper-V List <linux-hyperv@vger.kernel.org>,
mukeshrathor@linux.microsoft.com,
magnuskulke@linux.microsoft.com,
John Starks <jostarks@microsoft.com>,
Haiyang Zhang <haiyangz@microsoft.com>,
Dexuan Cui <decui@microsoft.com>,
Michael Kelley <mhklinux@outlook.com>,
Naman Jain <namjain@linux.microsoft.com>,
Nuno Das Neves <nunodasneves@linux.microsoft.com>,
Muminul Islam <muislam@microsoft.com>,
Anatol Belski <anbelski@linux.microsoft.com>,
open list <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] mshv: Add an ioctl to scrub partition state
Date: Thu, 5 Nov 2026 13:14:08 +0200 [thread overview]
Message-ID: <auxlAE9xTnZU6Eqo@linux.microsoft.com> (raw)
In-Reply-To: <20261029062801.28598-2-wei.liu@kernel.org>
On Wed, Oct 28, 2026 at 11:27:54PM -0700, wei.liu@kernel.org wrote:
> From: John Starks <jostarks@microsoft.com>
>
> Userspace VMMs need to reset a child partition's hypervisor-managed state
> without destroying its VPs or rebuilding its memory and eventfd
> registrations. Exposing HvCallScrubPartition through generic hypercall
> passthrough would bypass the synchronization and cached-state updates
> needed by the driver.
>
> Add MSHV_SCRUB_PARTITION as a no-argument partition-fd ioctl. Hold the
> partition mutex and try-lock each populated VP mutex in index order,
> using the partition mutex as the lockdep nesting lock. Return -EBUSY
> without issuing the hypercall if a VP is busy. This excludes VP ioctls
> without waiting indefinitely for a running VP; userspace must stop its
> run threads before requesting scrub.
>
> After a successful scrub, clear cached intercept suspend so the next run
> clears explicit suspend rather than trying to consume a stale intercept.
> Preserve deferred blocked waits and notification accounting: a VP becoming
> dispatchable does not imply its host notification has already arrived.
> Keep the locks through this update and unwind them on every exit.
>
> Scrub is nonallocating, so issue one fast hypercall, trace its status and
> return the existing errno translation. Let the hypervisor determine which
> partition configurations support scrub. Device quiescing and restoring
> guest execution state remain userspace responsibilities.
>
> Signed-off-by: John Starks <jostarks@microsoft.com>
> Signed-off-by: Wei Liu <wei.liu@kernel.org>
>
> ---
> Tested repeated scrub/run, sparse and 64-VP locking, busy unwinding,
> interrupted blocked runs, concurrent memory invalidation and irqfd
> activity on x86-64, and delayed notifications with separate diagnostic
> instrumentation. The affected ARM64 objects compile. ARM64 runtime and
> hypervisor scheduling remain untested. Doorbell delivery across scrub
> works, but exposes an existing eventfd hardirq wait-context warning under
> lockdep, separate from this change.
>
> GitHub Copilot generated the implementation and test probes, investigated
> locking and notification handling, ran builds and Incubator tests, and
> drafted this description. Human review selected the dedicated ioctl and
> try-lock policy and corrected the nonallocating hypercall contract.
> ---
> drivers/hv/mshv_root.h | 1 +
> drivers/hv/mshv_root_hv_call.c | 11 ++++++++
> drivers/hv/mshv_root_main.c | 50 ++++++++++++++++++++++++++++++++++
> drivers/hv/mshv_trace.h | 17 ++++++++++++
> include/hyperv/hvgdk_mini.h | 1 +
> include/hyperv/hvhdk.h | 4 +++
> include/uapi/linux/mshv.h | 11 ++++++++
> 7 files changed, 95 insertions(+)
>
> diff --git a/drivers/hv/mshv_root.h b/drivers/hv/mshv_root.h
> index 1f086dcb7aa1..0c89d47c3ab5 100644
> --- a/drivers/hv/mshv_root.h
> +++ b/drivers/hv/mshv_root.h
> @@ -279,6 +279,7 @@ int hv_call_create_partition(u64 flags,
> union hv_partition_isolation_properties isolation_properties,
> u64 *partition_id);
> int hv_call_initialize_partition(u64 partition_id);
> +int hv_call_scrub_partition(u64 partition_id);
> int hv_call_finalize_partition(u64 partition_id);
> int hv_call_delete_partition(u64 partition_id);
> int hv_call_map_mmio_pages(u64 partition_id, u64 gfn, u64 mmio_spa, u64 numpgs);
> diff --git a/drivers/hv/mshv_root_hv_call.c b/drivers/hv/mshv_root_hv_call.c
> index cb55d4d4be2e..8ab99f1afeed 100644
> --- a/drivers/hv/mshv_root_hv_call.c
> +++ b/drivers/hv/mshv_root_hv_call.c
> @@ -161,6 +161,17 @@ int hv_call_initialize_partition(u64 partition_id)
> return ret;
> }
>
> +int hv_call_scrub_partition(u64 partition_id)
> +{
> + u64 status;
> +
> + status = hv_do_fast_hypercall8(HVCALL_SCRUB_PARTITION, partition_id);
> +
> + trace_mshv_hvcall_scrub_partition(partition_id, status);
> +
> + return hv_result_to_errno(status);
> +}
> +
> int hv_call_finalize_partition(u64 partition_id)
> {
> struct hv_input_finalize_partition input;
> diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
> index cc2cfce2aefd..9f21855b8518 100644
> --- a/drivers/hv/mshv_root_main.c
> +++ b/drivers/hv/mshv_root_main.c
> @@ -1648,6 +1648,53 @@ mshv_partition_ioctl_initialize(struct mshv_partition *partition)
> return ret;
> }
>
> +static int mshv_partition_ioctl_scrub(struct mshv_partition *partition)
> +{
> + unsigned int i, vps_locked = 0;
> + int ret;
> +
> + lockdep_assert_held(&partition->pt_mutex);
> +
> + /*
> + * Run ioctls may wait indefinitely. Userspace must stop its run
> + * threads; never wait for a VP while holding the others. The
> + * partition mutex stabilizes even a sparse VP array.
> + */
> + for (; vps_locked < MSHV_MAX_VPS; vps_locked++) {
> + struct mshv_vp *vp = partition->pt_vp_array[vps_locked];
> +
> + if (vp && !mutex_trylock_nest_lock(&vp->vp_mutex,
> + &partition->pt_mutex)) {
> + ret = -EBUSY;
> + goto unlock;
> + }
> + }
> +
> + ret = hv_call_scrub_partition(partition->pt_id);
> + if (ret)
> + goto unlock;
> +
> + /*
> + * Scrub clears intercept suspend and sets explicit suspend.
> + * Retain deferred waits and lifetime notification accounting.
> + */
> + for (i = 0; i < MSHV_MAX_VPS; i++) {
> + struct mshv_vp *vp = partition->pt_vp_array[i];
> +
> + if (vp)
> + vp->run.flags.intercept_suspend = 0;
> + }
> +
> +unlock:
> + while (vps_locked) {
> + struct mshv_vp *vp = partition->pt_vp_array[--vps_locked];
> +
> + if (vp)
> + mutex_unlock(&vp->vp_mutex);
> + }
> + return ret;
> +}
> +
> static long
> mshv_partition_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
> {
> @@ -1662,6 +1709,9 @@ mshv_partition_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
> case MSHV_INITIALIZE_PARTITION:
> ret = mshv_partition_ioctl_initialize(partition);
> break;
> + case MSHV_SCRUB_PARTITION:
> + ret = mshv_partition_ioctl_scrub(partition);
> + break;
> case MSHV_SET_GUEST_MEMORY:
> ret = mshv_partition_ioctl_set_memory(partition, uarg);
> break;
> diff --git a/drivers/hv/mshv_trace.h b/drivers/hv/mshv_trace.h
> index e7280c47e579..9f6d9e67d987 100644
> --- a/drivers/hv/mshv_trace.h
> +++ b/drivers/hv/mshv_trace.h
> @@ -71,6 +71,23 @@ TRACE_EVENT(mshv_hvcall_initialize_partition,
> )
> );
>
> +TRACE_EVENT(mshv_hvcall_scrub_partition,
> + TP_PROTO(u64 partition_id, u64 status),
> + TP_ARGS(partition_id, status),
> + TP_STRUCT__entry(
> + __field(u64, partition_id)
> + __field(u64, status)
> + ),
> + TP_fast_assign(
> + __entry->partition_id = partition_id;
> + __entry->status = status;
> + ),
> + TP_printk("partition_id=%llu status=%#llx",
> + __entry->partition_id,
> + __entry->status
> + )
> +);
> +
> TRACE_EVENT(mshv_partition_release,
> TP_PROTO(u64 partition_id),
> TP_ARGS(partition_id),
> diff --git a/include/hyperv/hvgdk_mini.h b/include/hyperv/hvgdk_mini.h
> index 6a4e8b9d570f..c0172699b145 100644
> --- a/include/hyperv/hvgdk_mini.h
> +++ b/include/hyperv/hvgdk_mini.h
> @@ -478,6 +478,7 @@ union hv_vp_assist_msr_contents { /* HV_REGISTER_VP_ASSIST_PAGE */
> #define HVCALL_NOTIFY_PARTITION_EVENT 0x0087
> #define HVCALL_ENTER_SLEEP_STATE 0x0084
> #define HVCALL_NOTIFY_PORT_RING_EMPTY 0x008b
> +#define HVCALL_SCRUB_PARTITION 0x008d
> #define HVCALL_REGISTER_INTERCEPT_RESULT 0x0091
> #define HVCALL_ASSERT_VIRTUAL_INTERRUPT 0x0094
> #define HVCALL_CREATE_PORT 0x0095
> diff --git a/include/hyperv/hvhdk.h b/include/hyperv/hvhdk.h
> index 0c89c62c9706..d0043860693c 100644
> --- a/include/hyperv/hvhdk.h
> +++ b/include/hyperv/hvhdk.h
> @@ -369,6 +369,10 @@ struct hv_input_delete_partition {
> u64 partition_id;
> } __packed;
>
> +struct hv_input_scrub_partition {
> + u64 partition_id;
> +} __packed;
> +
> struct hv_input_get_partition_property {
> u64 partition_id;
> u32 property_code; /* enum hv_partition_property_code */
> diff --git a/include/uapi/linux/mshv.h b/include/uapi/linux/mshv.h
> index 32ff92b6342b..7681e3c73a7a 100644
> --- a/include/uapi/linux/mshv.h
> +++ b/include/uapi/linux/mshv.h
> @@ -255,6 +255,17 @@ struct mshv_root_hvcall {
> /* Generic hypercall */
> #define MSHV_ROOT_HVCALL _IOWR(MSHV_IOCTL, 0x07, struct mshv_root_hvcall)
>
> +/*
> + * Scrub a partition's guest state; takes no arguments.
> + * Stop all VP run threads first: a busy VP causes -EBUSY without issuing
> + * the hypercall. On success, the VPs are explicitly suspended.
> + *
> + * Kernel resource registrations and VP fd/mmap lifetimes are preserved.
> + * Userspace must quiesce its devices and restore guest execution state.
> + * Failure does not imply successful reset or guaranteed rollback.
> + */
> +#define MSHV_SCRUB_PARTITION _IO(MSHV_IOCTL, 0x0B)
> +
> /*
> ********************************
> * VP APIs for child partitions *
> --
> 2.53.0
Tested-by: Doru Blânzeanu <dblanzeanu@linux.microsoft.com>
prev parent reply other threads:[~2026-11-05 11:14 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-29 6:27 wei.liu
2026-11-05 11:14 ` Doru Blânzeanu [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=auxlAE9xTnZU6Eqo@linux.microsoft.com \
--to=dblanzeanu@linux.microsoft.com \
--cc=anbelski@linux.microsoft.com \
--cc=decui@microsoft.com \
--cc=haiyangz@microsoft.com \
--cc=jostarks@microsoft.com \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=magnuskulke@linux.microsoft.com \
--cc=mhklinux@outlook.com \
--cc=muislam@microsoft.com \
--cc=mukeshrathor@linux.microsoft.com \
--cc=namjain@linux.microsoft.com \
--cc=nunodasneves@linux.microsoft.com \
--cc=wei.liu@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®