From: sashiko-bot@kernel.org
To: "Joonho Lee" <mynameisjune111@gmail.com>, linux-sound@vger.kernel.org
Cc: virtualization@lists.linux.dev,
"Michael S. Tsirkin" <mst@redhat.com>,
"Eugenio Perez" <eperezma@redhat.com>
Subject: Re: [PATCH v32 20/20] ALSA: virtio: reset the device when PCM state stays unknown
Date: Fri, 13 Nov 2026 07:30:29 +0000 [thread overview]
Message-ID: <sashiko-outbox-212350@kernel.org> (raw)
In-Reply-To: <20261113-fix-virtio-snd-recovery-final-v32-20-4e95979e312c@gmail.com>
Thank you for your contribution! Sashiko AI review found 8 potential
issues to consider:
- [High] ALSA: virtio: deadlock between virtsnd_pcm_prepare() and
virtsnd_recover_work()
- [High] ALSA: virtio: missing recovery wait in open, hw_free, and
virtsnd_pcm_sync_stop()
- [Medium] ALSA: virtio: pending recover_work timer triggers premature
device reset
- [Medium] ALSA: virtio: virtsnd_recover_work() races with freeze/reset
and restore
- [Medium] ALSA: virtio: virtsnd_reset_prepare() does not suspend PCM
streams on reset
- [Medium] ALSA: virtio: snd_pcm_suspend_all() in recovery sends
blocking requests
- [Medium] ALSA: virtio: recovery ordering and races break
virtsnd_pcm_prepare() and virtsnd_pcm_hw_params()
- [Low] ALSA: virtio: double volatile read of jiffies in
virtsnd_recover_work()
--
commit ab36d8f3f343747049667c96b153b488074305f1
Author: Joonho Lee <mynameisjune111@gmail.com>
ALSA: virtio: reset the device when PCM state stays unknown
This commit adds a delayed recovery work item that suspends open PCM
streams and resets the VirtIO sound device when a PCM substream's device
state remains unknown or an I/O queue flush times out, disconnecting the
ALSA card if the transport reset fails.
> diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c
> index 3f2242f274404..dd110fd7ad165 100644
> --- a/sound/virtio/virtio_card.c
> +++ b/sound/virtio/virtio_card.c
[ ... ]
> @@ -528,6 +530,190 @@ static int virtsnd_restore(struct virtio_device *vdev)
>
> return 0;
> }
> +
> +/* Minimum time between recovery resets of one device. */
> +#define VIRTSND_RECOVER_INTERVAL_MS 30000
> +
> +static bool virtsnd_recover_needed(struct virtio_snd *snd)
> +{
> + unsigned int i;
> +
> + for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) {
> + struct virtio_pcm_substream *vss = &snd->substreams[i];
> +
> + guard(spinlock_irqsave)(&vss->lock);
> + if (vss->resetting)
> + continue;
> + if (vss->control_uncertain ||
> + vss->pause_restart_state ==
> + VIRTSND_PCM_PAUSE_RESTART_RESET_REQUIRED ||
> + (vss->io_flush_failed && vss->msg_count))
> + return true;
> + }
> +
> + return false;
> +}
> +
> +/**
> + * virtsnd_recover_work() - Reset the device when a PCM state stays unknown.
> + * @work: Recovery work of the sound device.
> + *
> + * A control reply or released I/O request that never returns leaves its PCM
> + * stream unusable. Suspend the open streams so applications prepare them
> + * again, then reset the device with the transport reset sequence.
> + *
> + * Context: Process context.
> + */
> +static void virtsnd_recover_work(struct work_struct *work)
> +{
> + struct virtio_snd *snd = container_of(to_delayed_work(work),
> + struct virtio_snd, recover_work);
> + struct virtio_device *vdev = snd->vdev;
> + struct virtio_pcm *vpcm;
> + unsigned int i;
> + int rc;
> +
> + if (!virtsnd_recover_needed(snd))
> + return;
> +
> + if (time_before(jiffies, snd->recover_next)) {
> + queue_delayed_work(system_dfl_wq, &snd->recover_work,
> + snd->recover_next - jiffies);
> + return;
> + }
[Severity: Low]
Can snd->recover_next - jiffies underflow here? jiffies is volatile and
read twice, so if it advances to or past snd->recover_next between
time_before() and the subtraction, the delay wraps around near ULONG_MAX
and prevents later queue_delayed_work() calls from scheduling recovery.
> + snd->recover_next = jiffies +
> + msecs_to_jiffies(VIRTSND_RECOVER_INTERVAL_MS);
> +
> + dev_warn(&vdev->dev, "PCM device state is unknown; resetting device\n");
> +
> + WRITE_ONCE(snd->recovering, true);
> + for (i = 0; i < snd->nsubstreams; ++i)
> + wake_up_all(&snd->substreams[i].control_wait);
> +
> + /* Applications observe -ESTRPIPE and prepare their streams again. */
> + list_for_each_entry(vpcm, &snd->pcm_list, list)
> + snd_pcm_suspend_all(vpcm->pcm);
> +
> + rc = virtio_device_reset_prepare(vdev);
[Severity: Medium]
Does calling snd_pcm_suspend_all() before virtio_device_reset_prepare()
cause recovery to send new synchronous control requests and repeat flush
waits against the unresponsive device?
At this point vss->resetting is still false and control messages are not
blocked. In virtsnd_pcm_control_settle(), virtsnd_pcm_control_settled()
is checked before READ_ONCE(vss->snd->recovering), so it returns 0 for any
substream where vss->control_uncertain is false (including streams being
recovered for vss->io_flush_failed or
VIRTSND_PCM_PAUSE_RESTART_RESET_REQUIRED, as well as any other active
substream on the card). During snd_pcm_suspend_all():
- snd_pcm_suspend() -> virtsnd_pcm_trigger(SNDRV_PCM_TRIGGER_SUSPEND)
sends a synchronous VIRTIO_SND_R_PCM_STOP request and blocks for
virtsnd_msg_timeout_ms.
- snd_pcm_sync_stop() -> virtsnd_pcm_release_locked() waits another
virtsnd_msg_timeout_ms on vss->msg_empty, logs a duplicate warning, sets
substream->runtime->stop_operating = true again, and calls
virtsnd_pcm_flush_failed() to re-schedule snd->recover_work for another
reset (or virtsnd_pcm_pause_restart_sync_stop() logs a duplicate error
and calls virtsnd_recover_schedule(vss->snd, 0)).
> + if (!rc)
> + rc = virtio_device_reset_done(vdev);
> + WRITE_ONCE(snd->recover_failed, !!rc);
> + /* Publish the result before releasing configuration waiters. */
> + smp_store_release(&snd->recovering, false);
> + wake_up_all(&snd->recover_wait);
> +
> + if (rc) {
> + /*
> + * Wake configuration waiters before disconnect, which waits for
> + * their ALSA power references to be released.
> + */
> + dev_err(&vdev->dev, "device recovery reset failed: %d; disconnecting\n",
> + rc);
> + snd_card_disconnect(snd->card);
> + }
> +}
> +
> +/**
> + * virtsnd_recover_wait() - Wait until a recovery reset has finished.
> + * @snd: VirtIO sound device.
> + *
> + * Applications prepare their streams again as soon as recovery suspends
> + * them. Configuring a stream must wait until the reset has completed.
> + *
> + * Context: Process context. The caller must not hold the PCM open mutex or
> + * a substream lifecycle lock, which recovery takes.
> + * Return: 0, -ENODEV if recovery failed, or -ERESTARTSYS if killed.
> + */
> +int virtsnd_recover_wait(struct virtio_snd *snd)
> +{
> + int rc;
> +
> + rc = wait_event_killable(snd->recover_wait,
> + /* Pair with recovery's result publication. */
> + !smp_load_acquire(&snd->recovering));
> + if (rc)
> + return rc;
> + return READ_ONCE(snd->recover_failed) ? -ENODEV : 0;
> +}
[Severity: High]
Can virtsnd_recover_wait() called from virtsnd_pcm_prepare() deadlock with
virtsnd_recover_work() and snd_pcm_release()?
snd_pcm_prepare() -> snd_pcm_action_nonatomic() holds
down_read(&snd_pcm_link_rwsem) when it invokes virtsnd_pcm_prepare() ->
virtsnd_recover_wait(). Meanwhile, snd_pcm_release() holds
pcm->open_mutex and calls snd_pcm_release_substream() -> snd_pcm_unlink(),
which unconditionally takes down_write(&snd_pcm_link_rwsem) before
checking whether the substream is linked. Because virtsnd_recover_work()
sets snd->recovering = true before taking pcm->open_mutex in
snd_pcm_suspend_all(), the three contexts can lock up:
CPU0 CPU1 kworker
---- ---- -------
virtsnd_recover_work()
snd->recovering = true
snd_pcm_prepare()
down_read(&snd_pcm_link_rwsem)
virtsnd_pcm_prepare()
virtsnd_recover_wait()
snd_pcm_release()
mutex_lock(&pcm->open_mutex)
snd_pcm_unlink()
down_write(&snd_pcm_link_rwsem)
snd_pcm_suspend_all()
mutex_lock(&pcm->open_mutex)
*** DEADLOCK ***
This wedges system_dfl_wq and the global snd_pcm_link_rwsem across all
sound cards.
> +
> +/**
> + * virtsnd_recover_schedule() - Request a recovery check.
> + * @snd: VirtIO sound device.
> + * @delay: Time before the check, in jiffies. Zero brings a pending check
> + * forward.
> + *
> + * Context: Any context.
> + */
> +void virtsnd_recover_schedule(struct virtio_snd *snd, unsigned long delay)
> +{
> + if (delay)
> + queue_delayed_work(system_dfl_wq, &snd->recover_work, delay);
> + else
> + mod_delayed_work(system_dfl_wq, &snd->recover_work, 0);
> +}
[Severity: Medium]
Can an already-pending snd->recover_work from an earlier event trigger a
premature device reset on a later timeout?
When a late control reply or I/O flush failure occurs at T1,
queue_delayed_work() schedules snd->recover_work for T1 + 5 timeouts. If
that reply arrives and settles the substream (or the I/O queue drains),
snd->recover_work remains queued for T1 + 5 timeouts. If another control
reply is late or an I/O flush fails at T2 < T1 + 5 timeouts,
queue_delayed_work() leaves the timer at T1 + 5 timeouts, and when
virtsnd_recover_work() runs at T1 + 5 timeouts, virtsnd_recover_needed()
sees vss->control_uncertain or (vss->io_flush_failed && vss->msg_count) set
and immediately resets the device before the second event's 4-timeout
settle window has elapsed.
> +
> +/*
> + * Transport resets and driver recovery use the freeze and restore sequence.
> + * Recovery calls these callbacks from its own work item.
> + */
> +static int virtsnd_reset_prepare(struct virtio_device *vdev)
> +{
> + struct virtio_snd *snd = vdev->priv;
> +
> + if (current_work() != &snd->recover_work.work)
> + disable_delayed_work_sync(&snd->recover_work);
> + virtsnd_quiesce(snd);
> +
> + return 0;
> +}
> +
> +static int virtsnd_reset_done(struct virtio_device *vdev)
> +{
> + struct virtio_snd *snd = vdev->priv;
> + int rc;
> +
> + rc = virtsnd_restart(snd);
> + if (current_work() != &snd->recover_work.work)
> + enable_delayed_work(&snd->recover_work);
> +
> + return rc;
> +}
[Severity: Medium]
On a transport-initiated reset (where current_work() !=
&snd->recover_work.work), does virtsnd_reset_prepare() leave open ALSA PCM
streams in their active states instead of suspending them?
During system sleep, the PM core suspends child PCM devices before calling
virtsnd_freeze(), and virtsnd_recover_work() calls snd_pcm_suspend_all()
before virtio_device_reset_prepare(). A transport-initiated reset calls
virtsnd_reset_prepare() directly without setting snd->recovering or
calling snd_pcm_suspend_all(), so virtsnd_quiesce() detaches all virtqueue
buffers and sets vss->prepared = false and vss->suspended = true while
leaving substream->runtime->state in RUNNING, PREPARED, or PAUSED, causing
blocked readers/writers to hang until timeout (-EIO) instead of observing
-ESTRPIPE and subsequent triggers to fail with -EBADFD. In addition, if
virtsnd_restart() fails in virtsnd_reset_done(), it still re-enables
snd->recover_work and does not set snd->recover_failed or disconnect the
card.
> +
> +#ifdef CONFIG_PM_SLEEP
> +/**
> + * virtsnd_freeze() - Suspend device.
> + * @vdev: VirtIO parent device.
> + *
> + * Context: Any context.
> + * Return: 0 on success, -errno on failure.
> + */
> +static int virtsnd_freeze(struct virtio_device *vdev)
> +{
> + struct virtio_snd *snd = vdev->priv;
> +
> + disable_delayed_work_sync(&snd->recover_work);
> + virtsnd_quiesce(snd);
> +
> + return 0;
> +}
> +
> +/**
> + * virtsnd_restore() - Resume device.
> + * @vdev: VirtIO parent device.
> + *
> + * Context: Any context.
> + * Return: 0 on success, -errno on failure.
> + */
> +static int virtsnd_restore(struct virtio_device *vdev)
> +{
> + struct virtio_snd *snd = vdev->priv;
> + int rc;
> +
> + rc = virtsnd_restart(snd);
> + enable_delayed_work(&snd->recover_work);
> +
> + return rc;
> +}
[Severity: Medium]
Can virtsnd_recover_work() race with virtio_device_freeze() or a
transport-initiated virtio_device_reset_prepare(), and can
virtsnd_restore() or virtsnd_reset_done() revive a card that was already
disconnected after a failed recovery?
virtio_device_freeze() and virtio_device_reset_prepare() call
virtio_config_core_disable(vdev) before invoking the driver callback:
CPU0 kworker
---- -------
virtio_device_freeze(vdev) virtsnd_recover_work()
virtio_config_core_disable(vdev)
virtsnd_freeze(vdev)
disable_delayed_work_sync(...)
virtio_device_reset_done(vdev)
virtio_device_restore_priv(vdev)
virtio_config_core_enable(vdev)
virtsnd_quiesce(snd) <-- vdev->config_core_enabled left true
Furthermore, if virtsnd_recover_work() fails its reset, sets
snd->recover_failed = true, and disconnects snd->card, a subsequent
virtsnd_restore() or transport-initiated virtsnd_reset_done() does not
check snd->recover_failed and unconditionally calls virtsnd_restart() and
enable_delayed_work(&snd->recover_work), re-initializing virtqueues and
enabling event dispatch on a disconnected card.
> diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c
> index 15d4473f4c0a0..dcce428d704c7 100644
> --- a/sound/virtio/virtio_pcm_ops.c
> +++ b/sound/virtio/virtio_pcm_ops.c
[ ... ]
> @@ -661,6 +706,9 @@ static int virtsnd_pcm_hw_params(struct snd_pcm_substream *substream,
> u64 epoch;
> int rc;
>
> + rc = virtsnd_recover_wait(vss->snd);
> + if (rc)
> + return rc;
> guard(mutex)(&vss->lifecycle_lock);
[Severity: High]
Why don't virtsnd_pcm_open(), virtsnd_pcm_hw_free(), and
virtsnd_pcm_sync_stop() also wait for an in-progress recovery reset?
The commit message notes that open and hw_free do not wait because they
run under pcm->open_mutex, which recovery takes to suspend the streams.
However:
1. virtsnd_recover_work() only holds pcm->open_mutex inside
snd_pcm_suspend_all() and releases it before calling
virtio_device_reset_prepare() and virtio_device_reset_done(), so
pcm->open_mutex is not held while vss->resetting and snd->recovering
are true.
2. SNDRV_PCM_IOCTL_HW_FREE (snd_pcm_hw_free()) and the error path of
snd_pcm_hw_params() only take runtime->buffer_mutex, never
pcm->open_mutex.
As a result, during recovery virtsnd_pcm_open() fails with -ECANCELED or
-EIO; virtsnd_pcm_hw_free() on close returns -EIO or -ECANCELED from
virtsnd_pcm_sync_stop_locked() before virtsnd_reset_vqs() detaches pending
buffers, causing !virtsnd_pcm_msg_pending_num(vss) to be false and skipping
virtsnd_pcm_msg_free(vss) so vss->msgs and vss->dma_pages remain allocated;
and when snd_pcm_hw_params() or snd_pcm_do_prepare() calls
snd_pcm_sync_stop() before invoking ops->hw_params() or ops->prepare(),
virtsnd_pcm_sync_stop() sees vss->resetting == true and sets
substream->runtime->stop_operating = true again before
virtsnd_recover_wait() runs.
[ ... ]
> @@ -933,6 +982,10 @@ static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream)
>
> int rc;
>
> + /* Applications prepare again as soon as recovery suspends the stream. */
> + rc = virtsnd_recover_wait(vss->snd);
> + if (rc)
> + return rc;
> guard(mutex)(&vss->lifecycle_lock);
> rc = virtsnd_pcm_prepare_locked(substream);
[Severity: Medium]
Can ordering races between virtsnd_pcm_control_settle(),
virtsnd_recover_work(), and virtsnd_recover_wait() cause
snd_pcm_prepare() and snd_pcm_hw_params() to fail with -EIO or -ESTRPIPE
instead of waiting for recovery?
Two sequences can happen when recovery starts:
1. In snd_pcm_do_prepare() and snd_pcm_hw_params(), ALSA core calls
snd_pcm_sync_stop() before ops->prepare() or ops->hw_params(). When
vss->control_uncertain is true and runtime->stop_operating is set,
snd_pcm_sync_stop() -> virtsnd_pcm_control_settle() waits 4 timeouts,
calls virtsnd_recover_schedule(vss->snd, 0), and returns -EIO (which
snd_pcm_sync_stop() ignores). Because virtsnd_recover_schedule() only
queues snd->recover_work without setting snd->recovering = true,
virtsnd_recover_wait() in virtsnd_pcm_prepare() or
virtsnd_pcm_hw_params() sees snd->recovering == false and returns 0
immediately. virtsnd_pcm_prepare_locked() or virtsnd_pcm_hw_params()
then enters virtsnd_pcm_control_settle() a second time, which either
returns -EIO as soon as virtsnd_recover_work() sets snd->recovering =
true (leaving runtime->state in SNDRV_PCM_STATE_SETUP, which
snd_pcm_suspend_all() then skips with -EBUSY) or waits another 4
timeouts if rate-limited by snd->recover_next.
2. In virtsnd_recover_work(), WRITE_ONCE(snd->recovering, true) runs
before snd_pcm_suspend_all(). If a thread enters snd_pcm_prepare() on
a stream in PREPARED or XRUN state after snd->recovering becomes true
and sleeps in virtsnd_recover_wait() before snd_pcm_suspend_all()
suspends that substream, snd_pcm_suspend_all() sets runtime->state to
SNDRV_PCM_STATE_SUSPENDED while the thread is sleeping. After the
reset completes, virtsnd_pcm_prepare_locked() configures and prepares
the reset device, but snd_pcm_finish_prepare() then sees
runtime->state == SNDRV_PCM_STATE_SUSPENDED, cancels the completed
prepare via virtsnd_pcm_prepare_complete(s, false), and returns
-ESTRPIPE:
sound/core/pcm_native.c:snd_pcm_finish_prepare() {
if (runtime->state == SNDRV_PCM_STATE_SUSPENDED) {
snd_pcm_Substream_ops_prepare_complete(substream, false);
return -ESTRPIPE;
}
}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261113-fix-virtio-snd-recovery-final-v32-0-4e95979e312c@gmail.com?part=20
prev parent reply other threads:[~2026-11-13 7:30 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 6:41 [PATCH v32 00/20] ALSA: virtio: preserve PCM progress Joonho Lee via B4 Relay
2026-11-13 6:41 ` [PATCH v32 01/20] ALSA: pcm: mark stop-threshold accesses for capture policy sampling Joonho Lee via B4 Relay
2026-11-13 6:46 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 02/20] ALSA: pcm: report partial progress under the stream lock Joonho Lee via B4 Relay
2026-11-13 7:05 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 03/20] ALSA: pcm: add an optional reset operation " Joonho Lee via B4 Relay
2026-11-13 6:51 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 04/20] ALSA: pcm: notify drivers after linked prepare completes Joonho Lee via B4 Relay
2026-11-13 6:53 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 05/20] ALSA: pcm: serialize linked buffer actions Joonho Lee via B4 Relay
2026-11-13 6:51 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 06/20] ALSA: virtio: propagate playback send failures through ACK Joonho Lee via B4 Relay
2026-11-13 7:08 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 07/20] ALSA: virtio: Recover PCM state after a failed start Joonho Lee via B4 Relay
2026-11-13 7:08 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 08/20] ALSA: virtio: Retain queued messages through device reset Joonho Lee via B4 Relay
2026-11-13 7:01 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 09/20] ALSA: virtio: bound PCM transfers and retain DMA buffers Joonho Lee via B4 Relay
2026-11-13 7:11 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 10/20] ALSA: virtio: Keep control payloads alive through DMA completion Joonho Lee via B4 Relay
2026-11-13 6:50 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 11/20] ALSA: virtio: wait through signals for PCM teardown Joonho Lee via B4 Relay
2026-11-13 6:58 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 12/20] ALSA: virtio: use request-owned capture and serialize recovery Joonho Lee via B4 Relay
2026-11-13 7:10 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 13/20] ALSA: virtio: prioritize capture period work Joonho Lee via B4 Relay
2026-11-13 6:50 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 14/20] docs: describe virtio-sound capture options Joonho Lee via B4 Relay
2026-11-13 6:52 ` sashiko-bot
2026-11-13 6:41 ` [PATCH v32 15/20] ALSA: virtio: reject invalid playback completions Joonho Lee via B4 Relay
2026-11-13 6:59 ` sashiko-bot
2026-11-13 6:42 ` [PATCH v32 16/20] ALSA: pcm: add an explicit application pointer to indirect playback transfer Joonho Lee via B4 Relay
2026-11-13 6:54 ` sashiko-bot
2026-11-13 6:42 ` [PATCH v32 17/20] ALSA: virtio: preserve playback progress across pause and buffer access Joonho Lee via B4 Relay
2026-11-13 7:08 ` sashiko-bot
2026-11-13 6:42 ` [PATCH v32 18/20] ALSA: virtio: settle PCM control state from late replies Joonho Lee via B4 Relay
2026-11-13 7:26 ` sashiko-bot
2026-11-13 6:42 ` [PATCH v32 19/20] ALSA: pcm: allow stream suspension without power management Joonho Lee via B4 Relay
2026-11-13 6:58 ` sashiko-bot
2026-11-13 6:42 ` [PATCH v32 20/20] ALSA: virtio: reset the device when PCM state stays unknown Joonho Lee via B4 Relay
2026-11-13 7:30 ` sashiko-bot [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=sashiko-outbox-212350@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=eperezma@redhat.com \
--cc=linux-sound@vger.kernel.org \
--cc=mst@redhat.com \
--cc=mynameisjune111@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=virtualization@lists.linux.dev \
/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