From: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
To: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Cc: svt-core@virtuozzo.com, den@openvz.org
Subject: Re: [QEMU HCI-8.0 PATCH v2 4/5] vhost-blk: watch the device for resize events
Date: Tue, 8 Sep 2026 02:31:03 +0200 [thread overview]
Message-ID: <da658755-0a22-471a-b306-35a5e4aafd22@virtuozzo.com> (raw)
In-Reply-To: <178853599893.728973.14654758383882924790.b4-review@b4>
On 9/4/26 17:33, Andrey Drobyshev wrote:
>> Resize was tied to block node, which we removed a few patches ago.
>> Luckily we can make resize automated: receive an uevent socket
>> from the management layer via the new "ueventfd" property (e.g. a
>> /dev/fdset/N path), watch it for relevant netlink messages and
>> call virtio_notify_config() if we detect a capacity change.
>>
>> The socket is set up (possibly with filter) by management layer.
>> We only need to check that it is netlink and do some message
>> filtering.
>>
>> When the property is not set, capacity changes are not detected.
>
> So libvirt must ALWAYS set it, and we fail in .realize() if it's not
> set. Correct? Let's mention it.
This is an optional field. If it is not set, nothing happens:
vhost_blk_uevent_attach() returns true and realize goes on.
>
>>
>> https://virtuozzo.atlassian.net/browse/VSTOR-143437
>> Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
>>
>> diff --git a/hw/block/vhost-blk.c b/hw/block/vhost-blk.c
>> index 04a7013e521..7cb842a859e 100644
>> --- a/hw/block/vhost-blk.c
>> +++ b/hw/block/vhost-blk.c
>> @@ -10,7 +10,9 @@
>>
>> #include "qemu/osdep.h"
>> #include "qapi/error.h"
>> +#include "qemu/cutils.h"
>> #include "qemu/error-report.h"
>> +#include "qemu/main-loop.h"
>> #include "qom/object.h"
>> #include "hw/qdev-core.h"
>> #include "hw/boards.h"
>> @@ -25,6 +27,7 @@
>> #include "linux-headers/linux/vhost.h"
>> #include <sys/ioctl.h>
>> #include <linux/fs.h>
>> +#include <linux/netlink.h>
>> #include "system/runstate.h"
>>
>> static int vhost_blk_start(VirtIODevice *vdev)
>> @@ -228,6 +231,173 @@ static int vhost_blk_update_size(VHostBlk *s, bool *changed, Error **errp)
>> return 0;
>> }
>>
>> +static void vhost_blk_resize_bh(void *opaque)
>> +{
>> + VHostBlk *s = opaque;
>> + Error *local_err = NULL;
>> + bool changed;
>> +
>> + if (vhost_blk_update_size(s, &changed, &local_err) < 0) {
>> + error_report_err(local_err);
>> + return;
>> + }
>> +
>> + if (changed) {
>> + virtio_notify_config(VIRTIO_DEVICE(s));
>> + }
>> +}
>> +
>> +/*
>> + * The uevent socket is created, bound and filtered by the management
>> + * layer and passed to us via the "ueventfd" property.
>> + */
>> +static void vhost_blk_uevent_read(void *opaque)
>> +{
>> + VHostBlk *s = opaque;
>> + char buffer[64 * 1024 + 1];
>
> include/linux/kobject.h
> 33:#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
>
> Looks like 64K is overkill, maybe 4K?
>
>> +
>> + for (;;) {
>> + struct sockaddr_nl source;
>> + socklen_t source_len = sizeof(source);
>> + uint64_t event_major = UINT64_MAX;
>> + uint64_t event_minor = UINT64_MAX;
>> + bool action_change = false;
>> + bool subsystem_block = false;
>> + bool resize = false;
>> + char *field;
>> + char *end;
>> + ssize_t len;
>> +
>> + memset(&source, 0, sizeof(source));
>> + len = recvfrom(s->uevent_fd, buffer, sizeof(buffer) - 1,
>> + MSG_DONTWAIT, (struct sockaddr *)&source, &source_len);
>> + if (len < 0) {
>> + if (errno == EINTR) {
>> + continue;
>> + }
>> + if (errno == ENOBUFS) {
>> + /* Some events may be dropped, just re-check */
>> + qemu_bh_schedule(s->resize_bh);
>> + continue;
>> + }
>> + if (errno != EAGAIN && errno != EWOULDBLOCK) {
>
> Should ENOMEM go here to? And if it's an error that breaks the socket,
> like EBADF or smth else - maybe spit the error and detach the handler?
> What's the point of keeping it afterwards?
ENOMEM is expected only for recvmsg.
>
>> + error_report("vhost-blk: unable to receive uevent: %s",
>> + strerror(errno));
>> + }
>> + return;
>> + }
>> +
>> + if (source.nl_family != AF_NETLINK || source.nl_pid != 0) {
>> + continue;
>> + }
>> +
>> + buffer[len] = '\0';
>> + field = buffer;
>> + end = buffer + len;
>> + while (field < end) {
>> + size_t field_len = strnlen(field, end - field);
>> +
>> + if (!strcmp(field, "ACTION=change")) {
>> + action_change = true;
>> + } else if (!strcmp(field, "SUBSYSTEM=block")) {
>> + subsystem_block = true;
>> + } else if (!strcmp(field, "RESIZE=1")) {
>> + resize = true;
>> + } else if (g_str_has_prefix(field, "MAJOR=")) {
>> + uint64_t value;
>> +
>> + if (!qemu_strtou64(field + strlen("MAJOR="), NULL, 10,
>> + &value)) {
>> + event_major = value;
>> + }
>> + } else if (g_str_has_prefix(field, "MINOR=")) {
>> + uint64_t value;
>> +
>> + if (!qemu_strtou64(field + strlen("MINOR="), NULL, 10,
>> + &value)) {
>> + event_minor = value;
>> + }
>> + }
>> +
>> + if (field_len == end - field) {
>> + break;
>> + }
>> + field += field_len + 1;
>> + }
>> +
>> + if (action_change && subsystem_block && resize &&
>> + event_major == major(s->backend_rdev) &&
>> + event_minor == minor(s->backend_rdev)) {
>> + qemu_bh_schedule(s->resize_bh);
>> + }
>> + }
>> +}
>> +
>> +static bool vhost_blk_uevent_check(int fd, const char *src, Error **errp)
>> +{
>> + socklen_t optlen;
>> + int domain;
>> + int protocol;
>> +
>> + optlen = sizeof(domain);
>> + if (getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &domain, &optlen) < 0) {
>> + error_setg_errno(errp, errno, "vhost-blk: '%s' is not a socket", src);
>> + return false;
>> + }
>> +
>> + optlen = sizeof(protocol);
>> + if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &optlen) < 0) {
>> + error_setg_errno(errp, errno,
>> + "vhost-blk: unable to get protocol of '%s'", src);
>> + return false;
>> + }
>> +
>> + if (domain != AF_NETLINK || protocol != NETLINK_KOBJECT_UEVENT) {
>> + error_setg(errp,
>> + "vhost-blk: '%s' is not a NETLINK_KOBJECT_UEVENT socket",
>> + src);
>> + return false;
>> + }
>
> How about also checking nl_groups? Should be 1 for multicast. I.e.
>
> if (getsockname(fd, (struct sockaddr *)&addr, &addrlen) < 0) {
> error_setg_errno(...);
> return false;
> }
> if (addr.nl_groups != 1) {
> error_setg(errp, "vhost-blk: '%s' is not subscribed to kernel uevents",
> src);
> return false;
> }
>
>> +
>> + return true;
>> +}
>> +
>> +static bool vhost_blk_uevent_attach(VHostBlk *s, Error **errp)
>> +{
>> + if (!s->conf.ueventfd) {
>> + return true;
>> + }
>> +
>> + s->uevent_fd = qemu_open(s->conf.ueventfd, O_RDWR, errp);
>
> For conf values monitor_fd_param() is usually used, so how about
>
> s->uevent_fd = monitor_fd_param(monitor_cur(), s->conf.ueventfd, errp);
>
> Andrey
>
next prev parent reply other threads:[~2026-09-08 0:31 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-04 13:21 [QEMU HCI-8.0 PATCH v2 0/5] vhost-blk change backend setup Andrey Zhadchenko
2026-09-04 13:21 ` [QEMU HCI-8.0 PATCH v2 1/5] vhost-blk: do not double close vhostfd Andrey Zhadchenko
2026-09-04 15:33 ` Andrey Drobyshev
2026-09-04 13:21 ` [QEMU HCI-8.0 PATCH v2 2/5] vhost-blk: change backend setup Andrey Zhadchenko
2026-09-04 15:33 ` Andrey Drobyshev
2026-09-04 13:21 ` [QEMU HCI-8.0 PATCH v2 3/5] vhost-blk: add read-only flag Andrey Zhadchenko
2026-09-04 15:33 ` Andrey Drobyshev
2026-09-04 13:21 ` [QEMU HCI-8.0 PATCH v2 4/5] vhost-blk: watch the device for resize events Andrey Zhadchenko
2026-09-04 15:33 ` Andrey Drobyshev
2026-09-08 0:31 ` Andrey Zhadchenko [this message]
2026-09-04 13:21 ` [QEMU HCI-8.0 PATCH v2 5/5] vhost-blk: preserve the uevent socket across cpr-exec Andrey Zhadchenko
2026-09-04 15:33 ` Andrey Drobyshev
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=da658755-0a22-471a-b306-35a5e4aafd22@virtuozzo.com \
--to=andrey.zhadchenko@virtuozzo.com \
--cc=andrey.drobyshev@virtuozzo.com \
--cc=den@openvz.org \
--cc=svt-core@virtuozzo.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