Xen regression fixes and cleanups
From: David Woodhouse <[email protected]>
The following changes since commit 7433709a147706ad7d1956b15669279933d0f82b:
Merge tag 'hw-misc-20250113' of https://github.com/philmd/qemu into staging (2025-01-14 12:46:56 -0500)
are available in the Git repository at:
git://git.infradead.org/users/dwmw2/qemu.git tags/pull-xenfv-20250116
for you to fetch changes up to e7bc0204e57836b3df611b73d2decc56ed698c4a:
system/runstate: Fix regression, clarify BQL status of exit notifiers (2025-01-15 18:05:19 +0000)
----------------------------------------------------------------
Xen regression fixes and cleanups
----------------------------------------------------------------
David Woodhouse (6):
hw/xen: Add xs_node_read() helper function
hw/xen: Use xs_node_read() from xs_node_vscanf()
hw/xen: Use xs_node_read() from xen_console_get_name()
hw/xen: Use xs_node_read() from xen_netdev_get_name()
hw/xen: Use xs_node_read() from xenstore_read_str() instead of open-coding it hw/xen: Fix errp handling in xen_console
Phil Dennis-Jordan (1):
system/runstate: Fix regression, clarify BQL status of exit notifiers
Roger Pau Monné (1):
xen: do not use '%ms' scanf specifier
hw/block/xen-block.c | 3 ++- hw/char/xen_console.c | 56 ++++++++++++++++++++++++----------------- hw/net/xen_nic.c | 13 +++++----- hw/xen/trace-events | 2 +- hw/xen/xen-bus-helper.c | 37 ++++++++++++++++++++------- hw/xen/xen-bus.c | 14 +++++++++-- hw/xen/xen_pvdev.c | 6 ++--- include/hw/xen/xen-bus-helper.h | 9 +++++++ include/hw/xen/xen-bus.h | 1 + include/system/system.h | 1 + system/runstate.c | 1 + 11 files changed, 96 insertions(+), 47 deletions(-)
[PULL 8/8] system/runstate: Fix regression, clarify BQL status of exit notifiers
From: Phil Dennis-Jordan <[email protected]>
By changing the way the main QEMU event loop is invoked, I inadvertently changed the BQL status of exit notifiers: some of them implicitly assumed they would be called with the BQL held; the BQL is however not held during the exit(status) call in qemu_default_main().
Instead of attempting to ensuring we always call exit() from the BQL - including any transitive calls - this change adds a BQL lock guard to qemu_run_exit_notifiers, ensuring the BQL will always be held in the exit notifiers.
Additionally, the BQL promise is now documented at the qemu_{add,remove}_exit_notifier() declarations.
thread event handling")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2771
--- include/system/system.h | 1 + system/runstate.c | 1 + 2 files changed, 2 insertions(+)
include/system/system.h +1 -0
@@ -15,6 +15,7 @@ extern bool qemu_uuid_set;const char *qemu_get_vm_name (void ); +/* Exit notifiers will run with BQL held. */ void qemu_add_exit_notifier (Notifier *notify);void qemu_remove_exit_notifier (Notifier *notify);
system/runstate.c +1 -0
@@ -850,6 +850,7 @@ void qemu_remove_exit_notifier(Notifier *notify)static void qemu_run_exit_notifiers (void ) { +BQL_LOCK_GUARD ();notifier_list_notify (&exit_notifiers,NULL ); }
Signature · 1 line
2.47.0
[PULL 6/8] hw/xen: Use xs_node_read() from xenstore_read_str() instead of open-coding it
In reply to David WoodhouseFrom: David Woodhouse <[email protected]>
--- hw/xen/xen_pvdev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
hw/xen/xen_pvdev.c +2 -4
@@ -22,6 +22,7 @@#include "qemu/main-loop.h" #include "hw/qdev-core.h" #include "hw/xen/xen-legacy-backend.h" +#include "hw/xen/xen-bus-helper.h" #include "hw/xen/xen_pvdev.h" /* private */
@@ -81,12 +82,9 @@ int xenstore_write_str(const char *base, const char *node, const char *val)char *xenstore_read_str (const char *base,const char *node) { -char abspath[XEN_BUFSIZE ]; -unsigned int len;char *str, *ret =NULL ; -snprintf (abspath,sizeof (abspath),"%s/%s" , base, node); - str =qemu_xen_xs_read (xenstore,0 , abspath, &len); + str =xs_node_read (xenstore,0 ,NULL ,NULL ,"%s/%s" , base, node);if (str !=NULL ) {/* move to qemu-allocated memory to make sure * callers can safely g_free() stuff. */
Signature · 1 line
2.47.0
[PULL 7/8] hw/xen: Fix errp handling in xen_console
In reply to David WoodhouseFrom: David Woodhouse <[email protected]>
When attempting to read the 'output' node, interpret any error *other* than ENOENT as a fatal error. For ENOENT, fall back to serial_hd() to find a character device, or create a null device.
Do not attempt to prepend to errp when serial_hd() fails; the error isn't relevant (and prior to this change, wasn't set anyway).
--- hw/char/xen_console.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-)
hw/char/xen_console.c +21 -13
@@ -569,7 +569,7 @@ static void xen_console_device_create(XenBackendInstance *backend,snprintf (label,sizeof (label),"xencons%ld" , number); - output =xs_node_read (xsh,XBT_NULL ,NULL ,NULL ,"%s/%s" , fe,"output" ); + output =xs_node_read (xsh,XBT_NULL ,NULL , errp,"%s/%s" , fe,"output" );if (output) {/* * FIXME: sure we want to support implicit
@@ -581,19 +581,27 @@ static void xen_console_device_create(XenBackendInstance *backend, output); goto fail; } - }else if (number) { - cd =serial_hd (number); -if (!cd) { -error_prepend (errp,"console: No serial device #%ld found: " , - number); - goto fail; - } + }else if (errno !=ENOENT ) { +error_prepend (errp,"console: No valid chardev found: " ); + goto fail; }else { -/* No 'output' node on primary console: use null. */ - cd =qemu_chr_new (label,"null" ,NULL ); -if (!cd) { -error_setg (errp,"console: failed to create null device" ); - goto fail; +error_free (*errp); + *errp =NULL ; + +if (number) { + cd =serial_hd (number); +if (!cd) { +error_setg (errp,"console: No serial device #%ld found" , + number); + goto fail; + } + }else { +/* No 'output' node on primary console: use null. */ + cd =qemu_chr_new (label,"null" ,NULL ); +if (!cd) { +error_setg (errp,"console: failed to create null device" ); + goto fail; + } } }
Signature · 1 line
2.47.0
[PULL 1/8] hw/xen: Add xs_node_read() helper function
In reply to David WoodhouseFrom: David Woodhouse <[email protected]>
This returns the full contents of the node, having created the node path from the printf-style format string provided in its arguments.
This will save various callers from having to do so for themselves (and from using xs_node_scanf() with the non-portable %ms format string.
--- hw/xen/trace-events | 1 + hw/xen/xen-bus-helper.c | 22 ++++++++++++++++++++++ include/hw/xen/xen-bus-helper.h | 9 +++++++++ 3 files changed, 32 insertions(+)
hw/xen/trace-events +1 -0
@@ -39,6 +39,7 @@ xs_node_create(const char *node) "%s" xs_node_destroy(const char *node) "%s" xs_node_vprintf(char *path, char *value) "%s %s" xs_node_vscanf(char *path, char *value) "%s %s" +xs_node_read(const char *path, const char *value) "%s %s" xs_node_watch(char *path) "%s" xs_node_unwatch(char *path) "%s"
hw/xen/xen-bus-helper.c +22 -0
@@ -142,6 +142,28 @@ int xs_node_scanf(struct qemu_xs_handle *h, xs_transaction_t tid,return rc; } +char *xs_node_read (struct qemu_xs_handle *h,xs_transaction_t tid, +unsigned int *len,Error **errp, +const char *path_fmt, ...) +{ +char *path, *value; +va_list ap; + +va_start (ap, path_fmt); + path =g_strdup_vprintf (path_fmt, ap); +va_end (ap); + + value =qemu_xen_xs_read (h, tid, path, len); +trace_xs_node_read (path, value); +if (!value) { +error_setg_errno (errp, errno,"failed to read from '%s'" , path); + } + +g_free (path); + +return value; +} +struct qemu_xs_watch *xs_node_watch (struct qemu_xs_handle *h,const char *node,const char *key,xs_watch_fn fn,void *opaque,Error **errp)
include/hw/xen/xen-bus-helper.h +9 -0
@@ -38,6 +38,15 @@ int xs_node_scanf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *fmt, ...) G_GNUC_SCANF(6, 7); +/* +* Unlike other functions here, the printf-formatted path_fmt is for +* the XenStore path, not the contents of the node. +*/ +char *xs_node_read (struct qemu_xs_handle *h,xs_transaction_t tid, +unsigned int *len,Error **errp, +const char *path_fmt, ...) +G_GNUC_PRINTF (5 ,6 ); +/* Watch node/key unless node is empty, in which case watch key */ struct qemu_xs_watch *xs_node_watch(struct qemu_xs_handle *h, const char *node, const char *key, xs_watch_fn fn,
Signature · 1 line
2.47.0
[PULL 2/8] xen: do not use '%ms' scanf specifier
In reply to David WoodhouseFrom: Roger Pau Monne <[email protected]>
The 'm' parameter used to request auto-allocation of the destination variable is not supported on FreeBSD, and as such leads to failures to parse.
What's more, the current usage of '%ms' with xs_node_scanf() is pointless, as it just leads to a double allocation of the same string. Instead use xs_node_read() to read the whole xenstore node.
--- hw/block/xen-block.c | 3 ++- hw/char/xen_console.c | 6 ++++-- hw/xen/xen-bus.c | 14 ++++++++++++-- include/hw/xen/xen-bus.h | 1 + 4 files changed, 19 insertions(+), 5 deletions(-)
hw/block/xen-block.c +2 -1
@@ -239,7 +239,8 @@ static void xen_block_connect(XenDevice *xendev, Error **errp)return ; } -if (xen_device_frontend_scanf (xendev,"protocol" ,"%ms" , &str) !=1 ) { + str =xen_device_frontend_read (xendev,"protocol" ); +if (!str) {/* x86 defaults to the 32-bit protocol even for 64-bit guests. */ if (object_dynamic_cast (OBJECT (qdev_get_machine ()),"x86-machine" )) { protocol =BLKIF_PROTOCOL_X86_32 ;
hw/char/xen_console.c +4 -2
@@ -550,7 +550,8 @@ static void xen_console_device_create(XenBackendInstance *backend, goto fail; } -if (xs_node_scanf (xsh,XBT_NULL , fe,"type" , errp,"%ms" , &type) !=1 ) { + type =xs_node_read (xsh,XBT_NULL ,NULL , errp,"%s/%s" , fe,"type" ); +if (!type) {error_prepend (errp,"failed to read console device type: " ); goto fail; }
@@ -568,7 +569,8 @@ static void xen_console_device_create(XenBackendInstance *backend,snprintf (label,sizeof (label),"xencons%ld" , number); -if (xs_node_scanf (xsh,XBT_NULL , fe,"output" ,NULL ,"%ms" , &output) ==1 ) { + output =xs_node_read (xsh,XBT_NULL ,NULL ,NULL ,"%s/%s" , fe,"output" ); +if (output) {/* * FIXME: sure we want to support implicit * muxed monitors here?
hw/xen/xen-bus.c +12 -2
@@ -156,8 +156,8 @@ again: !strcmp(key[i], "hotplug-status"))continue ; -if (xs_node_scanf (xenbus->xsh, tid, path, key[i],NULL ,"%ms" , - &val) ==1 ) { + val =xs_node_read (xenbus->xsh, tid,NULL ,NULL ,"%s/%s" , path, key[i]); +if (val) {qdict_put_str (opts, key[i], val);free (val); }
@@ -650,6 +650,16 @@ int xen_device_frontend_scanf(XenDevice *xendev, const char *key,return rc; } +char *xen_device_frontend_read (XenDevice *xendev,const char *key) +{ +XenBus *xenbus =XEN_BUS (qdev_get_parent_bus (DEVICE (xendev))); + +g_assert (xenbus->xsh); + +return xs_node_read (xenbus->xsh,XBT_NULL ,NULL ,NULL ,"%s/%s" , + xendev->frontend_path, key); +} +static void xen_device_frontend_set_state (XenDevice *xendev,enum xenbus_state state,bool publish)
include/hw/xen/xen-bus.h +1 -0
@@ -91,6 +91,7 @@ void xen_device_frontend_printf(XenDevice *xendev, const char *key, int xen_device_frontend_scanf(XenDevice *xendev, const char *key, const char *fmt, ...) G_GNUC_SCANF(3, 4); +char *xen_device_frontend_read (XenDevice *xendev,const char *key);void xen_device_set_max_grant_refs (XenDevice *xendev,unsigned int nr_refs,Error **errp);
Signature · 1 line
2.47.0
[PULL 3/8] hw/xen: Use xs_node_read() from xs_node_vscanf()
In reply to David WoodhouseFrom: David Woodhouse <[email protected]>
Reduce some duplication.
--- hw/xen/trace-events | 1 - hw/xen/xen-bus-helper.c | 15 ++++++--------- 2 files changed, 6 insertions(+), 10 deletions(-)
hw/xen/trace-events +0 -1
@@ -38,7 +38,6 @@ xen_device_remove_watch(const char *type, char *name, const char *node, const ch xs_node_create(const char *node) "%s" xs_node_destroy(const char *node) "%s" xs_node_vprintf(char *path, char *value) "%s %s" -xs_node_vscanf(char *path, char *value) "%s %s" xs_node_read(const char *path, const char *value) "%s %s" xs_node_watch(char *path) "%s" xs_node_unwatch(char *path) "%s"
hw/xen/xen-bus-helper.c +6 -9
@@ -105,25 +105,22 @@ int xs_node_vscanf(struct qemu_xs_handle *h, xs_transaction_t tid, const char *node, const char *key, Error **errp, const char *fmt, va_list ap) { - char *path, *value; + char *value;int rc; - path = (strlen (node) !=0 ) ?g_strdup_printf ("%s/%s" , node, key) : -g_strdup (key); - value =qemu_xen_xs_read (h, tid, path,NULL ); - -trace_xs_node_vscanf (path, value); +if (node &&strlen (node) !=0 ) { + value =xs_node_read (h, tid,NULL , errp,"%s/%s" , node, key); + }else { + value =xs_node_read (h, tid,NULL , errp,"%s" , key); + }if (value) { rc =vsscanf (value, fmt, ap); }else { -error_setg_errno (errp, errno,"failed to read from '%s'" , - path); rc =EOF ; }free (value); -g_free (path);return rc; }
Signature · 1 line
2.47.0
[PULL 5/8] hw/xen: Use xs_node_read() from xen_netdev_get_name()
In reply to David WoodhouseFrom: David Woodhouse <[email protected]>
Now that xs_node_read() can construct a node path, no need to open-code it.
--- hw/net/xen_nic.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
hw/net/xen_nic.c +6 -7
@@ -510,23 +510,22 @@ static char *xen_netdev_get_name(XenDevice *xendev, Error **errp)if (netdev->dev ==-1 ) {XenBus *xenbus =XEN_BUS (qdev_get_parent_bus (DEVICE (xendev))); -char fe_path[XENSTORE_ABS_PATH_MAX +1 ];int idx = (xen_mode ==XEN_EMULATE ) ?0 :1 ; +Error *local_err =NULL ;char *value;/* Theoretically we could go up to INT_MAX here but that's overkill */ while (idx <100 ) { -snprintf (fe_path,sizeof (fe_path), -"/local/domain/%u/device/vif/%u" , - xendev->frontend_id, idx); - value =qemu_xen_xs_read (xenbus->xsh,XBT_NULL , fe_path,NULL ); + value =xs_node_read (xenbus->xsh,XBT_NULL ,NULL , &local_err, +"/local/domain/%u/device/vif/%u" , + xendev->frontend_id, idx);if (!value) {if (errno ==ENOENT ) { netdev->dev = idx; +error_free (local_err); goto found; } -error_setg (errp,"cannot read %s: %s" , fe_path, -strerror (errno)); +error_propagate (errp, local_err);return NULL ; }free (value);
Signature · 1 line
2.47.0
[PULL 4/8] hw/xen: Use xs_node_read() from xen_console_get_name()
In reply to David WoodhouseFrom: David Woodhouse <[email protected]>
Now that xs_node_read() can construct a node path, no need to open-code it.
--- hw/char/xen_console.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
hw/char/xen_console.c +9 -9
@@ -367,28 +367,28 @@ static char *xen_console_get_name(XenDevice *xendev, Error **errp)if (con->dev ==-1 ) {XenBus *xenbus =XEN_BUS (qdev_get_parent_bus (DEVICE (xendev))); -char fe_path[XENSTORE_ABS_PATH_MAX +1 ];int idx = (xen_mode ==XEN_EMULATE ) ?0 :1 ; +Error *local_err =NULL ;char *value;/* Theoretically we could go up to INT_MAX here but that's overkill */ while (idx <100 ) {if (!idx) { -snprintf (fe_path,sizeof (fe_path), -"/local/domain/%u/console" , xendev->frontend_id); + value =xs_node_read (xenbus->xsh,XBT_NULL ,NULL , &local_err, +"/local/domain/%u/console" , + xendev->frontend_id); }else { -snprintf (fe_path,sizeof (fe_path), -"/local/domain/%u/device/console/%u" , - xendev->frontend_id, idx); + value =xs_node_read (xenbus->xsh,XBT_NULL ,NULL , &local_err, +"/local/domain/%u/device/console/%u" , + xendev->frontend_id, idx); } - value =qemu_xen_xs_read (xenbus->xsh,XBT_NULL , fe_path,NULL );if (!value) {if (errno ==ENOENT ) { con->dev = idx; +error_free (local_err); goto found; } -error_setg (errp,"cannot read %s: %s" , fe_path, -strerror (errno)); +error_propagate (errp, local_err);return NULL ; }free (value);
Signature · 1 line
2.47.0
Stefan Hajnoczi
AppliedApplied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/10.0 for any user-visible changes.
Quoted 5 lines · Stefan Hajnoczi
Applied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/10.0 for any user-visible changes.
This note made me realise that my feature addition (macOS PV graphics device) that caused the regression requiring my patch in this series hasn't made it into the changelog. I'd be happy to add it myself, but I don't have a wiki account. How do I get one?
Thanks,
Phil
Quoted 5 lines · Phil Dennis-Jordan
This note made me realise that my feature addition (macOS PV graphics device) that caused the regression requiring my patch in this series hasn't made it into the changelog. I'd be happy to add it myself, but I don't have a wiki account. How do I get one?
I think the automatic account creation and you have to mail someone to get access, but I can't remember whom.
If you want to give me something I can cut/paste, I can add it for you.
Quoted 8 lines · David Woodhouse
Quoted 5 lines · Phil Dennis-Jordan
This note made me realise that my feature addition (macOS PV graphics device) that caused the regression requiring my patch in this series hasn't made it into the changelog. I'd be happy to add it myself, but I don't have a wiki account. How do I get one?
Quoted 4 lines
I think the automatic account creation and you have to mail someone to get access, but I can't remember whom.
If you want to give me something I can cut/paste, I can add it for you.
Any existing wiki user can create a new account for someone:
https://wiki.qemu.org/Special:CreateAccount
I have created an account for Phil and will send him the login details in a private email.
Stefan