PATCH: 0/10: Merge xenfb & xenconsoled into qemu-dm
The following series of 10 patches is a merge of the xenfb and xenconsoled functionality into the qemu-dm code. The general approach taken is to have qemu-dm provide two machine types - one for xen paravirt, the other for fullyvirt. For compatability the later is the default. The goals overall are to kill LibVNCServer, remove alot of code duplication and/or parallel impls of the same concepts, and increase the functionality for PV. In particular this will let paravirt guests take advantage of TLS encryption for the VNC server, and let us configure the text console in all the variety of ways QEMU supports (PTY, File, TCP, TCP_Telnet,UDP, etc).
One interesting possiblity that merging the text & graphics consoles into same daemon allows for, is to expose the pygrub screens over both a PTY and VNC server at the same time. If I can figure out how to actually code this idea it would solve a major headache when using bootloaders with PV guests remotely.
The only feature this re-factoring looses is the ability to have the paravirt text console persistently logged to a file. QEMU allows us to specify that a character device is either sent to a PTY, or a file, but not both at the same time. I'm thinking about ways in which QEMU's character device config syntax & drivers may be extended to allow use of a PTY & File concurrently.
The patches should be applied in order - after each individual patch you should still have a fully operational system for both FV & PV.
Regards,
Dan.
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 1/10: Add a QEMU machine type for fullvirt guests
This patch does a (no functional change) re-arrangement of the code for starting up a fully virtualized guest. In particular it creates a new QEMU machine type for Xen fullyvirt guests which can be specified with '-M xenfv'. For compatability this is in fact made to be the default. The code for setting up memory maps is moved out of vl.c, and into hw/xen_machine_fv.c. This is basically to ensure that it can be easily skipped when we add a paravirt machine type in the next patch.
b/tools/ioemu/hw/xen_machine_fv.c | 286 ++++++++++++++++++++++++++++++++++++++ tools/ioemu/Makefile.target | 1 tools/ioemu/vl.c | 244 -------------------------------- tools/ioemu/vl.h | 3 4 files changed, 295 insertions(+), 239 deletions(-)
Dan.
tools/ioemu/Makefile.target +1 -0
@@ -400,6 +400,7 @@ VL_OBJS+= piix4acpi.o VL_OBJS+= piix4acpi.o VL_OBJS+= xenstore.o VL_OBJS+= xen_platform.o +VL_OBJS+= xen_machine_fv.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif
tools/ioemu/hw/xen_machine_fv.c new file +286 -0
286 lines not on this page · raw message
tools/ioemu/vl.c +5 -239
288 lines not on this page · raw message
tools/ioemu/vl.h +3 -0
@@ -1118,6 +1118,9 @@ extern void pci_piix4_acpi_init(PCIBus */* pc.c */ extern QEMUMachine pc_machine;extern QEMUMachine isapc_machine; +#ifdef CONFIG_DM +extern QEMUMachine xenfv_machine; +#endif extern int fd_bootchk;void ioport_set_a20 (int enable);
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 2/10: Add a QEMU machine type for paravirt guests
In reply to Daniel P. BerrangeThis patch adds a paravirt machine type to QEMU. THis can be requested by passing the arg '-M xenpv' to qemu-dm. Aside from -d, and -domain-name, the only other args that are processed are the VNC / SDL graphics related args. Any others will be ignored. A tweak to helper2.c was made to stop it setting up a file handler watch when there are no CPUs registered.
The paravirt machine is in hw/xen_machine_pv.c and registers an instance of the xenfb class, integrating it with the QEMU event loop and key/mouse handlers. A couple of methods were adding to xenfb.h to allow direct access to the file handles for xenstore & the event channel.
The vfbif.py device controller is modified to launch qemu-dm instead of the old xen-vncfb / sdlfb daemons.
When receiving framebuffer updates from the guest, the update has to be copied into QEMU's copy of the framebuffer. This is because QEMU stores the framebuffer in the format that is native to the SDL display, or VNC client. This is not neccessarily the same as the guest framebuffer which is always 32bpp. If there is an exact depth match we use memcpy for speed, but in the non-matching case we have to fallback to slow code to covert pixel formats. It fully supports all features of the paravirt framebuffer including the choice between absolute & relative pointers.
To avoid both moving the xenfb.c and making changes to it in the same patch, this just uses a Makefile hack to link against the xenfb.o from the tools/xenfb/ directory. This will be removed in the following patch.
b/tools/ioemu/hw/xen_machine_pv.c | 231 ++++++++++++++++++++++++++++++++++ tools/ioemu/Makefile.target | 2 tools/ioemu/target-i386-dm/helper2.c | 5 tools/ioemu/vl.c | 5 tools/ioemu/vl.h | 1 tools/python/xen/xend/server/vfbif.py | 26 +-- tools/xenfb/xenfb.c | 80 ++++++++--- tools/xenfb/xenfb.h | 4 8 files changed, 317 insertions(+), 37 deletions(-)
Dan.
tools/ioemu/Makefile.target +2 -0
@@ -401,6 +401,8 @@ VL_OBJS+= xenstore.o VL_OBJS+= xenstore.o VL_OBJS+= xen_platform.o VL_OBJS+= xen_machine_fv.o +VL_OBJS+= xen_machine_pv.o +VL_OBJS+= ../../xenfb/xenfb.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif
tools/ioemu/hw/xen_machine_pv.c new file +231 -0
231 lines not on this page · raw message
tools/ioemu/target-i386-dm/helper2.c +3 -2
@@ -616,7 +616,7 @@ int main_loop(void)extern int shutdown_requested;extern int suspend_requested;CPUState *env = cpu_single_env; -int evtchn_fd =xc_evtchn_fd (xce_handle); +int evtchn_fd = xce_handle ==-1 ?-1 :xc_evtchn_fd (xce_handle);char qemu_file[PATH_MAX ];fd_set fds;
@@ -624,7 +624,8 @@ int main_loop(void) cpu_single_env);qemu_mod_timer (buffered_io_timer,qemu_get_clock (rt_clock)); -qemu_set_fd_handler (evtchn_fd, cpu_handle_ioreq,NULL , env); +if (evtchn_fd !=-1 ) +qemu_set_fd_handler (evtchn_fd, cpu_handle_ioreq,NULL , env);xenstore_record_dm_state ("running" );while (1 ) {
tools/ioemu/vl.c +3 -2
@@ -182,7 +182,7 @@ extern int vcpus;int xc_handle; -char domain_name[64 ] ="Xen-HVM-no-name" ; +char domain_name[64 ] ="Xen-no-name" ;extern int domid;char vncpasswd[64 ];
@@ -6651,6 +6651,7 @@ void register_machines(void)qemu_register_machine (&isapc_machine);#else qemu_register_machine (&xenfv_machine); +qemu_register_machine (&xenpv_machine);#endif #elif defined(TARGET_PPC)qemu_register_machine (&heathrow_machine);
@@ -7370,7 +7371,7 @@ int main(int argc, char **argv)break ;case QEMU_OPTION_domainname:snprintf (domain_name,sizeof (domain_name), -"Xen-HVM-%s" , optarg); +"Xen-%s" , optarg);break ;case QEMU_OPTION_d: domid =atoi (optarg);
tools/ioemu/vl.h +1 -0
@@ -1120,6 +1120,7 @@ extern QEMUMachine isapc_machine;extern QEMUMachine isapc_machine;#ifdef CONFIG_DM extern QEMUMachine xenfv_machine; +extern QEMUMachine xenpv_machine;#endif extern int fd_bootchk;
tools/python/xen/xend/server/vfbif.py +13 -13
@@ -50,8 +50,10 @@ class VfbifController(DevController): # is HVM, so qemu-dm will handle the vfb. return - std_args = [ "--domid", "%d" % self.vm.getDomid(), - "--title", self.vm.getName() ] + args = [ xen.util.auxbin.pathTo("qemu-dm"), + "-M", "xenpv", + "-d", "%d" % self.vm.getDomid(), + "-domain-name", self.vm.getName() ] t = config.get("type", None) if t == "vnc": passwd = None
@@ -65,15 +67,14 @@ class VfbifController(DevController): else: log.debug("No VNC passwd configured for vfb access") - # Try to start the vnc backend - args = [xen.util.auxbin.pathTo("xen-vncfb")] - if config.has_key("vncunused"): - args += ["--unused"] - elif config.has_key("vncdisplay"): - args += ["--vncport", "%d" % (5900 + int(config["vncdisplay"]))] - vnclisten = config.get("vnclisten", + vnclisten = config.get('vnclisten', xen.xend.XendOptions.instance().get_vnclisten_address()) - args += [ "--listen", vnclisten ] + vncdisplay = config.get('vncdisplay', 0) + args += ['-vnc', "%s:%d" % (vnclisten, vncdisplay)] + + if config.get('vncunused', 0): + args += ['-vncunused'] + if config.has_key("keymap"): args += ["-k", "%s" % config["keymap"]] else:
@@ -81,15 +82,14 @@ class VfbifController(DevController): if xoptions.get_keymap(): args += ["-k", "%s" % xoptions.get_keymap()] - spawn_detached(args[0], args + std_args, os.environ) + spawn_detached(args[0], args, os.environ) elif t == "sdl": - args = [xen.util.auxbin.pathTo("xen-sdlfb")] env = dict(os.environ) if config.has_key("display"): env['DISPLAY'] = config["display"] if config.has_key("xauthority"): env['XAUTHORITY'] = config["xauthority"] - spawn_detached(args[0], args + std_args, env) + spawn_detached(args[0], args, env) else: raise VmError('Unknown vfb type %s (%s)' % (t, repr(config)))
tools/xenfb/xenfb.c +60 -20
106 lines not on this page · raw message
tools/xenfb/xenfb.h +4 -0
@@ -25,8 +25,12 @@ void xenfb_teardown(struct xenfb *xenfb)int xenfb_attach_dom (struct xenfb *xenfb,int domid); +int xenfb_dispatch_store (struct xenfb *xenfb_pub); +int xenfb_dispatch_channel (struct xenfb *xenfb_pub);int xenfb_select_fds (struct xenfb *xenfb,fd_set *readfds);int xenfb_poll (struct xenfb *xenfb,fd_set *readfds); +int xenfb_get_store_fd (struct xenfb *xenfb_pub); +int xenfb_get_channel_fd (struct xenfb *xenfb_pub);int xenfb_send_key (struct xenfb *xenfb,bool down,int keycode);int xenfb_send_motion (struct xenfb *xenfb,int rel_x,int rel_y);
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 3/10: Remove standalone xenfb code
In reply to Daniel P. BerrangeThis patch removes all trace of the standalone paravirt framebuffer daemon. With this there is no longer any requirement for LibVNCServer. Everything is handled by the QEMU device model. The xenfb.c and xenfb.h files are now moved (without code change) into tools/ioemu/hw/ & the temporary Makefile hack from the previous patch is removed.
Config.mk | 1 a/tools/check/check_libvncserver | 38 - a/tools/check/check_sdl | 27 - a/tools/xenfb/Makefile | 32 - a/tools/xenfb/sdlfb.c | 342 ---------------- a/tools/xenfb/vncfb.c | 522 ------------------------ a/tools/xenfb/xenfb.c | 825 --------------------------------------- a/tools/xenfb/xenfb.h | 39 - b/tools/ioemu/hw/xenfb.c | 825 +++++++++++++++++++++++++++++++++++++++ b/tools/ioemu/hw/xenfb.h | 39 + tools/Makefile | 1 tools/check/Makefile | 4 tools/ioemu/Makefile.target | 2 tools/ioemu/hw/xen_machine_pv.c | 2 14 files changed, 868 insertions(+), 1831 deletions(-)
Dan.
Config.mk +0 -1
@@ -85,7 +85,6 @@ XENSTAT_XENTOP ?= y XENSTAT_XENTOP ?= y VTPM_TOOLS ?= n LIBXENAPI_BINDINGS ?= n -XENFB_TOOLS ?= n PYTHON_TOOLS ?= y -include $(XEN_ROOT)/.config
tools/Makefile +0 -1
@@ -19,7 +19,6 @@ SUBDIRS-y += libaio SUBDIRS-y += libaio SUBDIRS-y += blktap SUBDIRS-y += libfsimage -SUBDIRS-$(XENFB_TOOLS) += xenfb SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen # These don't cross-compile
tools/check/Makefile +2 -2
@@ -7,7 +7,7 @@ all: build # Check this machine is OK for building on. .PHONY: build build: - XENFB_TOOLS=$(XENFB_TOOLS) LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk build + LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk build # Check this machine is OK for installing on. # DO NOT use this check from 'make install' in the parent
@@ -15,7 +15,7 @@ build: # copy rather than actually installing. .PHONY: install install: - XENFB_TOOLS=$(XENFB_TOOLS) LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk install + LIBXENAPI_BINDINGS=$(LIBXENAPI_BINDINGS) ./chk install .PHONY: clean clean:
tools/check/check_libvncserver deleted +0 -38
@@ -1,38 +0,0 @@ -#!/bin/sh -# CHECK-BUILD CHECK-INSTALL - -if [ ! "$XENFB_TOOLS" = "y" ] -then - echo -n "unused, " - exit 0 -fi - -RC=0 - -LIBVNCSERVER_CONFIG="$(which libvncserver-config)" -tmpfile=$(mktemp) - -if test -z ${LIBVNCSERVER_CONFIG}; then - RC=1 -else - ${LIBVNCSERVER_CONFIG} --libs 2>&1 > /dev/null - RC=$? -fi - -if test $RC -ne 0; then - echo "FAILED" - echo " *** libvncserver-config is missing. " - echo " *** Please install libvncserver." -elif ! ld $($LIBVNCSERVER_CONFIG --libs) -o $tmpfile >/dev/null 2>&1; then - echo "FAILED" - echo " *** dependency libraries for libvncserver are missing: " - RC=1 - for i in $(ld $($LIBVNCSERVER_CONFIG --libs) -o $tmpfile 2>&1 >/dev/null); do - case $i in - -l*) echo lib${i#-l} - esac - done -fi -rm -f $tmpfile - -exit $RC
tools/check/check_sdl deleted +0 -27
@@ -1,27 +0,0 @@ -#!/bin/sh -# CHECK-BUILD CHECK-INSTALL - -if [ ! "$XENFB_TOOLS" = "y" ] -then - echo -n "unused, " - exit 0 -fi - -RC=0 - -SDL_CONFIG="$(which sdl-config)" - -if test -z ${SDL_CONFIG}; then - RC=1 -else - ${SDL_CONFIG} --libs 2>&1 > /dev/null - RC=$? -fi - -if test $RC -ne 0; then - echo "FAILED" - echo " *** sdl-config is missing. " - echo " *** Please install libsdl-dev or sdl." -fi - -exit $RC
tools/ioemu/Makefile.target +1 -1
@@ -402,7 +402,7 @@ VL_OBJS+= xen_platform.o VL_OBJS+= xen_platform.o VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_pv.o -VL_OBJS+= ../../xenfb/xenfb.o +VL_OBJS+= xenfb.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif
tools/ioemu/hw/xen_machine_pv.c +1 -1
@@ -23,7 +23,7 @@*/ #include "vl.h" -#include "../../xenfb/xenfb.h" +#include "xenfb.h" #include <linux/input.h> /* A convenient function for munging pixels between different depths */
tools/ioemu/hw/xenfb.c new file +825 -0
825 lines not on this page · raw message
tools/ioemu/hw/xenfb.h new file +39 -0
@@ -0,0 +1,39 @@ +#ifndef _XENFB_H_ +#define _XENFB_H_ + +#include <stdbool.h> +#include <sys/types.h> + +struct xenfb +{ +void *pixels; + +int row_stride; +int depth; +int width; +int height; +int abs_pointer_wanted; + +void *user_data; + +void (*update)(struct xenfb *xenfb,int x,int y,int width,int height); +}; + +struct xenfb *xenfb_new (void ); +void xenfb_delete (struct xenfb *xenfb); +void xenfb_teardown (struct xenfb *xenfb); + +int xenfb_attach_dom (struct xenfb *xenfb,int domid); + +int xenfb_dispatch_store (struct xenfb *xenfb_pub); +int xenfb_dispatch_channel (struct xenfb *xenfb_pub); +int xenfb_select_fds (struct xenfb *xenfb,fd_set *readfds); +int xenfb_poll (struct xenfb *xenfb,fd_set *readfds); +int xenfb_get_store_fd (struct xenfb *xenfb_pub); +int xenfb_get_channel_fd (struct xenfb *xenfb_pub); + +int xenfb_send_key (struct xenfb *xenfb,bool down,int keycode); +int xenfb_send_motion (struct xenfb *xenfb,int rel_x,int rel_y); +int xenfb_send_position (struct xenfb *xenfb,int abs_x,int abs_y); + +#endif
tools/xenfb/Makefile deleted +0 -32
@@ -1,32 +0,0 @@ -XEN_ROOT=../.. -include $(XEN_ROOT)/tools/Rules.mk - -CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) -CFLAGS += -I$(XEN_ROOT)/tools/ioemu -LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE) - -.PHONY: all -all: build - -.PHONY: build -build: - $(MAKE) vncfb sdlfb - -install: all - $(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)/xen/bin - $(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb - $(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb - -sdlfb: sdlfb.o xenfb.o - -sdlfb.o: CFLAGS += $(shell sdl-config --cflags) -sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore - -clean: - $(RM) *.o *~ vncfb sdlfb - -vncfb: vncfb.o xenfb.o -vncfb.o: CFLAGS += $(shell libvncserver-config --cflags) -vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore - -sdlfb.o xenfb.o vncfb.o: xenfb.h
tools/xenfb/sdlfb.c deleted +0 -342
342 lines not on this page · raw message
tools/xenfb/vncfb.c deleted +0 -522
522 lines not on this page · raw message
tools/xenfb/xenfb.c deleted +0 -825
825 lines not on this page · raw message
tools/xenfb/xenfb.h deleted +0 -39
@@ -1,39 +0,0 @@ -#ifndef _XENFB_H_ -#define _XENFB_H_ - -#include <stdbool.h> -#include <sys/types.h> - -struct xenfb -{ -void *pixels; - -int row_stride; -int depth; -int width; -int height; -int abs_pointer_wanted; - -void *user_data; - -void (*update)(struct xenfb *xenfb,int x,int y,int width,int height); -}; - -struct xenfb *xenfb_new (void ); -void xenfb_delete (struct xenfb *xenfb); -void xenfb_teardown (struct xenfb *xenfb); - -int xenfb_attach_dom (struct xenfb *xenfb,int domid); - -int xenfb_dispatch_store (struct xenfb *xenfb_pub); -int xenfb_dispatch_channel (struct xenfb *xenfb_pub); -int xenfb_select_fds (struct xenfb *xenfb,fd_set *readfds); -int xenfb_poll (struct xenfb *xenfb,fd_set *readfds); -int xenfb_get_store_fd (struct xenfb *xenfb_pub); -int xenfb_get_channel_fd (struct xenfb *xenfb_pub); - -int xenfb_send_key (struct xenfb *xenfb,bool down,int keycode); -int xenfb_send_motion (struct xenfb *xenfb,int rel_x,int rel_y); -int xenfb_send_position (struct xenfb *xenfb,int abs_x,int abs_y); - -#endif
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 4/10: Refactor xenfb event handlers
In reply to Daniel P. BerrangeThis patch is a simple code re-factoring to move the event loop integration directly into the xenfb.c file. It is to facilitate the patches which follow.
xen_machine_pv.c | 29 ------ xenfb.c | 249 +++++++++++++++++++++++-------------------------------- xenfb.h | 7 - 3 files changed, 106 insertions(+), 179 deletions(-)
Dan.
tools/ioemu/hw/xen_machine_pv.c +0 -29
@@ -136,21 +136,6 @@ void xen_pvfb_invalidate(void *opaque)/* Screen dump is not used in Xen, so no need to impl this ? */ void xen_pvfb_screen_dump (void *opaque,const char *name) { } -void xen_pvfb_dispatch_store (void *opaque) { -int ret; -if ((ret =xenfb_dispatch_store ((struct xenfb *)opaque)) <0 ) { -fprintf (stderr,"Failure while dispatching store: %d\n" , ret); -exit (1 ); - } -} - -void xen_pvfb_dispatch_channel (void *opaque) { -int ret; -if ((ret =xenfb_dispatch_channel ((struct xenfb *)opaque)) <0 ) { -fprintf (stderr,"Failure while dispatching store: %d\n" , ret); -exit (1 ); - } -}/* The Xen PV machine currently provides * - a virtual framebuffer
@@ -165,7 +150,6 @@ static void xen_init_pv(uint64_t ram_siz {struct xenfb *xenfb;extern int domid; -int fd;/* Prepare PVFB state */ xenfb =xenfb_new ();
@@ -197,19 +181,6 @@ static void xen_init_pv(uint64_t ram_siz xenfb->abs_pointer_wanted, "Xen PVFB Mouse"); -/* Listen for events from xenstore */ - fd =xenfb_get_store_fd (xenfb); -if (qemu_set_fd_handler2 (fd,NULL , xen_pvfb_dispatch_store,NULL , xenfb) <0 ) { -fprintf (stderr,"Could not register event handler (%s)\n" , -strerror (errno)); - } - -/* Listen for events from the event channel */ - fd =xenfb_get_channel_fd (xenfb); -if (qemu_set_fd_handler2 (fd,NULL , xen_pvfb_dispatch_channel,NULL , xenfb) <0 ) { -fprintf (stderr,"Could not register event handler (%s)\n" , -strerror (errno)); - }/* Setup QEMU display */ dpy_resize (ds, xenfb->width, xenfb->height);
tools/ioemu/hw/xenfb.c +106 -143
292 lines not on this page · raw message
tools/ioemu/hw/xenfb.h +0 -7
@@ -25,13 +25,6 @@ void xenfb_teardown(struct xenfb *xenfb)int xenfb_attach_dom (struct xenfb *xenfb,int domid); -int xenfb_dispatch_store (struct xenfb *xenfb_pub); -int xenfb_dispatch_channel (struct xenfb *xenfb_pub); -int xenfb_select_fds (struct xenfb *xenfb,fd_set *readfds); -int xenfb_poll (struct xenfb *xenfb,fd_set *readfds); -int xenfb_get_store_fd (struct xenfb *xenfb_pub); -int xenfb_get_channel_fd (struct xenfb *xenfb_pub); -int xenfb_send_key (struct xenfb *xenfb,bool down,int keycode);int xenfb_send_motion (struct xenfb *xenfb,int rel_x,int rel_y);int xenfb_send_position (struct xenfb *xenfb,int abs_x,int abs_y);
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 5/10: Refactor QEMU console integration
In reply to Daniel P. BerrangeThis patch moves a bunch of code out of the xen_machine_pv.c file and into the xenfb.c file. This is simply a re-factoring to facilitate the two patches which follow.
xen_machine_pv.c | 132 ---------------------------- xenfb.c | 254 +++++++++++++++++++++++++++++++++++++++++-------------- xenfb.h | 8 - 3 files changed, 195 insertions(+), 199 deletions(-)
Dan.
tools/ioemu/hw/xen_machine_pv.c +1 -131
@@ -24,117 +24,6 @@#include "vl.h" #include "xenfb.h" -#include <linux/input.h> - -/* A convenient function for munging pixels between different depths */ -#define BLT (SRC_T ,DST_T ,RLS ,GLS ,BLS ,RRS ,GRS ,BRS ,RM ,GM ,BM ) \ - for (line = y ; line < h ; line++) { \ - SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ - DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ - int col; \ - for (col = x ; col < w ; col++) { \ - *dst = (((*src >> RRS)&RM) << RLS) | \ - (((*src >> GRS)&GM) << GLS) | \ - (((*src >> GRS)&BM) << BLS); \ - src++; \ - dst++; \ - } \ - } - - -/* This copies data from the guest framebuffer region, into QEMU's copy -* NB. QEMU's copy is stored in the pixel format of a) the local X server (SDL case) -* or b) the current VNC client pixel format. -*/ -static void xen_pvfb_guest_copy (struct xenfb *xenfb,int x,int y,int w,int h) -{ -DisplayState *ds = (DisplayState *)xenfb->user_data; -int line; - -if (xenfb->depth == ds->depth) {/* Perfect match can use fast path */ -for (line = y ; line < (y+h) ; line++) { -memcpy (ds->data + (line * ds->linesize) + (x*ds->depth/8 ), - xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8 ), - w * xenfb->depth/8 ); - } - }else {/* Mismatch requires slow pixel munging */ -if (xenfb->depth ==8 ) { -/* 8 bit source == r:3 g:3 b:2 */ -if (ds->depth ==16 ) { -BLT (uint8_t, uint16_t,5 ,2 ,0 ,11 ,5 ,0 ,7 ,7 ,3 ); - }else if (ds->depth ==32 ) { -BLT (uint8_t, uint32_t,5 ,2 ,0 ,16 ,8 ,0 ,7 ,7 ,3 ); - } - }else if (xenfb->depth ==16 ) { -/* 16 bit source == r:5 g:6 b:5 */ -if (ds->depth ==8 ) { -BLT (uint16_t, uint8_t,11 ,5 ,0 ,5 ,2 ,0 ,31 ,63 ,31 ); - }else if (ds->depth ==32 ) { -BLT (uint16_t, uint32_t,11 ,5 ,0 ,16 ,8 ,0 ,31 ,63 ,31 ); - } - }else if (xenfb->depth ==32 ) { -/* 32 bit source == r:8 g:8 b:8 (padding:8) */ -if (ds->depth ==8 ) { -BLT (uint32_t, uint8_t,16 ,8 ,0 ,5 ,2 ,0 ,255 ,255 ,255 ); - }else if (ds->depth ==16 ) { -BLT (uint32_t, uint16_t,16 ,8 ,0 ,11 ,5 ,0 ,255 ,255 ,255 ); - } - } - } -dpy_update (ds, x, y, w, h); -} - - -/* Send a keypress from the client to the guest OS */ -static void xen_pvfb_put_keycode (void *opaque,int keycode) -{ -struct xenfb *xenfb = (struct xenfb *)opaque; -xenfb_send_key (xenfb, keycode &0x80 ?0 :1 , keycode &0x7f ); -} - -/* Send a mouse event from the client to the guest OS */ -static void xen_pvfb_mouse_event (void *opaque, -int dx,int dy,int dz,int button_state) -{ -static int old_state =0 ; -int i; -struct xenfb *xenfb = (struct xenfb *)opaque; -DisplayState *ds = (DisplayState *)xenfb->user_data; -if (xenfb->abs_pointer_wanted) -xenfb_send_position (xenfb, - dx*ds->width/0x7fff , - dy*ds->height/0x7fff ); -else -xenfb_send_motion (xenfb, dx, dy); - -for (i =0 ; i <8 ; i++) { -int lastDown = old_state & (1 << i); -int down = button_state & (1 << i); -if (down == lastDown) -continue ; - -if (xenfb_send_key (xenfb, down,BTN_LEFT +i) <0 ) -return ; - } - old_state = button_state; -} - -/* QEMU display state changed, so refresh the framebuffer copy */ -void xen_pvfb_update (void *opaque) -{ -struct xenfb *xenfb = (struct xenfb *)opaque; -xen_pvfb_guest_copy (xenfb,0 ,0 , xenfb->width, xenfb->height); -} - -/* QEMU display state changed, so refresh the framebuffer copy */ -void xen_pvfb_invalidate (void *opaque) -{ -struct xenfb *xenfb = (struct xenfb *)opaque; -xen_pvfb_guest_copy (xenfb,0 ,0 , xenfb->width, xenfb->height); -} - -/* Screen dump is not used in Xen, so no need to impl this ? */ -void xen_pvfb_screen_dump (void *opaque,const char *name) { }/* The Xen PV machine currently provides
@@ -160,30 +49,11 @@ static void xen_init_pv(uint64_t ram_siz }/* Talk to the guest */ -if (xenfb_attach_dom (xenfb, domid) <0 ) { +if (xenfb_attach_dom (xenfb, domid, ds) <0 ) {fprintf (stderr,"Could not connect to domain (%s)\n" ,strerror (errno));exit (1 ); } - xenfb->update = xen_pvfb_guest_copy; - xenfb->user_data = ds; - -/* Tell QEMU to allocate a graphical console */ -graphic_console_init (ds, - xen_pvfb_update, - xen_pvfb_invalidate, - xen_pvfb_screen_dump, - xenfb); - -/* Register our keyboard & mouse handlers */ -qemu_add_kbd_event_handler (xen_pvfb_put_keycode, xenfb); -qemu_add_mouse_event_handler (xen_pvfb_mouse_event, xenfb, - xenfb->abs_pointer_wanted, -"Xen PVFB Mouse" ); - - -/* Setup QEMU display */ -dpy_resize (ds, xenfb->width, xenfb->height); }QEMUMachine xenpv_machine = {
tools/ioemu/hw/xenfb.c +191 -63
284 lines not on this page · raw message
tools/ioemu/hw/xenfb.h +3 -5
@@ -1,6 +1,7 @@#ifndef _XENFB_H_#define _XENFB_H_ +#include "vl.h" #include <stdbool.h> #include <sys/types.h>
@@ -13,6 +14,7 @@ struct xenfbint width;int height;int abs_pointer_wanted; +int button_state;void *user_data;
@@ -23,10 +25,6 @@ void xenfb_delete(struct xenfb *xenfb);void xenfb_delete (struct xenfb *xenfb);void xenfb_teardown (struct xenfb *xenfb); -int xenfb_attach_dom (struct xenfb *xenfb,int domid); - -int xenfb_send_key (struct xenfb *xenfb,bool down,int keycode); -int xenfb_send_motion (struct xenfb *xenfb,int rel_x,int rel_y); -int xenfb_send_position (struct xenfb *xenfb,int abs_x,int abs_y); +int xenfb_attach_dom (struct xenfb *xenfb,int domid,DisplayState *ds);#endif
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 6/10: Merge private & public xenfb structs
In reply to Daniel P. BerrangeThis patch merges the public & private structs from the paravirt FB into a single struct. Since QEMU is the only consumer of this code there is no need for the artifical pub/priv split. Merging the two will make it possible to more tightly integrate with QEMU's event loop and do asynchronous non-blocking negoiation with the frontend devices (see next patch).
xenfb.c | 273 ++++++++++++++++++++++++++++++++-------------------------------- xenfb.h | 16 --- 2 files changed, 139 insertions(+), 150 deletions(-)
Dan.
tools/ioemu/hw/xenfb.c +138 -135
@@ -22,6 +22,8 @@// FIXME defend against malicious frontend? +struct xenfb ; +struct xenfb_device {const char *devicetype;char nodename[64 ];/* backend xenstore dir */
@@ -30,20 +32,33 @@ struct xenfb_device {enum xenbus_state state;/* backend state */ void *page;/* shared page */ evtchn_port_t port; -struct xenfb_private *xenfb; +struct xenfb *xenfb; }; -struct xenfb_private { -struct xenfb pub; +struct xenfb_data +{ +void *pixels; +size_t len; + +int row_stride; +int depth; +int width; +int height; +int abs_pointer_wanted; +}; + +struct xenfb { +DisplayState *ds;int evt_xch;/* event channel driver handle */ int xc;/* hypervisor interface handle */ struct xs_handle *xsh;/* xs daemon handle */ struct xenfb_device fb, kbd; -size_t fb_len;/* size of framebuffer */ +struct xenfb_data data;char protocol[64 ];/* frontend protocol */ +int button_state; }; -static void xenfb_detach_dom (struct xenfb_private *); +static void xenfb_detach_dom (struct xenfb *); static char *xenfb_path_in_dom(struct xs_handle *xsh, char *buf, size_t size,
@@ -124,7 +139,7 @@ static int xenfb_xs_printf(struct xs_hanstatic void xenfb_device_init (struct xenfb_device *dev,const char *type, -struct xenfb_private *xenfb) +struct xenfb *xenfb) { dev->devicetype = type; dev->otherend_id =-1 ;
@@ -132,19 +147,17 @@ static void xenfb_device_init(struct xen dev->xenfb = xenfb; } -int xenfb_device_set_domain (struct xenfb_device *dev,int domid) -{ -struct xenfb_private *xenfb = dev->xenfb; - +static int xenfb_device_set_domain (struct xenfb_device *dev,int domid) +{ dev->otherend_id = domid; -if (!xenfb_path_in_dom (xenfb->xsh, +if (!xenfb_path_in_dom (dev->xenfb->xsh, dev->otherend,sizeof (dev->otherend), domid,"device/%s/0" , dev->devicetype)) { errno =ENOENT ;return -1 ; } -if (!xenfb_path_in_dom (xenfb->xsh, +if (!xenfb_path_in_dom (dev->xenfb->xsh, dev->nodename,sizeof (dev->nodename),0 ,"backend/%s/%d/0" , dev->devicetype, domid)) { errno =ENOENT ;
@@ -156,8 +169,8 @@ int xenfb_device_set_domain(struct xenfbstruct xenfb *xenfb_new (void ) { -struct xenfb_private *xenfb =malloc (sizeof (*xenfb));int serrno; +struct xenfb *xenfb =qemu_malloc (sizeof (struct xenfb ));if (xenfb ==NULL )return NULL ;
@@ -179,30 +192,26 @@ struct xenfb *xenfb_new(void)if (!xenfb->xsh) goto fail; -return &xenfb->pub; +return xenfb; fail: serrno = errno; -xenfb_delete (&xenfb->pub); +xenfb_delete (xenfb); errno = serrno;return NULL ; }/* Remove the backend area in xenbus since the framebuffer really is going away. */ -void xenfb_teardown (struct xenfb *xenfb_pub) -{ -struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - +void xenfb_teardown (struct xenfb *xenfb) +{xs_rm (xenfb->xsh,XBT_NULL , xenfb->fb.nodename);xs_rm (xenfb->xsh,XBT_NULL , xenfb->kbd.nodename); } -void xenfb_delete (struct xenfb *xenfb_pub) -{ -struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - +void xenfb_delete (struct xenfb *xenfb) +{xenfb_detach_dom (xenfb);if (xenfb->xc >=0 )xc_interface_close (xenfb->xc);
@@ -334,7 +343,7 @@ static void xenfb_copy_mfns(int mode, in dst[i] = (mode ==32 ) ? src32[i] : src64[i]; } -static int xenfb_map_fb (struct xenfb_private *xenfb,int domid) +static int xenfb_map_fb (struct xenfb *xenfb,int domid) {struct xenfb_page *page = xenfb->fb.page;int n_fbmfns;
@@ -389,7 +398,7 @@ static int xenfb_map_fb(struct xenfb_pri#endif } - n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE -1 )) /XC_PAGE_SIZE ; + n_fbmfns = (xenfb->data.len + (XC_PAGE_SIZE -1 )) /XC_PAGE_SIZE ; n_fbdirs = n_fbmfns * mode /8 ; n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE -1 )) /XC_PAGE_SIZE ;
@@ -412,9 +421,9 @@ static int xenfb_map_fb(struct xenfb_prixenfb_copy_mfns (mode, n_fbmfns, fbmfns, map);munmap (map, n_fbdirs *XC_PAGE_SIZE ); - xenfb->pub.pixels =xc_map_foreign_batch (xenfb->xc, domid, + xenfb->data.pixels =xc_map_foreign_batch (xenfb->xc, domid,PROT_READ |PROT_WRITE , fbmfns, n_fbmfns); -if (xenfb->pub.pixels ==NULL ) +if (xenfb->data.pixels ==NULL ) goto out; ret =0 ;/* all is fine */
@@ -429,7 +438,7 @@ static int xenfb_map_fb(struct xenfb_pristatic int xenfb_bind (struct xenfb_device *dev) { -struct xenfb_private *xenfb = dev->xenfb; +struct xenfb *xenfb = dev->xenfb;unsigned long mfn;evtchn_port_t evtchn;
@@ -512,17 +521,74 @@ static void xenfb_dev_fatal(struct xenfb } -static void xenfb_detach_dom (struct xenfb_private *xenfb) +static void xenfb_detach_dom (struct xenfb *xenfb) {xenfb_unbind (&xenfb->fb);xenfb_unbind (&xenfb->kbd); -if (xenfb->pub.pixels) { -munmap (xenfb->pub.pixels, xenfb->fb_len); - xenfb->pub.pixels =NULL ; - } -} - -static void xenfb_on_fb_event (struct xenfb_private *xenfb) +if (xenfb->data.pixels) { +munmap (xenfb->data.pixels, xenfb->data.len); + xenfb->data.pixels =NULL ; + } +} + +/* A convenient function for munging pixels between different depths */ +#define BLT (SRC_T ,DST_T ,RLS ,GLS ,BLS ,RRS ,GRS ,BRS ,RM ,GM ,BM ) \ + for (line = y ; line < h ; line++) { \ + SRC_T *src = (SRC_T *)(xenfb->data.pixels + (line*xenfb->data.row_stride) + (x*xenfb->data.depth/8)); \ + DST_T *dst = (DST_T *)(xenfb->ds->data + (line*xenfb->ds->linesize) + (x*xenfb->ds->depth/8)); \ + int col; \ + for (col = x ; col < w ; col++) { \ + *dst = (((*src >> RRS)&RM) << RLS) | \ + (((*src >> GRS)&GM) << GLS) | \ + (((*src >> GRS)&BM) << BLS); \ + src++; \ + dst++; \ + } \ + } + + +/* This copies data from the guest framebuffer region, into QEMU's copy +* NB. QEMU's copy is stored in the pixel format of a) the local X server (SDL case) +* or b) the current VNC client pixel format. +*/ +static void xenfb_guest_copy (struct xenfb *xenfb,int x,int y,int w,int h) +{ +int line; + +if (xenfb->data.depth == xenfb->ds->depth) {/* Perfect match can use fast path */ +for (line = y ; line < (y+h) ; line++) { +memcpy (xenfb->ds->data + (line * xenfb->ds->linesize) + (x*xenfb->ds->depth/8 ), + xenfb->data.pixels + (line*xenfb->data.row_stride) + (x*xenfb->data.depth/8 ), + w * xenfb->data.depth/8 ); + } + }else {/* Mismatch requires slow pixel munging */ +if (xenfb->data.depth ==8 ) { +/* 8 bit source == r:3 g:3 b:2 */ +if (xenfb->ds->depth ==16 ) { +BLT (uint8_t, uint16_t,5 ,2 ,0 ,11 ,5 ,0 ,7 ,7 ,3 ); + }else if (xenfb->ds->depth ==32 ) { +BLT (uint8_t, uint32_t,5 ,2 ,0 ,16 ,8 ,0 ,7 ,7 ,3 ); + } + }else if (xenfb->data.depth ==16 ) { +/* 16 bit source == r:5 g:6 b:5 */ +if (xenfb->ds->depth ==8 ) { +BLT (uint16_t, uint8_t,11 ,5 ,0 ,5 ,2 ,0 ,31 ,63 ,31 ); + }else if (xenfb->ds->depth ==32 ) { +BLT (uint16_t, uint32_t,11 ,5 ,0 ,16 ,8 ,0 ,31 ,63 ,31 ); + } + }else if (xenfb->data.depth ==32 ) { +/* 32 bit source == r:8 g:8 b:8 (padding:8) */ +if (xenfb->ds->depth ==8 ) { +BLT (uint32_t, uint8_t,16 ,8 ,0 ,5 ,2 ,0 ,255 ,255 ,255 ); + }else if (xenfb->ds->depth ==16 ) { +BLT (uint32_t, uint16_t,16 ,8 ,0 ,11 ,5 ,0 ,255 ,255 ,255 ); + } + } + } +dpy_update (xenfb->ds, x, y, w, h); +} + +static void xenfb_on_fb_event (struct xenfb *xenfb) {uint32_t prod, cons;struct xenfb_page *page = xenfb->fb.page;
@@ -536,11 +602,10 @@ static void xenfb_on_fb_event(struct xenswitch (event->type) {case XENFB_TYPE_UPDATE : -if (xenfb->pub.update) - xenfb->pub.update (&xenfb->pub, - event->update.x, event->update.y, - event->update.width, event->update.height); -break ; +xenfb_guest_copy (xenfb, + event->update.x, event->update.y, + event->update.width, event->update.height); +break ; } }mb ();/* ensure we're done with ring contents */
@@ -548,7 +613,7 @@ static void xenfb_on_fb_event(struct xenxc_evtchn_notify (xenfb->evt_xch, xenfb->fb.port); } -static void xenfb_on_kbd_event (struct xenfb_private *xenfb) +static void xenfb_on_kbd_event (struct xenfb *xenfb) {struct xenkbd_page *page = xenfb->kbd.page;
@@ -586,7 +651,7 @@ static int xenfb_on_state_change(structreturn 0 ; } -static int xenfb_kbd_event (struct xenfb_private *xenfb, +static int xenfb_kbd_event (struct xenfb *xenfb,union xenkbd_in_event *event) {uint32_t prod;
@@ -608,9 +673,8 @@ static int xenfb_kbd_event(struct xenfb_return xc_evtchn_notify (xenfb->evt_xch, xenfb->kbd.port); } -static int xenfb_send_key (struct xenfb *xenfb_pub,bool down,int keycode) -{ -struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_key (struct xenfb *xenfb,bool down,int keycode) +{union xenkbd_in_event event;memset (&event,0 ,XENKBD_IN_EVENT_SIZE );
@@ -621,9 +685,8 @@ static int xenfb_send_key(struct xenfb *return xenfb_kbd_event (xenfb, &event); } -static int xenfb_send_motion (struct xenfb *xenfb_pub,int rel_x,int rel_y) -{ -struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_motion (struct xenfb *xenfb,int rel_x,int rel_y) +{union xenkbd_in_event event;memset (&event,0 ,XENKBD_IN_EVENT_SIZE );
@@ -634,9 +697,8 @@ static int xenfb_send_motion(struct xenfreturn xenfb_kbd_event (xenfb, &event); } -static int xenfb_send_position (struct xenfb *xenfb_pub,int abs_x,int abs_y) -{ -struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static int xenfb_send_position (struct xenfb *xenfb,int abs_x,int abs_y) +{union xenkbd_in_event event;memset (&event,0 ,XENKBD_IN_EVENT_SIZE );
@@ -660,11 +722,11 @@ static void xenfb_mouse_event(void *opaq {int i;struct xenfb *xenfb = (struct xenfb *)opaque; -DisplayState *ds = (DisplayState *)xenfb->user_data; -if (xenfb->abs_pointer_wanted) + +if (xenfb->data.abs_pointer_wanted)xenfb_send_position (xenfb, - dx*ds->width/0x7fff , - dy*ds->height/0x7fff ); + dx*xenfb->ds->width/0x7fff , + dy*xenfb->ds->height/0x7fff );else xenfb_send_motion (xenfb, dx, dy);
@@ -680,76 +742,19 @@ static void xenfb_mouse_event(void *opaq xenfb->button_state = button_state; } -/* A convenient function for munging pixels between different depths */ -#define BLT (SRC_T ,DST_T ,RLS ,GLS ,BLS ,RRS ,GRS ,BRS ,RM ,GM ,BM ) \ - for (line = y ; line < h ; line++) { \ - SRC_T *src = (SRC_T *)(xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8)); \ - DST_T *dst = (DST_T *)(ds->data + (line*ds->linesize) + (x*ds->depth/8)); \ - int col; \ - for (col = x ; col < w ; col++) { \ - *dst = (((*src >> RRS)&RM) << RLS) | \ - (((*src >> GRS)&GM) << GLS) | \ - (((*src >> GRS)&BM) << BLS); \ - src++; \ - dst++; \ - } \ - } - - -/* This copies data from the guest framebuffer region, into QEMU's copy -* NB. QEMU's copy is stored in the pixel format of a) the local X server (SDL case) -* or b) the current VNC client pixel format. -*/ -static void xenfb_guest_copy (struct xenfb *xenfb,int x,int y,int w,int h) -{ -DisplayState *ds = (DisplayState *)xenfb->user_data; -int line; - -if (xenfb->depth == ds->depth) {/* Perfect match can use fast path */ -for (line = y ; line < (y+h) ; line++) { -memcpy (ds->data + (line * ds->linesize) + (x*ds->depth/8 ), - xenfb->pixels + (line*xenfb->row_stride) + (x*xenfb->depth/8 ), - w * xenfb->depth/8 ); - } - }else {/* Mismatch requires slow pixel munging */ -if (xenfb->depth ==8 ) { -/* 8 bit source == r:3 g:3 b:2 */ -if (ds->depth ==16 ) { -BLT (uint8_t, uint16_t,5 ,2 ,0 ,11 ,5 ,0 ,7 ,7 ,3 ); - }else if (ds->depth ==32 ) { -BLT (uint8_t, uint32_t,5 ,2 ,0 ,16 ,8 ,0 ,7 ,7 ,3 ); - } - }else if (xenfb->depth ==16 ) { -/* 16 bit source == r:5 g:6 b:5 */ -if (ds->depth ==8 ) { -BLT (uint16_t, uint8_t,11 ,5 ,0 ,5 ,2 ,0 ,31 ,63 ,31 ); - }else if (ds->depth ==32 ) { -BLT (uint16_t, uint32_t,11 ,5 ,0 ,16 ,8 ,0 ,31 ,63 ,31 ); - } - }else if (xenfb->depth ==32 ) { -/* 32 bit source == r:8 g:8 b:8 (padding:8) */ -if (ds->depth ==8 ) { -BLT (uint32_t, uint8_t,16 ,8 ,0 ,5 ,2 ,0 ,255 ,255 ,255 ); - }else if (ds->depth ==16 ) { -BLT (uint32_t, uint16_t,16 ,8 ,0 ,11 ,5 ,0 ,255 ,255 ,255 ); - } - } - } -dpy_update (ds, x, y, w, h); -}/* QEMU display state changed, so refresh the framebuffer copy */ static void xenfb_update (void *opaque) {struct xenfb *xenfb = (struct xenfb *)opaque; -xenfb_guest_copy (xenfb,0 ,0 , xenfb->width, xenfb->height); +xenfb_guest_copy (xenfb,0 ,0 , xenfb->data.width, xenfb->data.height); }/* QEMU display state changed, so refresh the framebuffer copy */ static void xenfb_invalidate (void *opaque) {struct xenfb *xenfb = (struct xenfb *)opaque; -xenfb_guest_copy (xenfb,0 ,0 , xenfb->width, xenfb->height); +xenfb_guest_copy (xenfb,0 ,0 , xenfb->data.width, xenfb->data.height); }/* Screen dump is not used in Xen, so no need to impl this ? */
@@ -757,9 +762,9 @@ static void xenfb_screen_dump(void *opaq -static void xenfb_dispatch_channel (void *xenfb_pub) -{ -struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static void xenfb_dispatch_channel (void *opaque) +{ +struct xenfb *xenfb = (struct xenfb *)opaque;evtchn_port_t port; port =xc_evtchn_pending (xenfb->evt_xch);if (port ==-1 )
@@ -774,9 +779,9 @@ static void xenfb_dispatch_channel(voidexit (1 ); } -static void xenfb_dispatch_store (void *xenfb_pub) -{ -struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +static void xenfb_dispatch_store (void *opaque) +{ +struct xenfb *xenfb = (struct xenfb *)opaque;unsigned dummy;char **vec;int r;
@@ -791,9 +796,8 @@ static void xenfb_dispatch_store(void *x } -int xenfb_attach_dom (struct xenfb *xenfb_pub,int domid,DisplayState *ds) -{ -struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; +int xenfb_attach_dom (struct xenfb *xenfb,int domid,DisplayState *ds) +{struct xs_handle *xsh = xenfb->xsh;int val, serrno;struct xenfb_page *fb_page;
@@ -849,12 +853,12 @@ int xenfb_attach_dom(struct xenfb *xenfb/* TODO check for permitted ranges */ fb_page = xenfb->fb.page; - xenfb->pub.depth = fb_page->depth; - xenfb->pub.width = fb_page->width; - xenfb->pub.height = fb_page->height; + xenfb->data.depth = fb_page->depth; + xenfb->data.width = fb_page->width; + xenfb->data.height = fb_page->height;/* TODO check for consistency with the above */ - xenfb->fb_len = fb_page->mem_length; - xenfb->pub.row_stride = fb_page->line_length; + xenfb->data.len = fb_page->mem_length; + xenfb->data.row_stride = fb_page->line_length;if (xenfb_map_fb (xenfb, domid) <0 ) goto error;
@@ -869,7 +873,7 @@ int xenfb_attach_dom(struct xenfb *xenfbif (xenfb_xs_scanf1 (xsh, xenfb->kbd.otherend,"request-abs-pointer" ,"%d" , &val) <0 ) val =0 ; - xenfb->pub.abs_pointer_wanted = val; + xenfb->data.abs_pointer_wanted = val;/* Listen for events from xenstore */ if (qemu_set_fd_handler2 (xs_fileno (xenfb->xsh),NULL , xenfb_dispatch_store,NULL , xenfb) <0 )
@@ -882,19 +886,18 @@ int xenfb_attach_dom(struct xenfb *xenfb/* Register our keyboard & mouse handlers */ qemu_add_kbd_event_handler (xenfb_put_keycode, xenfb);qemu_add_mouse_event_handler (xenfb_mouse_event, xenfb, - xenfb_pub->abs_pointer_wanted, + xenfb->data.abs_pointer_wanted,"Xen PVFB Mouse" ); - xenfb_pub->update = xenfb_guest_copy; - xenfb_pub->user_data = ds; + xenfb->ds = ds;/* Tell QEMU to allocate a graphical console */ graphic_console_init (ds, xenfb_update, xenfb_invalidate, xenfb_screen_dump, - xenfb_pub); -dpy_resize (ds, xenfb_pub->width, xenfb_pub->height); + xenfb); +dpy_resize (ds, xenfb->data.width, xenfb->data.height);return 0 ;
tools/ioemu/hw/xenfb.h +1 -15
@@ -5,21 +5,7 @@#include <stdbool.h> #include <sys/types.h> -struct xenfb -{ -void *pixels; - -int row_stride; -int depth; -int width; -int height; -int abs_pointer_wanted; -int button_state; - -void *user_data; - -void (*update)(struct xenfb *xenfb,int x,int y,int width,int height); -}; +struct xenfb ;struct xenfb *xenfb_new (void );void xenfb_delete (struct xenfb *xenfb);
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 7/10: Async negotiation with xenfb frontend
In reply to Daniel P. BerrangeThis patch re-factors the paravirt console xenfb_attach_dom method. The original method blocks the caller until the front & backends have both switched to the connected state. This isn't an immediate problem, but patches which follow will extend qemu to also handle the text console so blocking on graphics console startup will block the text console processing.
The new code is basically a state machine. It starts off with a watch waiting for the KBD backend to switch to 'initialized' mode, then does the same for the FB backend. Now it waits for KBD & FB frontend devices to initialize, reading & mapping the framebuffer & its config at the appropriate step. When the KBD frontend finally reaches the connected state it registers a graphical console with QEMU and sets up the various framebuffer, mouse & keyboard event handlers. If a client connects to the VNC server before this is completed, then they will merely see a text console (or perhaps the monitor if configured that way).
xen_machine_pv.c | 9 xenfb.c | 687 ++++++++++++++++++++++++++++++++----------------------- xenfb.h | 7 3 files changed, 405 insertions(+), 298 deletions(-)
Dan.
tools/ioemu/hw/xen_machine_pv.c +1 -8
@@ -41,16 +41,9 @@ static void xen_init_pv(uint64_t ram_sizextern int domid;/* Prepare PVFB state */ - xenfb =xenfb_new (); + xenfb =xenfb_new (domid, ds);if (xenfb ==NULL ) {fprintf (stderr,"Could not create framebuffer (%s)\n" , -strerror (errno)); -exit (1 ); - } - -/* Talk to the guest */ -if (xenfb_attach_dom (xenfb, domid, ds) <0 ) { -fprintf (stderr,"Could not connect to domain (%s)\n" ,strerror (errno));exit (1 ); }
tools/ioemu/hw/xenfb.c +402 -285
768 lines not on this page · raw message
tools/ioemu/hw/xenfb.h +2 -5
@@ -7,10 +7,7 @@struct xenfb ; -struct xenfb *xenfb_new (void ); -void xenfb_delete (struct xenfb *xenfb); -void xenfb_teardown (struct xenfb *xenfb); - -int xenfb_attach_dom (struct xenfb *xenfb,int domid,DisplayState *ds); +struct xenfb *xenfb_new (int domid,DisplayState *ds); +void xenfb_shutdown (struct xenfb *xenfb);#endif
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 8/10: Add pv console to QEMU paravirt machine
In reply to Daniel P. BerrangeThis patch adds a paravirt console driver to qemu-dm. This is used when the QEMU machine type is 'xenpv', connecting to the ring buffer provided by the guest kernel. The '-serial' command line flag controls how the guest console is exposed. For parity with xenconsoled the '-serial pty' arg can be used. The xenconsoled daemon is no longer needed for guest consoles with this change applied. The code for the xen_console.c is based on the original tools/console/daemon/io.c, but greatly simplified - since its only dealing with a single guest there's no state tracking to worry about.
b/tools/ioemu/hw/xen_console.c | 424 ++++++++++++++++++++++++++++++++++++++++ b/tools/ioemu/hw/xen_console.h | 25 ++ tools/ioemu/Makefile.target | 1 tools/ioemu/hw/xen_machine_pv.c | 9 tools/ioemu/xenstore.c | 2 5 files changed, 460 insertions(+), 1 deletion(-)
Dan.
tools/ioemu/Makefile.target +1 -0
@@ -403,6 +403,7 @@ VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_fv.o VL_OBJS+= xen_machine_pv.o VL_OBJS+= xenfb.o +VL_OBJS+= xen_console.o VL_OBJS+= tpm_tis.o CPPFLAGS += -DHAS_AUDIO endif
tools/ioemu/hw/xen_console.c new file +424 -0
424 lines not on this page · raw message
tools/ioemu/hw/xen_console.h new file +25 -0
@@ -0,0 +1,25 @@ +/* +* Copyright (C) International Business Machines Corp., 2005 +* Author(s): Anthony Liguori <[email protected]> +* +* Copyright (C) Red Hat 2007 +* +* Xen Console +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; under version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vl.h" + +extern int xencons_init (int domid,CharDriverState *chr);
tools/ioemu/hw/xen_machine_pv.c +9 -0
@@ -23,6 +23,7 @@*/ #include "vl.h" +#include "xen_console.h" #include "xenfb.h"
@@ -39,6 +40,14 @@ static void xen_init_pv(uint64_t ram_siz {struct xenfb *xenfb;extern int domid; + +/* Connect to text console */ +if (serial_hds[0 ]) { +if (xencons_init (domid, serial_hds[0 ]) <0 ) { +fprintf (stderr,"Could not connect to domain console\n" ); +exit (1 ); + } + }/* Prepare PVFB state */ xenfb =xenfb_new (domid, ds);
tools/ioemu/xenstore.c +1 -1
@@ -17,7 +17,7 @@#include <sys/stat.h> #include <fcntl.h> -static struct xs_handle *xsh =NULL ; +struct xs_handle *xsh =NULL ;static char *media_filename[MAX_DISKS +MAX_SCSI_DISKS ];static QEMUTimer *insert_timer =NULL ;
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 9/10: XenD device model re-factoring
In reply to Daniel P. BerrangeThis code re-factors the image.py class, unifying the paravirt and fullvirt cases to a large degree. Both PV & FV now have a 'device model' - provided by same QEMU-DM binary in both cases. We pass -M xenpv, or -M xenfv as needed. The args for VNC, SDL etc are shared by both. HVM adds a bunch of extra args for disks & NICs mostly. The vfbif.py class no longer needs to start its own daemon for the paravirt framebuffer, since this is taken care of by the QEMU now. XendDomainInfo is tweaked so that it also starts the device model when restoring a paravirt guest.
XendDomainInfo.py | 7 - image.py | 367 +++++++++++++++++++++++++++--------------------------- server/vfbif.py | 59 -------- 3 files changed, 192 insertions(+), 241 deletions(-)
Dan.
tools/python/xen/xend/image.py +189 -178
@@ -56,10 +56,9 @@ class ImageHandler: defining in a subclass. The method createDeviceModel() is called to create the domain device - model if it needs one. The default is to do nothing. + model. The method destroy() is called when the domain is destroyed. - The default is to do nothing. """ ostype = None
@@ -91,6 +90,17 @@ class ImageHandler: ("image/cmdline", self.cmdline), ("image/ramdisk", self.ramdisk)) + self.dmargs = self.parseDeviceModelArgs(vmConfig) + self.device_model = vmConfig['platform'].get('device_model') + if not self.device_model: + self.device_model = xen.util.auxbin.pathTo("qemu-dm") + + self.display = vmConfig['platform'].get('display') + self.xauthority = vmConfig['platform'].get('xauthority') + self.vncconsole = vmConfig['platform'].get('vncconsole') + self.pid = None + + def cleanupBootloading(self): if self.bootloader:
@@ -173,25 +183,135 @@ class ImageHandler: """Build the domain. Define in subclass.""" raise NotImplementedError() + # Return a list of cmd line args to the device models based on the + # xm config file + def parseDeviceModelArgs(self, vmConfig): + ret = ["-domain-name", str(self.vm.info['name_label'])] + + # Find RFB console device, and if it exists, make QEMU enable + # the VNC console. + if int(vmConfig['platform'].get('nographic', 0)) != 0: + # skip vnc init if nographic is set + ret.append('-nographic') + return ret + + vnc_config = {} + has_vnc = int(vmConfig['platform'].get('vnc', 0)) != 0 + has_sdl = int(vmConfig['platform'].get('sdl', 0)) != 0 + for dev_uuid in vmConfig['console_refs']: + dev_type, dev_info = vmConfig['devices'][dev_uuid] + if dev_type == 'vfb': + vnc_config = dev_info.get('other_config', {}) + has_vnc = True + break + + keymap = vmConfig['platform'].get("keymap") + if keymap: + ret.append("-k") + ret.append(keymap) + + if has_vnc: + if not vnc_config: + for key in ('vncunused', 'vnclisten', 'vncdisplay', + 'vncpasswd'): + if key in vmConfig['platform']: + vnc_config[key] = vmConfig['platform'][key] + + vnclisten = vnc_config.get('vnclisten', + xenopts().get_vnclisten_address()) + vncdisplay = vnc_config.get('vncdisplay', 0) + ret.append('-vnc') + ret.append("%s:%d" % (vnclisten, vncdisplay)) + + if vnc_config.get('vncunused', 0): + ret.append('-vncunused') + + # Store vncpassword in xenstore + vncpasswd = vnc_config.get('vncpasswd') + if not vncpasswd: + vncpasswd = xenopts().get_vncpasswd_default() + + if vncpasswd is None: + raise VmError('vncpasswd is not setup in vmconfig or ' + 'xend-config.sxp') + + if vncpasswd != '': + self.vm.storeVm('vncpasswd', vncpasswd) + elif has_sdl: + # SDL is default in QEMU. + pass + else: + ret.append('-nographic') + + if int(vmConfig['platform'].get('monitor', 0)) != 0: + ret = ret + ['-monitor', 'vc'] + return ret + + def getDeviceModelArgs(self, restore = False): + args = [self.device_model] + args = args + ([ "-d", "%d" % self.vm.getDomid() ]) + args = args + self.dmargs + return args + def createDeviceModel(self, restore = False): - """Create device model for the domain (define in subclass if needed).""" - pass - + if self.pid: + return + # Execute device model. + #todo: Error handling + args = self.getDeviceModelArgs(restore) + env = dict(os.environ) + if self.display: + env['DISPLAY'] = self.display + if self.xauthority: + env['XAUTHORITY'] = self.xauthority + if self.vncconsole: + args = args + ([ "-vncviewer" ]) + log.info("spawning device models: %s %s", self.device_model, args) + # keep track of pid and spawned options to kill it later + self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) + self.vm.storeDom("image/device-model-pid", self.pid) + log.info("device model pid: %d", self.pid) + def saveDeviceModel(self): - """Save device model for the domain (define in subclass if needed).""" - pass + # Signal the device model to pause itself and save its state + xstransact.Store("/local/domain/0/device-model/%i" + % self.vm.getDomid(), ('command', 'save')) + # Wait for confirmation. Could do this with a watch but we'd + # still end up spinning here waiting for the watch to fire. + state = '' + count = 0 + while state != 'paused': + state = xstransact.Read("/local/domain/0/device-model/%i/state" + % self.vm.getDomid()) + time.sleep(0.1) + count += 1 + if count > 100: + raise VmError('Timed out waiting for device model to save') def resumeDeviceModel(self): - """Unpause device model for the domain (define in subclass if needed).""" - pass - - def destroy(self): - """Extra cleanup on domain destroy (define in subclass if needed).""" - pass - + # Signal the device model to resume activity after pausing to save. + xstransact.Store("/local/domain/0/device-model/%i" + % self.vm.getDomid(), ('command', 'continue')) def recreate(self): - pass + self.pid = self.vm.gatherDom(('image/device-model-pid', int)) + + def destroy(self, suspend = False): + if self.pid and not suspend: + try: + os.kill(self.pid, signal.SIGKILL) + except OSError, exn: + log.exception(exn) + try: + os.waitpid(self.pid, 0) + except OSError, exn: + # This is expected if Xend has been restarted within the + # life of this domain. In this case, we can kill the process, + # but we can't wait for it because it's not our child. + pass + self.pid = None + state = xstransact.Remove("/local/domain/0/device-model/%i" + % self.vm.getDomid()) class LinuxImageHandler(ImageHandler):
@@ -223,6 +343,19 @@ class LinuxImageHandler(ImageHandler): ramdisk = self.ramdisk, features = self.vm.getFeatures()) + def parseDeviceModelArgs(self, vmConfig): + ret = ImageHandler.parseDeviceModelArgs(self, vmConfig) + # Equivalent to old xenconsoled behaviour. Should make + # it configurable in future + ret = ret + ["-serial", "pty"] + return ret + + def getDeviceModelArgs(self, restore = False): + args = ImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-M", "xenpv"]) + return args + + class PPC_LinuxImageHandler(LinuxImageHandler): ostype = "linux"
@@ -256,15 +389,6 @@ class HVMImageHandler(ImageHandler): if 'hvm' not in info['xen_caps']: raise HVMRequired() - self.dmargs = self.parseDeviceModelArgs(vmConfig) - self.device_model = vmConfig['platform'].get('device_model') - if not self.device_model: - raise VmError("hvm: missing device model") - - self.display = vmConfig['platform'].get('display') - self.xauthority = vmConfig['platform'].get('xauthority') - self.vncconsole = vmConfig['platform'].get('vncconsole') - rtc_timeoffset = vmConfig['platform'].get('rtc_timeoffset') self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)),
@@ -272,46 +396,17 @@ class HVMImageHandler(ImageHandler): ("image/display", self.display)) self.vm.storeVm(("rtc/timeoffset", rtc_timeoffset)) - self.pid = None - self.pae = int(vmConfig['platform'].get('pae', 0)) self.apic = int(vmConfig['platform'].get('apic', 0)) self.acpi = int(vmConfig['platform'].get('acpi', 0)) - - - def buildDomain(self): - store_evtchn = self.vm.getStorePort() - - mem_mb = self.getRequiredInitialReservation() / 1024 - - log.debug("domid = %d", self.vm.getDomid()) - log.debug("image = %s", self.kernel) - log.debug("store_evtchn = %d", store_evtchn) - log.debug("memsize = %d", mem_mb) - log.debug("vcpus = %d", self.vm.getVCpuCount()) - log.debug("pae = %d", self.pae) - log.debug("acpi = %d", self.acpi) - log.debug("apic = %d", self.apic) - - rc = xc.hvm_build(domid = self.vm.getDomid(), - image = self.kernel, - store_evtchn = store_evtchn, - memsize = mem_mb, - vcpus = self.vm.getVCpuCount(), - pae = self.pae, - acpi = self.acpi, - apic = self.apic) - rc['notes'] = { 'SUSPEND_CANCEL': 1 } - return rc - - # Return a list of cmd line args to the device models based on the - # xm config file + def parseDeviceModelArgs(self, vmConfig): + ret = ImageHandler.parseDeviceModelArgs(self, vmConfig) + ret = ret + ['-vcpus', str(self.vm.getVCpuCount())] + dmargs = [ 'boot', 'fda', 'fdb', 'soundhw', 'localtime', 'serial', 'stdvga', 'isa', - 'acpi', 'usb', 'usbdevice', 'keymap' ] - - ret = ['-vcpus', str(self.vm.getVCpuCount())] + 'acpi', 'usb', 'usbdevice' ] for a in dmargs: v = vmConfig['platform'].get(a)
@@ -340,7 +435,6 @@ class HVMImageHandler(ImageHandler): # Handle disk/network related options mac = None - ret = ret + ["-domain-name", str(self.vm.info['name_label'])] nics = 0 for devuuid in vmConfig['vbd_refs']:
@@ -369,130 +463,40 @@ class HVMImageHandler(ImageHandler): ret.append("-net") ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge)) - - # - # Find RFB console device, and if it exists, make QEMU enable - # the VNC console. - # - if int(vmConfig['platform'].get('nographic', 0)) != 0: - # skip vnc init if nographic is set - ret.append('-nographic') - return ret - - vnc_config = {} - has_vnc = int(vmConfig['platform'].get('vnc', 0)) != 0 - has_sdl = int(vmConfig['platform'].get('sdl', 0)) != 0 - for dev_uuid in vmConfig['console_refs']: - dev_type, dev_info = vmConfig['devices'][dev_uuid] - if dev_type == 'vfb': - vnc_config = dev_info.get('other_config', {}) - has_vnc = True - break - - if has_vnc: - if not vnc_config: - for key in ('vncunused', 'vnclisten', 'vncdisplay', - 'vncpasswd'): - if key in vmConfig['platform']: - vnc_config[key] = vmConfig['platform'][key] - - vnclisten = vnc_config.get('vnclisten', - xenopts().get_vnclisten_address()) - vncdisplay = vnc_config.get('vncdisplay', 0) - ret.append('-vnc') - ret.append("%s:%d" % (vnclisten, vncdisplay)) - - if vnc_config.get('vncunused', 0): - ret.append('-vncunused') - - # Store vncpassword in xenstore - vncpasswd = vnc_config.get('vncpasswd') - if not vncpasswd: - vncpasswd = xenopts().get_vncpasswd_default() - - if vncpasswd is None: - raise VmError('vncpasswd is not setup in vmconfig or ' - 'xend-config.sxp') - - if vncpasswd != '': - self.vm.storeVm('vncpasswd', vncpasswd) - elif has_sdl: - # SDL is default in QEMU. - pass - else: - ret.append('-nographic') - - if int(vmConfig['platform'].get('monitor', 0)) != 0: - ret = ret + ['-monitor', 'vc'] return ret - def createDeviceModel(self, restore = False): - if self.pid: - return - # Execute device model. - #todo: Error handling - args = [self.device_model] - args = args + ([ "-d", "%d" % self.vm.getDomid() ]) - if arch.type == "ia64": - args = args + ([ "-m", "%s" % - (self.getRequiredInitialReservation() / 1024) ]) - args = args + self.dmargs + def getDeviceModelArgs(self, restore = False): + args = ImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-M", "xenfv"]) if restore: args = args + ([ "-loadvm", "/var/lib/xen/qemu-save.%d" % self.vm.getDomid() ]) - env = dict(os.environ) - if self.display: - env['DISPLAY'] = self.display - if self.xauthority: - env['XAUTHORITY'] = self.xauthority - if self.vncconsole: - args = args + ([ "-vncviewer" ]) - log.info("spawning device models: %s %s", self.device_model, args) - # keep track of pid and spawned options to kill it later - self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) - self.vm.storeDom("image/device-model-pid", self.pid) - log.info("device model pid: %d", self.pid) - - def saveDeviceModel(self): - # Signal the device model to pause itself and save its state - xstransact.Store("/local/domain/0/device-model/%i" - % self.vm.getDomid(), ('command', 'save')) - # Wait for confirmation. Could do this with a watch but we'd - # still end up spinning here waiting for the watch to fire. - state = '' - count = 0 - while state != 'paused': - state = xstransact.Read("/local/domain/0/device-model/%i/state" - % self.vm.getDomid()) - time.sleep(0.1) - count += 1 - if count > 100: - raise VmError('Timed out waiting for device model to save') - - def resumeDeviceModel(self): - # Signal the device model to resume activity after pausing to save. - xstransact.Store("/local/domain/0/device-model/%i" - % self.vm.getDomid(), ('command', 'continue')) - - def recreate(self): - self.pid = self.vm.gatherDom(('image/device-model-pid', int)) - - def destroy(self, suspend = False): - if self.pid and not suspend: - try: - os.kill(self.pid, signal.SIGKILL) - except OSError, exn: - log.exception(exn) - try: - os.waitpid(self.pid, 0) - except OSError, exn: - # This is expected if Xend has been restarted within the - # life of this domain. In this case, we can kill the process, - # but we can't wait for it because it's not our child. - pass - self.pid = None - state = xstransact.Remove("/local/domain/0/device-model/%i" - % self.vm.getDomid()) + return args + + def buildDomain(self): + store_evtchn = self.vm.getStorePort() + + mem_mb = self.getRequiredInitialReservation() / 1024 + + log.debug("domid = %d", self.vm.getDomid()) + log.debug("image = %s", self.kernel) + log.debug("store_evtchn = %d", store_evtchn) + log.debug("memsize = %d", mem_mb) + log.debug("vcpus = %d", self.vm.getVCpuCount()) + log.debug("pae = %d", self.pae) + log.debug("acpi = %d", self.acpi) + log.debug("apic = %d", self.apic) + + rc = xc.hvm_build(domid = self.vm.getDomid(), + image = self.kernel, + store_evtchn = store_evtchn, + memsize = mem_mb, + vcpus = self.vm.getVCpuCount(), + pae = self.pae, + acpi = self.acpi, + apic = self.apic) + rc['notes'] = { 'SUSPEND_CANCEL': 1 } + return rc class IA64_HVM_ImageHandler(HVMImageHandler):
@@ -514,6 +518,13 @@ class IA64_HVM_ImageHandler(HVMImageHand def getRequiredShadowMemory(self, shadow_mem_kb, maxmem_kb): # Explicit shadow memory is not a concept return 0 + + def getDeviceModelArgs(self, restore = False): + args = HVMImageHandler.getDeviceModelArgs(self, restore) + args = args + ([ "-m", "%s" % + (self.getRequiredInitialReservation() / 1024) ]) + return args + class X86_HVM_ImageHandler(HVMImageHandler):
tools/python/xen/xend/server/vfbif.py +0 -59
71 lines not on this page · raw message
tools/python/xen/xend/XendDomainInfo.py +3 -4
@@ -1638,10 +1638,9 @@ class XendDomainInfo: self.console_mfn = console_mfn self._introduceDomain() - if self.info.is_hvm(): - self.image = image.create(self, self.info) - if self.image: - self.image.createDeviceModel(True) + self.image = image.create(self, self.info) + if self.image: + self.image.createDeviceModel(True) self._storeDomDetails() self._registerWatches() self.refreshShutdown()
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Re: PATCH: 10/10: Gut the xenconsoled daemon
In reply to Daniel P. BerrangeThis patch guts the xenconsoled daemon, removing all code related to processing the paravirt guest text console. This capability is now provided by QEMU so using a separate daemon is redundant. The only thing left in xenconsoled is the code for persistently logging the hypervisor messages. If this isn't desired, then there is no need to launch xenconsoled at all. In fact this code could easily just be pushed into XenD it is so small.
a/tools/console/daemon/io.c | 831 ------------------------------------------- a/tools/console/daemon/io.h | 27 - tools/console/daemon/main.c | 62 ++- tools/console/daemon/utils.c | 28 - tools/console/daemon/utils.h | 3 5 files changed, 46 insertions(+), 905 deletions(-)
Dan.
tools/console/daemon/io.c deleted +0 -831
@@ -1,831 +0,0 @@ -/* -* Copyright (C) International Business Machines Corp., 2005 -* Author(s): Anthony Liguori <[email protected]> -* -* Xen Console Daemon -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; under version 2 of the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#define _GNU_SOURCE - -#include "utils.h" -#include "io.h" -#include <xs.h> -#include <xen/io/console.h> -#include <xenctrl.h> - -#include <malloc.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <sys/select.h> -#include <fcntl.h> -#include <unistd.h> -#include <termios.h> -#include <stdarg.h> -#include <sys/mman.h> - -#define MAX (a, b) (((a) > (b)) ? (a) : (b)) -#define MIN (a, b) (((a) < (b)) ? (a) : (b)) - -/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */ -#define MAX_STRLEN (x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2) - -extern int log_reload; -extern int log_guest; -extern int log_hv; -extern char *log_dir; - -static int log_hv_fd =-1 ; -static int xc_handle =-1 ; - -struct buffer -{ -char *data; -size_t consumed; -size_t size; -size_t capacity; -size_t max_capacity; -}; - -struct domain -{ -int domid; -int tty_fd; -int log_fd; -bool is_dead; -struct buffer buffer; -struct domain *next; -char *conspath; -char *serialpath; -int use_consolepath; -int ring_ref; -evtchn_port_t local_port; -evtchn_port_t remote_port; -int xce_handle; -struct xencons_interface *interface; -}; - -static struct domain *dom_head; - -static void buffer_append (struct domain *dom) -{ -struct buffer *buffer = &dom->buffer; -XENCONS_RING_IDX cons, prod, size; -struct xencons_interface *intf = dom->interface; - - cons = intf->out_cons; - prod = intf->out_prod; -mb (); - - size = prod - cons; -if ((size ==0 ) || (size >sizeof (intf->out))) -return ; - -if ((buffer->capacity - buffer->size) < size) { - buffer->capacity += (size +1024 ); - buffer->data =realloc (buffer->data, buffer->capacity); -if (buffer->data ==NULL ) { -dolog (LOG_ERR ,"Memory allocation failed" ); -exit (ENOMEM ); - } - } - -while (cons != prod) - buffer->data[buffer->size++] = intf->out[ -MASK_XENCONS_IDX (cons++, intf->out)]; - -mb (); - intf->out_cons = cons; -xc_evtchn_notify (dom->xce_handle, dom->local_port); - -/* Get the data to the logfile as early as possible because if -* no one is listening on the console pty then it will fill up -* and handle_tty_write will stop being called. -*/ -if (dom->log_fd !=-1 ) { -int len =write (dom->log_fd, - buffer->data + buffer->size - size, - size); -if (len <0 ) -dolog (LOG_ERR ,"Write to log failed on domain %d: %d (%s)\n" , - dom->domid, errno,strerror (errno)); - } - -if (buffer->max_capacity && - buffer->size > buffer->max_capacity) { -/* Discard the middle of the data. */ - -size_t over = buffer->size - buffer->max_capacity; -char *maxpos = buffer->data + buffer->max_capacity; - -memmove (maxpos - over, maxpos, over); - buffer->data =realloc (buffer->data, buffer->max_capacity); - buffer->size = buffer->capacity = buffer->max_capacity; - -if (buffer->consumed > buffer->max_capacity - over) - buffer->consumed = buffer->max_capacity - over; - } -} - -static bool buffer_empty (struct buffer *buffer) -{ -return buffer->size ==0 ; -} - -static void buffer_advance (struct buffer *buffer,size_t len) -{ - buffer->consumed += len; -if (buffer->consumed == buffer->size) { - buffer->consumed =0 ; - buffer->size =0 ; - } -} - -static bool domain_is_valid (int domid) -{ -bool ret; -xc_dominfo_t info; - - ret = (xc_domain_getinfo (xc, domid,1 , &info) ==1 && - info.domid == domid); - -return ret; -} - -static int create_hv_log (void ) -{ -char logfile[PATH_MAX ]; -int fd; -snprintf (logfile,PATH_MAX -1 ,"%s/hypervisor.log" , log_dir); - logfile[PATH_MAX -1 ] ='\0' ; - - fd =open (logfile,O_WRONLY |O_CREAT |O_APPEND ,0644 ); -if (fd ==-1 ) -dolog (LOG_ERR ,"Failed to open log %s: %d (%s)" , - logfile, errno,strerror (errno)); -return fd; -} - -static int create_domain_log (struct domain *dom) -{ -char logfile[PATH_MAX ]; -char *namepath, *data, *s; -int fd; -unsigned int len; - - namepath =xs_get_domain_path (xs, dom->domid); - s =realloc (namepath,strlen (namepath) +6 ); -if (s ==NULL ) { -free (namepath); -return -1 ; - } - namepath = s; -strcat (namepath,"/name" ); - data =xs_read (xs,XBT_NULL , namepath, &len); -if (!data) -return -1 ; -if (!len) { -free (data); -return -1 ; - } - -snprintf (logfile,PATH_MAX -1 ,"%s/guest-%s.log" , log_dir, data); -free (data); - logfile[PATH_MAX -1 ] ='\0' ; - - fd =open (logfile,O_WRONLY |O_CREAT |O_APPEND ,0644 ); -if (fd ==-1 ) -dolog (LOG_ERR ,"Failed to open log %s: %d (%s)" , - logfile, errno,strerror (errno)); -return fd; -} - - -static int domain_create_tty (struct domain *dom) -{ -char *path; -int master; -bool success; - -if ((master =open ("/dev/ptmx" ,O_RDWR |O_NOCTTY )) ==-1 || -grantpt (master) ==-1 ||unlockpt (master) ==-1 ) { -dolog (LOG_ERR ,"Failed to create tty for domain-%d" , - dom->domid); - master =-1 ; - }else { -const char *slave =ptsname (master); -struct termios term; -char *data; -unsigned int len; - -if (tcgetattr (master, &term) !=-1 ) { -cfmakeraw (&term); -tcsetattr (master,TCSAFLUSH , &term); - } - -if (dom->use_consolepath) { - success =asprintf (&path,"%s/limit" , dom->conspath) != --1 ; -if (!success) - goto out; - data =xs_read (xs,XBT_NULL , path, &len); -if (data) { - dom->buffer.max_capacity =strtoul (data,0 ,0 ); -free (data); - } -free (path); - } - - success =asprintf (&path,"%s/limit" , dom->serialpath) !=-1 ; -if (!success) - goto out; - data =xs_read (xs,XBT_NULL , path, &len); -if (data) { - dom->buffer.max_capacity =strtoul (data,0 ,0 ); -free (data); - } -free (path); - - success =asprintf (&path,"%s/tty" , dom->serialpath) !=-1 ; -if (!success) - goto out; - success =xs_write (xs,XBT_NULL , path, slave,strlen (slave)); -free (path); -if (!success) - goto out; - -if (dom->use_consolepath) { - success =asprintf (&path,"%s/tty" , dom->conspath) != --1 ; -if (!success) - goto out; - success =xs_write (xs,XBT_NULL , path, slave, -strlen (slave)); -free (path); -if (!success) - goto out; - } - -if (fcntl (master,F_SETFL ,O_NONBLOCK ) ==-1 ) - goto out; - } - -return master; - out: -close (master); -return -1 ; -} - -/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ -int xs_gather (struct xs_handle *xs,const char *dir, ...) -{ -va_list ap; -const char *name; -char *path; -int ret =0 ; - -va_start (ap, dir); - while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { - const char *fmt = va_arg(ap, char *); - void *result = va_arg(ap, void *); -char *p; - -if (asprintf (&path,"%s/%s" , dir, name) ==-1 ) { - ret =ENOMEM ; -break ; - } - p =xs_read (xs,XBT_NULL , path,NULL ); -free (path); -if (p ==NULL ) { - ret =ENOENT ; -break ; - } -if (fmt) { -if (sscanf (p, fmt, result) ==0 ) - ret =EINVAL ; -free (p); - }else - *(char **)result = p; - } -va_end (ap); -return ret; -} - -static int domain_create_ring (struct domain *dom) -{ -int err, remote_port, ring_ref, rc; - - err =xs_gather (xs, dom->serialpath, -"ring-ref" ,"%u" , &ring_ref, -"port" ,"%i" , &remote_port, -NULL ); -if (err) { - err =xs_gather (xs, dom->conspath, -"ring-ref" ,"%u" , &ring_ref, -"port" ,"%i" , &remote_port, -NULL ); -if (err) - goto out; - dom->use_consolepath =1 ; - }else - dom->use_consolepath =0 ; - -if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port)) - goto out; - -if (ring_ref != dom->ring_ref) { -if (dom->interface !=NULL ) -munmap (dom->interface,getpagesize ()); - dom->interface =xc_map_foreign_range ( - xc, dom->domid,getpagesize (), -PROT_READ |PROT_WRITE , - (unsigned long )ring_ref); -if (dom->interface ==NULL ) { - err =EINVAL ; - goto out; - } - dom->ring_ref = ring_ref; - } - - dom->local_port =-1 ; - dom->remote_port =-1 ; -if (dom->xce_handle !=-1 ) -xc_evtchn_close (dom->xce_handle); - -/* Opening evtchn independently for each console is a bit -* wasteful, but that's how the code is structured... */ - dom->xce_handle =xc_evtchn_open (); -if (dom->xce_handle ==-1 ) { - err = errno; - goto out; - } - - rc =xc_evtchn_bind_interdomain (dom->xce_handle, - dom->domid, remote_port); - -if (rc ==-1 ) { - err = errno; -xc_evtchn_close (dom->xce_handle); - dom->xce_handle =-1 ; - goto out; - } - dom->local_port = rc; - dom->remote_port = remote_port; - -if (dom->tty_fd ==-1 ) { - dom->tty_fd =domain_create_tty (dom); - -if (dom->tty_fd ==-1 ) { - err = errno; -xc_evtchn_close (dom->xce_handle); - dom->xce_handle =-1 ; - dom->local_port =-1 ; - dom->remote_port =-1 ; - goto out; - } - } - -if (log_guest) - dom->log_fd =create_domain_log (dom); - - out: -return err; -} - -static bool watch_domain (struct domain *dom,bool watch) -{ -char domid_str[3 +MAX_STRLEN (dom->domid)]; -bool success; - -sprintf (domid_str,"dom%u" , dom->domid); -if (watch) { - success =xs_watch (xs, dom->serialpath, domid_str); -if (success) { - success =xs_watch (xs, dom->conspath, domid_str); -if (success) -domain_create_ring (dom); -else -xs_unwatch (xs, dom->serialpath, domid_str); - } - }else { - success =xs_unwatch (xs, dom->serialpath, domid_str); - success =xs_unwatch (xs, dom->conspath, domid_str); - } - -return success; -} - - -static struct domain *create_domain (int domid) -{ -struct domain *dom; -char *s; - - dom = (struct domain *)malloc (sizeof (struct domain )); -if (dom ==NULL ) { -dolog (LOG_ERR ,"Out of memory %s:%s():L%d" , - __FILE__, __FUNCTION__, __LINE__); -exit (ENOMEM ); - } - - dom->domid = domid; - - dom->serialpath =xs_get_domain_path (xs, dom->domid); - s =realloc (dom->serialpath,strlen (dom->serialpath) + -strlen ("/serial/0" ) +1 ); -if (s ==NULL ) - goto out; - dom->serialpath = s; -strcat (dom->serialpath,"/serial/0" ); - - dom->conspath =xs_get_domain_path (xs, dom->domid); - s =realloc (dom->conspath,strlen (dom->conspath) + -strlen ("/console" ) +1 ); -if (s ==NULL ) - goto out; - dom->conspath = s; -strcat (dom->conspath,"/console" ); - - dom->tty_fd =-1 ; - dom->log_fd =-1 ; - - dom->is_dead = false; - dom->buffer.data =0 ; - dom->buffer.consumed =0 ; - dom->buffer.size =0 ; - dom->buffer.capacity =0 ; - dom->buffer.max_capacity =0 ; - dom->next =NULL ; - - dom->ring_ref =-1 ; - dom->local_port =-1 ; - dom->remote_port =-1 ; - dom->interface =NULL ; - dom->xce_handle =-1 ; - -if (!watch_domain (dom, true)) - goto out; - - dom->next = dom_head; - dom_head = dom; - -dolog (LOG_DEBUG ,"New domain %d" , domid); - -return dom; - out: -free (dom->serialpath); -free (dom->conspath); -free (dom); -return NULL ; -} - -static struct domain *lookup_domain (int domid) -{ -struct domain *dom; - -for (dom = dom_head; dom; dom = dom->next) -if (dom->domid == domid) -return dom; -return NULL ; -} - -static void remove_domain (struct domain *dom) -{ -struct domain **pp; - -dolog (LOG_DEBUG ,"Removing domain-%d" , dom->domid); - -for (pp = &dom_head; *pp; pp = &(*pp)->next) { -if (dom == *pp) { - *pp = dom->next; -free (dom); -break ; - } - } -} - -static void cleanup_domain (struct domain *d) -{ -if (d->tty_fd !=-1 ) { -close (d->tty_fd); - d->tty_fd =-1 ; - } -if (d->log_fd !=-1 ) { -close (d->log_fd); - d->log_fd =-1 ; - } - -free (d->buffer.data); - d->buffer.data =NULL ; - -free (d->serialpath); - d->serialpath =NULL ; - -free (d->conspath); - d->conspath =NULL ; - -remove_domain (d); -} - -static void shutdown_domain (struct domain *d) -{ - d->is_dead = true; -watch_domain (d, false); -if (d->interface !=NULL ) -munmap (d->interface,getpagesize ()); - d->interface =NULL ; -if (d->xce_handle !=-1 ) -xc_evtchn_close (d->xce_handle); - d->xce_handle =-1 ; -cleanup_domain (d); -} - -void enum_domains (void ) -{ -int domid =1 ; -xc_dominfo_t dominfo; -struct domain *dom; - -while (xc_domain_getinfo (xc, domid,1 , &dominfo) ==1 ) { - dom =lookup_domain (dominfo.domid); -if (dominfo.dying) { -if (dom) -shutdown_domain (dom); - }else { -if (dom ==NULL ) -create_domain (dominfo.domid); - } - domid = dominfo.domid +1 ; - } -} - -static int ring_free_bytes (struct domain *dom) -{ -struct xencons_interface *intf = dom->interface; -XENCONS_RING_IDX cons, prod, space; - - cons = intf->in_cons; - prod = intf->in_prod; -mb (); - - space = prod - cons; -if (space >sizeof (intf->in)) -return 0 ;/* ring is screwed: ignore it */ - -return (sizeof (intf->in) - space); -} - -static void handle_tty_read (struct domain *dom) -{ -ssize_t len =0 ; -char msg[80 ]; -int i; -struct xencons_interface *intf = dom->interface; -XENCONS_RING_IDX prod; - - len =ring_free_bytes (dom); -if (len ==0 ) -return ; - -if (len >sizeof (msg)) - len =sizeof (msg); - - len =read (dom->tty_fd, msg, len); -if (len <1 ) { -close (dom->tty_fd); - dom->tty_fd =-1 ; - -if (domain_is_valid (dom->domid)) { - dom->tty_fd =domain_create_tty (dom); - }else { -shutdown_domain (dom); - } - }else if (domain_is_valid (dom->domid)) { - prod = intf->in_prod; -for (i =0 ; i < len; i++) { - intf->in[MASK_XENCONS_IDX (prod++, intf->in)] = - msg[i]; - } -wmb (); - intf->in_prod = prod; -xc_evtchn_notify (dom->xce_handle, dom->local_port); - }else { -close (dom->tty_fd); - dom->tty_fd =-1 ; -shutdown_domain (dom); - } -} - -static void handle_tty_write (struct domain *dom) -{ -ssize_t len; - - len =write (dom->tty_fd, dom->buffer.data + dom->buffer.consumed, - dom->buffer.size - dom->buffer.consumed); -if (len <1 ) { -dolog (LOG_DEBUG ,"Write failed on domain %d: %zd, %d\n" , - dom->domid, len, errno); - -close (dom->tty_fd); - dom->tty_fd =-1 ; - -if (domain_is_valid (dom->domid)) { - dom->tty_fd =domain_create_tty (dom); - }else { -shutdown_domain (dom); - } - }else { -buffer_advance (&dom->buffer, len); - } -} - -static void handle_ring_read (struct domain *dom) -{ -evtchn_port_t port; - -if ((port =xc_evtchn_pending (dom->xce_handle)) ==-1 ) -return ; - -buffer_append (dom); - - (void )xc_evtchn_unmask (dom->xce_handle, port); -} - -static void handle_xs (void ) -{ -char **vec; -int domid; -struct domain *dom; -unsigned int num; - - vec =xs_read_watch (xs, &num); -if (!vec) -return ; - -if (!strcmp (vec[XS_WATCH_TOKEN ],"domlist" )) -enum_domains (); -else if (sscanf (vec[XS_WATCH_TOKEN ],"dom%u" , &domid) ==1 ) { - dom =lookup_domain (domid); -/* We may get watches firing for domains that have recently -been removed, so dom may be NULL here. */ -if (dom && dom->is_dead == false) -domain_create_ring (dom); - } - -free (vec); -} - -static void handle_hv_logs (void ) -{ -char buffer[1024 *16 ]; -char *bufptr = buffer; -unsigned int size =sizeof (buffer); -if (xc_readconsolering (xc_handle, &bufptr, &size,1 ) ==0 ) { -int len =write (log_hv_fd, buffer, size); -if (len <0 ) -dolog (LOG_ERR ,"Failed to write hypervisor log: %d (%s)" , - errno,strerror (errno)); - } -} - -static void handle_log_reload (void ) -{ -if (log_guest) { -struct domain *d; -for (d = dom_head; d; d = d->next) { -if (d->log_fd !=-1 ) -close (d->log_fd); - d->log_fd =create_domain_log (d); - } - } - -if (log_hv) { -if (log_hv_fd !=-1 ) -close (log_hv_fd); - log_hv_fd =create_hv_log (); - } -} - -void handle_io (void ) -{ -fd_set readfds, writefds; -int ret; - -if (log_hv) { - xc_handle =xc_interface_open (); -if (xc_handle ==-1 ) -dolog (LOG_ERR ,"Failed to open xc handle: %d (%s)" , - errno,strerror (errno)); -else - log_hv_fd =create_hv_log (); - } - -for (;;) { -struct domain *d, *n; -struct timeval timeout = {1 ,0 };/* Read HV logs every 1 second */ -int max_fd =-1 ; - -FD_ZERO (&readfds); -FD_ZERO (&writefds); - -FD_SET (xs_fileno (xs), &readfds); - max_fd =MAX (xs_fileno (xs), max_fd); - -for (d = dom_head; d; d = d->next) { -if (d->xce_handle !=-1 ) { -int evtchn_fd =xc_evtchn_fd (d->xce_handle); -FD_SET (evtchn_fd, &readfds); - max_fd =MAX (evtchn_fd, max_fd); - } - -if (d->tty_fd !=-1 ) { -if (!d->is_dead &&ring_free_bytes (d)) -FD_SET (d->tty_fd, &readfds); - -if (!buffer_empty (&d->buffer)) -FD_SET (d->tty_fd, &writefds); - max_fd =MAX (d->tty_fd, max_fd); - } - } - -/* XXX I wish we didn't have to busy wait for hypervisor logs -* but there's no obvious way to get event channel notifications -* for new HV log data as we can with guest */ - ret =select (max_fd +1 , &readfds, &writefds,0 , - log_hv_fd !=-1 ? &timeout :NULL ); - -if (log_reload) { -handle_log_reload (); - log_reload =0 ; - } - -/* Abort if select failed, except for EINTR cases -which indicate a possible log reload */ -if (ret ==-1 ) { -if (errno ==EINTR ) -continue ; -dolog (LOG_ERR ,"Failure in select: %d (%s)" , - errno,strerror (errno)); -break ; - } - -/* Always process HV logs even if not a timeout */ -if (log_hv_fd !=-1 ) -handle_hv_logs (); - -/* Must not check returned FDSET if it was a timeout */ -if (ret ==0 ) -continue ; - -if (FD_ISSET (xs_fileno (xs), &readfds)) -handle_xs (); - -for (d = dom_head; d; d = n) { - n = d->next; -if (d->xce_handle !=-1 && -FD_ISSET (xc_evtchn_fd (d->xce_handle), &readfds)) -handle_ring_read (d); - -if (d->tty_fd !=-1 &&FD_ISSET (d->tty_fd, &readfds)) -handle_tty_read (d); - -if (d->tty_fd !=-1 &&FD_ISSET (d->tty_fd, &writefds)) -handle_tty_write (d); - -if (d->is_dead) -cleanup_domain (d); - } - } - -if (log_hv_fd !=-1 ) { -close (log_hv_fd); - log_hv_fd =-1 ; - } -if (xc_handle !=-1 ) { -xc_interface_close (xc_handle); - xc_handle =-1 ; - } -} - -/* -* Local variables: -* c-file-style: "linux" -* indent-tabs-mode: t -* c-indent-level: 8 -* c-basic-offset: 8 -* tab-width: 8 -* End: -*/
tools/console/daemon/io.h deleted +0 -27
@@ -1,27 +0,0 @@ -/*\ -* Copyright (C) International Business Machines Corp., 2005 -* Author(s): Anthony Liguori <[email protected]> -* -* Xen Console Daemon -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; under version 2 of the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -\*/ - -#ifndef CONSOLED_IO_H -#define CONSOLED_IO_H - -void enum_domains (void ); -void handle_io (void ); - -#endif
tools/console/daemon/main.c +45 -17
111 lines not on this page · raw message
tools/console/daemon/utils.c +1 -27
@@ -36,7 +36,6 @@#include "xenctrl.h" #include "utils.h" -struct xs_handle *xs;int xc;static void child_exit (int sig)
@@ -107,37 +106,12 @@ void daemonize(const char *pidfile)bool xen_setup (void ) { - - xs =xs_daemon_open (); -if (xs ==NULL ) { -dolog (LOG_ERR , -"Failed to contact xenstore (%m). Is it running?" ); - goto out; - } - xc =xc_interface_open ();if (xc ==-1 ) {dolog (LOG_ERR ,"Failed to contact hypervisor (%m)" ); - goto out; - } - -if (!xs_watch (xs,"@introduceDomain" ,"domlist" )) { -dolog (LOG_ERR ,"xenstore watch on @introduceDomain fails." ); - goto out; - } - -if (!xs_watch (xs,"@releaseDomain" ,"domlist" )) { -dolog (LOG_ERR ,"xenstore watch on @releaseDomain fails." ); - goto out; +return false; }return true; - - out: -if (xs) -xs_daemon_close (xs); -if (xc !=-1 ) -xc_interface_close (xc); -return false; }
tools/console/daemon/utils.h +0 -3
@@ -25,12 +25,9 @@#include <syslog.h> #include <stdio.h> -#include "xs.h" -void daemonize (const char *pidfile);bool xen_setup (void ); -extern struct xs_handle *xs;extern int xc;#if 1
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Quoted 8 lines · Daniel P. Berrange
The only feature this re-factoring looses is the ability to have the paravirt text console persistently logged to a file. QEMU allows us to specify that a character device is either sent to a PTY, or a file, but not both at the same time. I'm thinking about ways in which QEMU's character device config syntax & drivers may be extended to allow use of a PTY & File concurrently.
The patches should be applied in order - after each individual patch you should still have a fully operational system for both FV & PV.
Have you tested both HVM and PV guests with save/restore, migration, and *failed* save/restore (e.g., by forcing an error in xc_domain_save.c)? The last needs care because qemu-dm must be kept around until the last moment, in case the save or migration fails.
Are these patches intended to be applied now, or are they RFC?
-- Keir
Quoted 8 lines · Keir Fraser
Quoted 6 lines · Daniel P. Berrange
The only feature this re-factoring looses is the ability to have the paravirt text console persistently logged to a file. QEMU allows us to specify that a character device is either sent to a PTY, or a file, but not both at the same time. I'm thinking about ways in which QEMU's character device config syntax & drivers may be extended to allow use of a PTY & File concurrently.
Quoted 7 lines
Quoted 2 lines
The patches should be applied in order - after each individual patch you should still have a fully operational system for both FV & PV.
Have you tested both HVM and PV guests with save/restore, migration, and *failed* save/restore (e.g., by forcing an error in
xc_domain_save.c)? The last needs care because qemu-dm must be kept around until the last moment, in case the save or migration fails.
I've not tested failed save/restore or migration - just normal save/restore for FV & PV. I'll do some further testing of the scenarios you suggest. I don't think I should have broken anything in qemu-dm for HVM because in the HVM codepaths I merely moved code from one file to another.
Quoted 1 line
Are these patches intended to be applied now, or are they RFC?
They could be applied now, but was expecting people might have some feedback /recommendations for changes - Christian normally has lots of good comments for QEMU related stuff. So if I have to do another revision of the patches I'm fine with it.
Dan.
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Quoted 6 lines · Daniel P. Berrange
Quoted 1 line
Are these patches intended to be applied now, or are they RFC?
They could be applied now, but was expecting people might have some feedback /recommendations for changes - Christian normally has lots of good comments for QEMU related stuff. So if I have to do another revision of the patches I'm fine with it.
My own feeling is that the xenfb merge is very sensible, but I don't see much of a win from merging xenconsoled, and the downside is that you then need a qemu-dm instance for every PV guest. I think that requiring qemu-dm for more 'featureful' PV guests -- framebuffer, USB, etc -- is well and good, but someone who is running more minimal domU configurations -- console, net, block -- isn't going to want or welcome the rather unnecessary per-domU overhead of qemu-dm.
So I think that qemu-dm for PV guests should be optional, and automatically enabled only if a config option that requires qemu is enabled.
-- Keir
Quoted 9 lines · Keir Fraser
Quoted 6 lines · Daniel P. Berrange
Quoted 1 line
Are these patches intended to be applied now, or are they RFC?
They could be applied now, but was expecting people might have some feedback /recommendations for changes - Christian normally has lots of good comments for QEMU related stuff. So if I have to do another revision of the patches I'm fine with it.
Quoted 7 lines
My own feeling is that the xenfb merge is very sensible, but I don't see much of a win from merging xenconsoled, and the downside is that you then need a qemu-dm instance for every PV guest. I think that requiring qemu-dm for more 'featureful' PV guests -- framebuffer, USB, etc -- is well and good, but someone who is running more minimal domU configurations -- console, net, block -- isn't going to want or welcome the rather unnecessary per-domU overhead of qemu-dm.
Yep, I can see that would be useful for some folks working in constrained environments. Of course they probably don't want the XenD overhead either, but that's a can of worms I won't get into right now ;-)
Thinking about this, I think I can easily re-work the last two patches so that xenconsoled will continue to process the guest consoles, if-and-only-if the guest doesn't have a QEMU instance already doing it. That would give us choice between both deployment scenarios per-guest.
Regards,
Dan.
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Quoted 11 lines · Daniel P. Berrange
Quoted 7 lines
My own feeling is that the xenfb merge is very sensible, but I don't see much of a win from merging xenconsoled, and the downside is that you then need a qemu-dm instance for every PV guest. I think that requiring qemu-dm for more 'featureful' PV guests -- framebuffer, USB, etc -- is well and good, but someone who is running more minimal domU configurations -- console, net, block -- isn't going to want or welcome the rather unnecessary per-domU overhead of qemu-dm.
Yep, I can see that would be useful for some folks working in constrained environments. Of course they probably don't want the XenD overhead either, but that's a can of worms I won't get into right now ;-)
At least the xend overhead is largely one-off rather than per-domain.
Quoted 4 lines
Thinking about this, I think I can easily re-work the last two patches so that xenconsoled will continue to process the guest consoles, if-and-only-if the guest doesn't have a QEMU instance already doing it. That would give us choice between both deployment scenarios per-guest.
That seems fair. The guest-console-over-vnc scenario is a compelling argument for supporting console-in-qemu as an option.
-- Keir
Quoted 1 line
Quoted 1 line
Quoted 1 line
On Thu, Aug 16, 2007 at 9:34 AM, in message
<[email protected]>, "Daniel P. Berrange" <[email protected]>
Quoted 23 lines · wrote:
Quoted 5 lines · Keir Fraser
Quoted 3 lines · Daniel P. Berrange
Quoted 1 line
Are these patches intended to be applied now, or are they RFC?
They could be applied now, but was expecting people might have some
feedback
Quoted 11 lines
Quoted 3 lines
/recommendations for changes - Christian normally has lots of good comments for QEMU related stuff. So if I have to do another revision of the patches I'm fine with it.
My own feeling is that the xenfb merge is very sensible, but I don't see much of a win from merging xenconsoled, and the downside is that you then need a qemu- dm instance for every PV guest. I think that requiring qemu- dm for more 'featureful' PV guests -- framebuffer, USB, etc -- is well and good, but someone who is running more minimal domU configurations -- console, net, block -- isn't going to want or welcome the rather unnecessary per- domU overhead of qemu- dm.
Yep, I can see that would be useful for some folks working in constrained environments. Of course they probably don't want the XenD overhead either, but that's a can of worms I won't get into right now ;- )
Quoted 7 lines
Thinking about this, I think I can easily re- work the last two patches so that xenconsoled will continue to process the guest consoles, if- and- only- if the guest doesn't have a QEMU instance already doing it. That would give us choice between both deployment scenarios per- guest.
Regards,
Dan.
Would this patch set, in it's current state, allow a 'featureful' PV guest to see a DOM0 CDROM as a CD device instead of a block device?
Thanks
Pat
Quoted 10 lines · Pat Campbell
Quoted 9 lines
Yep, I can see that would be useful for some folks working in constrained environments. Of course they probably don't want the XenD overhead either, but that's a can of worms I won't get into right now ;- )
Thinking about this, I think I can easily re- work the last two patches so that xenconsoled will continue to process the guest consoles, if- and- only- if
the guest doesn't have a QEMU instance already doing it. That would give us choice between both deployment scenarios per- guest.
Quoted 3 lines
Would this patch set, in it's current state, allow a 'featureful' PV guest to see a
DOM0 CDROM as a CD device instead of a block device?
No, that kind of stuff isn't plumbed through at all. But it's an obvious direction to take it.
-- Keir
Quoted 12 lines · Keir Fraser
Quoted 10 lines · Pat Campbell
Quoted 9 lines
Yep, I can see that would be useful for some folks working in constrained environments. Of course they probably don't want the XenD overhead either, but that's a can of worms I won't get into right now ;- )
Thinking about this, I think I can easily re- work the last two patches so that xenconsoled will continue to process the guest consoles, if- and- only- if
the guest doesn't have a QEMU instance already doing it. That would give us choice between both deployment scenarios per- guest.
Quoted 6 lines
Quoted 3 lines
Would this patch set, in it's current state, allow a 'featureful' PV guest to see a
DOM0 CDROM as a CD device instead of a block device?No, that kind of stuff isn't plumbed through at all. But it's an obvious direction to take it.
Yes, I'd particularly like to be able get the emulated USB bus hooked up, but personally have no clue how to go about doing this.
It gives a very nice device passthrough capability that will integrate extremely well with HAL & desktop session policy allowing users to assign their local hotplugged devices to the guest as VMWare Workstation allows.
Dan.
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Quoted 6 lines
Yes, I'd particularly like to be able get the emulated USB bus hooked up, but personally have no clue how to go about doing this.
It gives a very nice device passthrough capability that will integrate extremely well with HAL & desktop session policy allowing users to assign their local hotplugged devices to the guest as VMWare Workstation allows.
IBM were interested in this kind of stuff too; their bladecenter has a single USB cdrom for a group of blades. The drive is simply switched between them using a USB switcher in the blade enclosure and standard hotplug on the blade OS. The ability to do the same thing *within* a blade, to different OSes would make management more uniform for them.
They did have someone looking at getting paravirt USB working but I'm not sure where that project got to. However, if USB could easily be passed to paravirt guests as an emulated device it would be quite handy for some things. It would be interesting to see what performance was achievable this way, but some high bandwidth devices like disk and network can always go through the usual paravirt drivers.
Cheers,
Mark
Signature · 4 lines
Dave: Just a question. What use is a unicyle with no seat? And no pedals! Mark: To answer a question with a question: What use is a skateboard? Dave: Skateboards have wheels. Mark: My wheel has a wheel!
PATCH 1/1 Shared CD-Rom Support
In response to the cdrom discussion going on today:
Attached is a port of a patch we have against 3.1
This patch plumbs the cdrom info through QEMU such that a QEMU monitor command may switch the domain owning the physiical cdrom, such that an eject command on the guest command line will physically eject the drive door.
Monitor command example:set_cdrom_owner 1 hdd
(for the time being the "hdd" parameter is a constant, as we only support a singular CDRom)
tools/ioemu/block.c +83 -4
@@ -56,6 +56,8 @@ static BlockDriverState *bdrv_first;static BlockDriverState *bdrv_first;static BlockDriver *first_drv; +static BlockDriver *get_bdrv_raw (void ); +int path_is_absolute (const char *path) {const char *p;
@@ -323,6 +325,7 @@ int bdrv_open2(BlockDriverState *bs, con {int ret, open_flags;char tmp_filename[1024 ]; +int is_media_inserted;char backing_filename[1024 ]; bs->read_only =0 ;
@@ -359,6 +362,10 @@ int bdrv_open2(BlockDriverState *bs, con }pstrcpy (bs->filename,sizeof (bs->filename), filename); +if (bs->type ==BDRV_TYPE_CDROM && !drv && bs->is_shared) { + drv =get_bdrv_raw (); + }else { +if (flags &BDRV_O_FILE ) { drv =find_protocol (filename);if (!drv)
@@ -370,16 +377,27 @@ int bdrv_open2(BlockDriverState *bs, conreturn -1 ; } } + + } bs->drv = drv; bs->opaque =qemu_mallocz (drv->instance_size);if (bs->opaque ==NULL && drv->instance_size >0 )return -1 ; + is_media_inserted =1 ;/* Note: for compatibility, we open disk image files as RDWR, and RDONLY as fallback */ if (!(flags &BDRV_O_FILE )) open_flags =BDRV_O_RDWR ;else open_flags = flags & ~(BDRV_O_FILE |BDRV_O_SNAPSHOT ); + +if (bs->type ==BDRV_TYPE_CDROM && bs->is_shared) { +if (!bs->is_owner) { + bs->total_sectors =0 ; +return ENOMEDIUM ; + } + } + ret = drv->bdrv_open (bs, filename, open_flags);if (ret == -EACCES && !(flags &BDRV_O_FILE )) { ret = drv->bdrv_open (bs, filename,BDRV_O_RDONLY );
@@ -391,6 +409,20 @@ int bdrv_open2(BlockDriverState *bs, con bs->drv =NULL ;return ret; } + +if (bs->type ==BDRV_TYPE_CDROM && ret <1 ) { +if (!bs->is_owner) { + bs->total_sectors =0 ; +if (errno ==ENOMEDIUM ) +return ENOMEDIUM ; +else +return -1 ; + } + } + +if (bs->type ==BDRV_TYPE_CDROM && ret ==ENOMEDIUM ) + is_media_inserted =0 ; +if (drv->bdrv_getlength) { bs->total_sectors =bdrv_getlength (bs) >>SECTOR_BITS ; }
@@ -413,8 +445,12 @@ int bdrv_open2(BlockDriverState *bs, con goto fail; } +if (is_media_inserted) + bs->media_changed =1 ; +else + bs->media_changed =0 ; +/* call the change callback */ - bs->media_changed =1 ;if (bs->change_cb) bs->change_cb (bs->change_opaque);
@@ -427,19 +463,20 @@ void bdrv_close(BlockDriverState *bs)if (bs->backing_hd)bdrv_delete (bs->backing_hd); bs->drv->bdrv_close (bs); -qemu_free (bs->opaque); + bs->drv =NULL ;#ifdef _WIN32if (bs->is_temporary) {unlink (bs->filename); }#endif - bs->opaque =NULL ; - bs->drv =NULL ;/* call the change callback */ bs->media_changed =1 ;if (bs->change_cb) bs->change_cb (bs->change_opaque); + +qemu_free (bs->opaque); + bs->opaque =NULL ; } }
@@ -754,6 +791,28 @@ void bdrv_set_translation_hint(BlockDriv bs->translation = translation; } +void bdrv_set_shared_owner_hint (BlockDriverState *bs,int is_owner) +{ + bs->is_shared =1 ; + bs->is_owner = is_owner; +} + +void bdrv_change_shared_owner (BlockDriverState *bs,int new_owner_state) +{ +if (!bs->is_shared) +return ; + +if (bs->is_owner == new_owner_state) +return ; + + bs->is_owner = new_owner_state; + +if (!new_owner_state) { +bdrv_close (bs); +return ; + } +} +void bdrv_get_geometry_hint (BlockDriverState *bs,int *pcyls,int *pheads,int *psecs) {
@@ -770,6 +829,16 @@ int bdrv_get_translation_hint(BlockDriveint bdrv_get_translation_hint (BlockDriverState *bs) {return bs->translation; +} + +int bdrv_is_shared (BlockDriverState *bs) +{ +return bs->is_shared; +} + +int bdrv_is_owner (BlockDriverState *bs) +{ +return bs->is_owner; }int bdrv_is_removable (BlockDriverState *bs)
@@ -854,6 +923,11 @@ const char *bdrv_get_device_name(BlockDrconst char *bdrv_get_device_name (BlockDriverState *bs) {return bs->device_name; +} + +const char *bdrv_get_filename (BlockDriverState *bs) +{ +return bs->filename; }void bdrv_flush (BlockDriverState *bs)
@@ -1231,6 +1305,11 @@ static int bdrv_write_em(BlockDriverStatreturn async_ret; } +static BlockDriver *get_bdrv_raw (void ) +{ +return &bdrv_raw ; +} +void bdrv_init (void ) {bdrv_register (&bdrv_raw);
tools/ioemu/block_int.h +2 -0
@@ -87,6 +87,8 @@ struct BlockDriverState {int removable;/* if true, the media can be removed */ int locked;/* if true, the media cannot temporarily be ejected */ int encrypted;/* if true, the media is encrypted */ +int is_shared;/* if true, the media is shared across multiple QEMU instances */ +int is_owner;/* if true, the media is sharable and currently owned by this QEMU instance */ /* event callback when inserting/removing */ void (*change_cb)(void *opaque);void *change_opaque;
tools/ioemu/hw/ide.c +222 -5
297 lines not on this page · raw message
tools/ioemu/monitor.c +38 -1
@@ -397,6 +397,40 @@ void do_change(const char *device, constterm_printf ("invalid password\n" ); } } +} + +static void do_set_cdrom_owner (const char * new_owner_state_cstr,const char *device) +{ +BlockDriverState *bs; +int new_owner_state; + +if (!new_owner_state_cstr || !device) { +term_printf ("[set_cdrom_owner] ERROR : insufficient args (NULL) !?!\n" ); +return ; + } + +if (sscanf (new_owner_state_cstr,"%d" , &new_owner_state) !=1 ) { +term_printf ("[set_cdrom_owner] ERROR : bad arg '%s'\n" , new_owner_state_cstr); +return ; + } + +if (new_owner_state)// normalize given input + new_owner_state =1 ; + + bs =bdrv_find (device); +if (!bs) { +term_printf ("[set_cdrom_owner] ERROR : cdrom device '%s' not found %d\n" , device, new_owner_state); +return ; + } + +if (bdrv_is_owner (bs) == new_owner_state) { +term_printf ("[set_cdrom_owner] IGNORED : no change to ownership %d\n" , new_owner_state); +return ; + } + +bdrv_change_shared_owner (bs, new_owner_state); + +term_printf ("[set_cdrom_owner] done : (%d)\n" , new_owner_state); }static void do_screen_dump (const char *filename)
@@ -1217,7 +1251,10 @@ static term_cmd_t term_cmds[] = { "filename", "save screen into PPM image 'filename'" }, {"log" ,"s" , do_log, "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, -#ifndef CONFIG_DM +#ifdef CONFIG_DM + { "set_cdrom_owner", "sB", do_set_cdrom_owner, + "<1|0> device", "1 to become the owner and acquire the physical drive or 0 to release it and no longer be the owner" }, +#else { "savevm", "s?", do_savevm, "tag|id", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" }, { "loadvm", "s", do_loadvm,
tools/ioemu/vl.c +5 -0
@@ -6436,6 +6436,7 @@ enum { QEMU_OPTION_hdd, QEMU_OPTION_cdrom, #endif /* !CONFIG_DM */ + QEMU_OPTION_cdrom_shared_with_eject, QEMU_OPTION_boot, QEMU_OPTION_snapshot, #ifdef TARGET_I386
@@ -6519,6 +6520,7 @@ const QEMUOption qemu_options[] = { { "hdd", HAS_ARG, QEMU_OPTION_hdd }, { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, #endif /* !CONFIG_DM */ + { "cdrom-shared-with-eject", 0, QEMU_OPTION_cdrom_shared_with_eject }, { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, #ifdef TARGET_I386
@@ -7279,6 +7281,9 @@ int main(int argc, char **argv) }break ;#endif /* !CONFIG_DM */ +case QEMU_OPTION_cdrom_shared_with_eject: +// XXX Temporarily ignore this option +break ;case QEMU_OPTION_boot: boot_device =strdup (optarg); if (strspn(boot_device, "a"
tools/ioemu/vl.h +5 -0
@@ -678,10 +678,14 @@ void bdrv_set_geometry_hint(BlockDriverS int cyls, int heads, int secs);void bdrv_set_type_hint (BlockDriverState *bs,int type);void bdrv_set_translation_hint (BlockDriverState *bs,int translation); +void bdrv_set_shared_owner_hint (BlockDriverState *bs,int is_owner); +void bdrv_change_shared_owner (BlockDriverState *bs,int new_owner_state);void bdrv_get_geometry_hint (BlockDriverState *bs,int *pcyls,int *pheads,int *psecs);int bdrv_get_type_hint (BlockDriverState *bs);int bdrv_get_translation_hint (BlockDriverState *bs); +int bdrv_is_shared (BlockDriverState *bs); +int bdrv_is_owner (BlockDriverState *bs);int bdrv_is_removable (BlockDriverState *bs);int bdrv_is_read_only (BlockDriverState *bs);int bdrv_is_inserted (BlockDriverState *bs);
@@ -700,6 +704,7 @@ void bdrv_iterate_format(void (*it)(voidvoid bdrv_iterate_format (void (*it)(void *opaque,const char *name),void *opaque);const char *bdrv_get_device_name (BlockDriverState *bs); +const char *bdrv_get_filename (BlockDriverState *bs);int bdrv_write_compressed (BlockDriverState *bs,int64_t sector_num,const uint8_t *buf,int nb_sectors);int bdrv_get_info (BlockDriverState *bs,BlockDriverInfo *bdi);
tools/ioemu/xenstore.c +23 -3
@@ -85,6 +85,7 @@ void xenstore_parse_domain_config(int do *dev =NULL , *params =NULL , *type =NULL ;int i, is_scsi;unsigned int len, num, hd_index; +int is_cdrom_shared_with_eject, is_cdrom_owner;for (i =0 ; i <MAX_DISKS +MAX_SCSI_DISKS ; i++) media_filename[i] =NULL ;
@@ -166,10 +167,29 @@ void xenstore_parse_domain_config(int do bs_table[hd_index + (is_scsi ?MAX_DISKS :0 )] =bdrv_new (dev);/* check if it is a cdrom */ -if (type && !strcmp (type,"cdrom" )) { +if (type && !strcmp (type,"cdrom" )) { + is_cdrom_shared_with_eject = is_cdrom_owner =0 ; +/* read the cdrom param is_cdrom_shared_with_eject (if any) */ +if (pasprintf (&buf,"%s/device/vbd/%s/cdrom-shared-witheject" , path, e[i]) ==-1 ) +continue ; +free (type); + type =xs_read (xsh,XBT_NULL , buf, &len); +if (type !=NULL ) + is_cdrom_shared_with_eject = (atoi (type))?1 :0 ; +/* read the cdrom param is_cdrom_shared_with_eject (if any) */ +if (pasprintf (&buf,"%s/device/vbd/%s/cdrom-owner" , path, e[i]) ==-1 ) +continue ; +free (type); + type =xs_read (xsh,XBT_NULL , buf, &len); +if (type !=NULL ) + is_cdrom_owner = (atoi (type))?1 :0 ; +/* indicate that this device is a cdrom */ bdrv_set_type_hint (bs_table[hd_index],BDRV_TYPE_CDROM ); -if (pasprintf (&buf,"%s/params" , bpath) !=-1 ) -xs_watch (xsh, buf, dev); +if (is_cdrom_shared_with_eject) +bdrv_set_shared_owner_hint (bs_table[hd_index], is_cdrom_owner); + +if (pasprintf (&buf,"%s/params" , bpath) !=-1 ) +xs_watch (xsh, buf, dev); }/* open device now if media present */ if (params[0 ]) {
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel
Quoted 18 lines · Daniel P. Berrange
Quoted 9 lines · Keir Fraser
Quoted 6 lines · Daniel P. Berrange
Quoted 1 line
Are these patches intended to be applied now, or are they RFC?
They could be applied now, but was expecting people might have some feedback /recommendations for changes - Christian normally has lots of good comments for QEMU related stuff. So if I have to do another revision of the patches I'm fine with it.
Quoted 7 lines
My own feeling is that the xenfb merge is very sensible, but I don't see much of a win from merging xenconsoled, and the downside is that you then need a qemu-dm instance for every PV guest. I think that requiring qemu-dm for more 'featureful' PV guests -- framebuffer, USB, etc -- is well and good, but someone who is running more minimal domU configurations -- console, net, block -- isn't going to want or welcome the rather unnecessary per-domU overhead of qemu-dm.
Quoted 8 lines
Yep, I can see that would be useful for some folks working in constrained environments. Of course they probably don't want the XenD overhead either, but that's a can of worms I won't get into right now ;-)
Thinking about this, I think I can easily re-work the last two patches so that xenconsoled will continue to process the guest consoles, if-and-only-if the guest doesn't have a QEMU instance already doing it. That would give us choice between both deployment scenarios per-guest.
I've got this working ok - since both xenconsoled and qemu-dm are already reading the /local/domain/<id>/console/ path in xenstore, I simply added an extra field 'use-device-model' which can be 1 or 0. If XenD sees that a PV domain has a device model then it sets it to 1, causing xenconsoled to ignore that guest. I'll post patches to this effect over the weekend
Dan.
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Quoted 10 lines · Daniel P. Berrange
Quoted 4 lines
Thinking about this, I think I can easily re-work the last two patches so that xenconsoled will continue to process the guest consoles, if-and-only-if the guest doesn't have a QEMU instance already doing it. That would give us choice between both deployment scenarios per-guest.
I've got this working ok - since both xenconsoled and qemu-dm are already reading the /local/domain/<id>/console/ path in xenstore, I simply added an extra field 'use-device-model' which can be 1 or 0. If XenD sees that a PV domain has a device model then it sets it to 1, causing xenconsoled to ignore that guest. I'll post patches to this effect over the weekend
Sounds basically good, but a field called 'type' in the backend xenstore directory would be more flexible and more consistent with other backend directory contents (at least netback's). We could use values 'ioemu' and 'xenconsoled', and absence of the field implies xenconsoled. Both ioemu and xenconsoled should check the field.
-- Keir
Quoted 17 lines · Daniel P. Berrange
Quoted 8 lines · Keir Fraser
Quoted 6 lines · Daniel P. Berrange
The only feature this re-factoring looses is the ability to have the paravirt text console persistently logged to a file. QEMU allows us to specify that a character device is either sent to a PTY, or a file, but not both at the same time. I'm thinking about ways in which QEMU's character device config syntax & drivers may be extended to allow use of a PTY & File concurrently.
Quoted 7 lines
Quoted 2 lines
The patches should be applied in order - after each individual patch you should still have a fully operational system for both FV & PV.
Have you tested both HVM and PV guests with save/restore, migration, and *failed* save/restore (e.g., by forcing an error in
xc_domain_save.c)? The last needs care because qemu-dm must be kept around until the last moment, in case the save or migration fails.
Quoted 4 lines
I've not tested failed save/restore or migration - just normal save/restore for FV & PV. I'll do some further testing of the scenarios you suggest. I don't think I should have broken anything in qemu-dm for HVM because in the HVM codepaths I merely moved code from one file to another.
Migration was working fine, but there's some complications with recovering from a failed save attempt. In fact even without my changes it currently fails being unable to detach the blktap disk, and so the recovery dies with a 'Device vbd already connected' error. Once I track that problem down I know what changes I need to make PVFB recovery work
Dan.
Signature · 4 lines
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|