Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: David Woodhouse <dwmw2@infradead.org>
Cc: Stefan Hajnoczi <stefanha@redhat.com>,
	pbonzini@redhat.com,  John Levon <john.levon@nutanix.com>,
	"kvm@vger.kernel.org" <kvm@vger.kernel.org>,
	 Thanos Makatos <thanos.makatos@nutanix.com>
Subject: Re: [PATCH] KVM: optionally post write on ioeventfd write
Date: Tue, 22 Sep 2026 09:47:39 -0700	[thread overview]
Message-ID: <arKxK-L85xIKIvdU@google.com> (raw)
In-Reply-To: <a3b8006c2953e6bda2e83d902fbbab1700fadd08.camel@infradead.org>

On Tue, Sep 22, 2026, David Woodhouse wrote:
> On Tue, 2026-09-22 at 09:51 -0400, Stefan Hajnoczi wrote:
> > On Fri, Mar 06, 2026 at 12:56:54PM +0000, Thanos Makatos wrote:
> > > Add a new flag, KVM_IOEVENTFD_FLAG_POST_WRITE, when assigning an
> > > ioeventfd that results in the value written by the guest to be copied
> > > to user-supplied memory instead of being discarded.
> > > 
> > > The goal of this new mechanism is to speed up doorbell writes on NVMe
> > > controllers emulated outside of the VMM. Currently, a doorbell write to
> > > an NVMe SQ tail doorbell requires returning from ioctl(KVM_RUN) and the
> > > VMM communicating the event, along with the doorbell value, to the NVMe
> > > controller emulation task.  With POST_WRITE, the NVMe emulation task is
> > > directly notified of the doorbell write and can find the doorbell value
> > > in a known location, without involving VMM.
> > > 
> > > Add tests for this new functionality.
> > > 
> > > LLM (claude-4.6-opus-high) was used mainly for the tests and to a
> > > lesser extent for pre-reviewing this patch.
> > > 
> > > Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com>
> > > ---
> > >  Documentation/virt/kvm/api.rst               |  13 +-
> > >  include/uapi/linux/kvm.h                     |   6 +-
> > >  tools/testing/selftests/kvm/Makefile.kvm     |   1 +
> > >  tools/testing/selftests/kvm/ioeventfd_test.c | 624 +++++++++++++++++++
> > >  virt/kvm/eventfd.c                           |  23 +
> > >  virt/kvm/kvm_main.c                          |   1 +
> > >  6 files changed, 666 insertions(+), 2 deletions(-)
> > >  create mode 100644 tools/testing/selftests/kvm/ioeventfd_test.c
> > 
> > Sean, Paolo: Ping
> > 
> > I would like to enable ioeventfd support in QEMU's NVMe device emulation
> > and this requires POST_WRITE for Windows guests (they don't support
> > NVMe's Doorbell Buffer Config feature so it's necessary to capture the
> > latest value written to the doorbell somehow).
> > 
> > POST_WRITE applies to any device that has a doorbell register where the
> > latest value needs to be captured. This looks like a reasonable
> > extension to ioeventfd.
> > 
> > I also looked into alternatives, like using userfaultfd, and didn't find
> > anything better.
> > 
> > Please consider merging this. Thanks!
> 
> I said I was working on using this for i82559 emulation; I have that
> working now, and POST_WRITE is perfectly sufficient.
> 
> I think I'd prefer to see it use a WRITE_ONCE to the userspace address
> rather than a __copy_to_user() which could theoretically tear,

Hrm, I was going to say that's a "feature" of sorts, not a bug, as eventfd_signal()
provides ordering by way of its spinlock, but I'm guessing that the userspace side
wants to read the tail pointer multiple times per wakeup, i.e. wants to eagerly
process all transactions.

I don't see any explicit documentation with respect to put_user() providing
atomicity guarantees, but unsafe_atomic_store_release_user() uses unsafe_put_user(),
so presumably that's an undocumented requirement?  Ah, not a requirement so much as
a "this will work so long as userspace isn't being stupid".  E.g. a 64-bit write
on a 32-bit x86 host is doomed unless KVM goes to extreme lengths.

So, if we want a best effort approach something end up with something like the
(compile-tested-only) below?  As ugly as it is, I think it has my vote, because
it should Just Work for the majority of use cases.

#define ioeventfd_get_val(__ptr, __len, __unsupported_len)	\
({								\
	u64 __val;						\
								\
	switch (len) {						\
	case 1:							\
		__val = get_unaligned((u8 *)__ptr);		\
		break;						\
	case 2:							\
		__val = get_unaligned((u16 *)__ptr);		\
		break;						\
	case 4:							\
		__val = get_unaligned((u32 *)__ptr);		\
		break;						\
	case 8:							\
		__val = get_unaligned((u64 *)__ptr);		\
		break;						\
	default:						\
		goto __unsupported_len;				\
	}							\
	__val;							\
})

static bool
ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val)
{
	if (addr != p->addr)
		/* address must be precise for a hit */
		return false;

	if (!p->length)
		/* length = 0 means only look at the address, so always a hit */
		return true;

	if (len != p->length)
		/* address-range must be precise for a hit */
		return false;

	if (p->wildcard)
		/* all else equal, wildcard is always a hit */
		return true;

	/* otherwise, we have to actually compare the data */
	return ioeventfd_get_val(val, len, unsupported_len) == p->datamatch;

unsupported_len:
	return false;
}

/* MMIO/PIO writes trigger an event if the addr/val match */
static int
ioeventfd_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, gpa_t addr,
		int len, const void *val)
{
	struct _ioeventfd *p = to_ioeventfd(this);

	if (!ioeventfd_in_range(p, addr, len, val))
		return -EOPNOTSUPP;

	if (p->post_addr) {
		u64 _val = ioeventfd_get_val(val, len, unsupported_len);
		int r;

		switch (len) {
		case 1:
			r = put_user(_val, (u8 __user *)p->post_addr);
			break;
		case 2:
			r = put_user(_val, (u16 __user *)p->post_addr);
			break;
		case 4:
			r = put_user(_val, (u32 __user *)p->post_addr);
			break;
		case 8:
			r = put_user(_val, (u64 __user *)p->post_addr);
			break;
		default:
			WARN_ON_ONCE(1);
			r = 0;
			break;
		}
		if (r)
			return r;

	}

unsupported_len:
	eventfd_signal(p->eventfd);
	return 0;
}


  reply	other threads:[~2026-09-22 16:47 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-06 12:56 [PATCH] KVM: optionally post write on ioeventfd write Thanos Makatos
2026-03-12 15:02 ` David Woodhouse
2026-03-12 16:12   ` Thanos Makatos
2026-04-21 14:44     ` Sean Christopherson
2026-09-19 15:59       ` David Woodhouse
2026-03-23 15:01 ` Thanos Makatos
2026-04-10 19:11   ` Thanos Makatos
2026-04-21 14:45     ` Sean Christopherson
2026-06-10  7:31       ` John Levon
2026-09-22 13:51 ` Stefan Hajnoczi
2026-09-22 15:28   ` David Woodhouse
2026-09-22 16:47     ` Sean Christopherson [this message]
2026-10-04 16:16   ` David Woodhouse
2026-10-05  5:11     ` Sean Christopherson
2026-09-22 17:03 ` Sean Christopherson
  -- strict thread matches above, loose matches on Subject: below --
2026-01-13 20:00 [RFC PATCH] KVM: optionally commit " Sean Christopherson
2026-03-02 12:28 ` [PATCH] KVM: optionally post " Thanos Makatos
2026-03-05  1:26   ` Sean Christopherson
2026-03-06 11:14     ` Thanos Makatos
2026-03-05  1:49   ` kernel test robot
2026-03-05  9:39   ` kernel test robot

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=arKxK-L85xIKIvdU@google.com \
    --to=seanjc@google.com \
    --cc=dwmw2@infradead.org \
    --cc=john.levon@nutanix.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=stefanha@redhat.com \
    --cc=thanos.makatos@nutanix.com \
    /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