[libvirt] [PATCH] qemu-options: Remove deprecated "-virtioconsole" option

2018-12-12 Thread Thomas Huth
It's been deprecated since QEMU 3.0, and nobody complained so far, so
it is time to remove this option now.

Signed-off-by: Thomas Huth 
---
 docs/qdev-device-use.txt |  4 
 include/hw/boards.h  |  1 -
 qemu-deprecated.texi |  5 
 qemu-options.hx  | 10 
 vl.c | 61 +---
 5 files changed, 1 insertion(+), 80 deletions(-)

diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt
index 98229b3..cc53e97 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -190,10 +190,6 @@ The appropriate DEVNAME depends on the machine type.  For 
type "pc":
 
   -device usb-braille,chardev=braille -chardev braille,id=braille
 
-* -virtioconsole becomes
-  -device virtio-serial-pci,class=C,vectors=V,ioeventfd=IOEVENTFD,max_ports=N
-  -device virtconsole,is_console=NUM,nr=NR,name=NAME
-
 LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
 
 * null becomes -chardev null
diff --git a/include/hw/boards.h b/include/hw/boards.h
index f82f284..5df67d2 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -181,7 +181,6 @@ struct MachineClass {
 int default_cpus;
 unsigned int no_serial:1,
 no_parallel:1,
-use_virtcon:1,
 no_floppy:1,
 no_cdrom:1,
 no_sdcard:1,
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index 72b8191..5cc18b4 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -60,11 +60,6 @@ The @code{--no-frame} argument works with SDL 1.2 only. The 
other user
 interfaces never implemented this in the first place. So this will be
 removed together with SDL 1.2 support.
 
-@subsection -virtioconsole (since 3.0.0)
-
-Option @option{-virtioconsole} has been replaced by
-@option{-device virtconsole}.
-
 @subsection -clock (since 3.0.0)
 
 The @code{-clock} option is ignored since QEMU version 1.7.0. There is no
diff --git a/qemu-options.hx b/qemu-options.hx
index 269eda7..5330603 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3635,16 +3635,6 @@ character to Control-t.
 @end table
 ETEXI
 
-DEF("virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon, \
-"-virtioconsole c\n" \
-"set virtio console\n", QEMU_ARCH_ALL)
-STEXI
-@item -virtioconsole @var{c}
-@findex -virtioconsole
-Set virtio console.
-This option is deprecated, please use @option{-device virtconsole} instead.
-ETEXI
-
 DEF("show-cursor", 0, QEMU_OPTION_show_cursor, \
 "-show-cursorshow cursor\n", QEMU_ARCH_ALL)
 STEXI
diff --git a/vl.c b/vl.c
index a5ae5f2..595d610 100644
--- a/vl.c
+++ b/vl.c
@@ -164,7 +164,6 @@ int no_frame;
 static int num_serial_hds;
 static Chardev **serial_hds;
 Chardev *parallel_hds[MAX_PARALLEL_PORTS];
-Chardev *virtcon_hds[MAX_VIRTIO_CONSOLES];
 int win2k_install_hack = 0;
 int singlestep = 0;
 int smp_cpus;
@@ -215,7 +214,6 @@ bool xen_domid_restrict;
 static int has_defaults = 1;
 static int default_serial = 1;
 static int default_parallel = 1;
-static int default_virtcon = 1;
 static int default_monitor = 1;
 static int default_floppy = 1;
 static int default_cdrom = 1;
@@ -236,8 +234,6 @@ static struct {
 { .driver = "ide-drive",.flag = &default_cdrom },
 { .driver = "scsi-cd",  .flag = &default_cdrom },
 { .driver = "scsi-hd",  .flag = &default_cdrom },
-{ .driver = "virtio-serial-pci",.flag = &default_virtcon   },
-{ .driver = "virtio-serial",.flag = &default_virtcon   },
 { .driver = "VGA",  .flag = &default_vga   },
 { .driver = "isa-vga",  .flag = &default_vga   },
 { .driver = "cirrus-vga",   .flag = &default_vga   },
@@ -2374,7 +2370,6 @@ struct device_config {
 DEV_BT,/* -bt*/
 DEV_SERIAL,/* -serial*/
 DEV_PARALLEL,  /* -parallel  */
-DEV_VIRTCON,   /* -virtioconsole */
 DEV_DEBUGCON,  /* -debugcon */
 DEV_GDB,   /* -gdb, -s */
 DEV_SCLP,  /* s390 sclp */
@@ -2472,39 +2467,6 @@ static int parallel_parse(const char *devname)
 return 0;
 }
 
-static int virtcon_parse(const char *devname)
-{
-QemuOptsList *device = qemu_find_opts("device");
-static int index = 0;
-char label[32];
-QemuOpts *bus_opts, *dev_opts;
-
-if (strcmp(devname, "none") == 0)
-return 0;
-if (index == MAX_VIRTIO_CONSOLES) {
-error_report("too many virtio consoles");
-exit(1);
-}
-
-bus_opts = qemu_opts_create(device, NULL, 0, &error_abort);
-qemu_opt_set(bus_opts, "driver", "virtio-serial", &error_abort);
-
-dev_opts = qemu_opts_create(device, NULL, 0, &error_abort);
-qemu_opt_set(dev_opts, "driver", "virtconsole", &error_abort);
-
-snprintf(label, sizeof(label), "virtcon%d", index);
-virtcon_hds[index] = qemu_chr_new_mux_mon(label, devname);
-if (!virtcon_hds[index]) {
-error_report("could not connect 

Re: [libvirt] [PATCH 4/8] tests: Introduce tests for storage pool xml to argv checks

2018-12-12 Thread John Ferlan



On 12/12/18 9:04 AM, Michal Privoznik wrote:
> On 12/4/18 5:47 PM, John Ferlan wrote:
>> Similar to qemuxml2argv and storagevolxml2argv, let's create some
>> tests to ensure that the XML generates a consistent command line.
>>
>> Using the same list of pools as storagepoolxml2xmltest, start with
>> the file system tests (fs, netfs, netfs-cifs, netfs-gluster).
>>
>> Signed-off-by: John Ferlan 
>> ---
>>  tests/Makefile.am |  12 ++
>>  tests/storagepoolxml2argvdata/pool-fs.argv|   1 +
>>  .../pool-netfs-cifs.argv  |   1 +
>>  .../pool-netfs-gluster.argv   |   1 +
>>  tests/storagepoolxml2argvdata/pool-netfs.argv |   1 +
>>  tests/storagepoolxml2argvtest.c   | 171 ++
>>  6 files changed, 187 insertions(+)
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-fs.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-cifs.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-gluster.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs.argv
>>  create mode 100644 tests/storagepoolxml2argvtest.c
>>
>> diff --git a/tests/Makefile.am b/tests/Makefile.am
>> index d7ec7e3a6f..bec0930c11 100644
>> --- a/tests/Makefile.am
>> +++ b/tests/Makefile.am
>> @@ -140,6 +140,7 @@ EXTRA_DIST = \
>>  storagepoolschemadata \
>>  storagepoolxml2xmlin \
>>  storagepoolxml2xmlout \
>> +storagepoolxml2argvdata \
>>  storagevolschemadata \
>>  storagevolxml2argvdata \
>>  storagevolxml2xmlin \
>> @@ -363,6 +364,7 @@ endif WITH_NWFILTER
>>  
>>  if WITH_STORAGE
>>  test_programs += storagevolxml2argvtest
>> +test_programs += storagepoolxml2argvtest
>>  test_programs += virstorageutiltest
>>  endif WITH_STORAGE
>>  
>> @@ -901,6 +903,16 @@ storagevolxml2argvtest_LDADD = \
>>  ../src/libvirt_util.la \
>>  $(LDADDS)
>>  
>> +storagepoolxml2argvtest_SOURCES = \
>> +storagepoolxml2argvtest.c \
>> +testutils.c testutils.h
>> +storagepoolxml2argvtest_LDADD = \
>> +$(LIBXML_LIBS) \
>> +../src/libvirt_driver_storage_impl.la \
>> +../src/libvirt_conf.la \
>> +../src/libvirt_util.la \
>> +$(LDADDS)
>> +
>>  else ! WITH_STORAGE
>>  EXTRA_DIST += storagevolxml2argvtest.c
>>  EXTRA_DIST += virstorageutiltest.c
>> diff --git a/tests/storagepoolxml2argvdata/pool-fs.argv 
>> b/tests/storagepoolxml2argvdata/pool-fs.argv
>> new file mode 100644
>> index 00..4a94148114
>> --- /dev/null
>> +++ b/tests/storagepoolxml2argvdata/pool-fs.argv
>> @@ -0,0 +1 @@
>> +/usr/bin/mount -t ext3 /dev/sda6 /mnt
> 
> Problem is, on my system (Gentoo), it is /usr/mount so this is failing
> for me.
> 
> I wonder if we should have a placeholder here, say "MOUNT" and then
> replace it with actual location of 'mount' (taken from config.h) at runtime.
> 
> Michal
> 

If I add a call to virTestClearCommandPath(actualCmdline); just prior to
the if (virTestCompareToFile(actualCmdline, cmdline) < 0) *and* I modify
each of the .argv files to remove the leading path, then things work
just fine.

Would you like to see or is the explanation good enough? IDC either way.

The .argv files would be affected/changed here, patch5 (netfs-auto), and
patch8 (logical).

Tks -

John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCHv2 01/16] qemu: Add KVM CPUs into cache only if KVM is present

2018-12-12 Thread Roman Bolshakov
On Fri, Nov 23, 2018 at 09:46:36PM +0300, Roman Bolshakov wrote:
> On Fri, Nov 23, 2018 at 06:16:46PM +0100, Jiri Denemark wrote:
> > On Fri, Nov 23, 2018 at 18:55:00 +0300, Roman Bolshakov wrote:
> > > On Fri, Nov 23, 2018 at 04:30:13PM +0100, Jiri Denemark wrote:
> > > > On Fri, Nov 23, 2018 at 17:16:12 +0300, Roman Bolshakov wrote:
> > > > > On Wed, Nov 21, 2018 at 07:43:43PM +0100, Jiri Denemark wrote:
> > > > > > virQEMUCapsInitHostCPUModel always fills in something and your check
> > > > > > should probably remain in place for it
> > > > > > 
> > > > > > virQEMUCapsFormatHostCPUModelInfo does
> > > > > > virQEMUCapsHostCPUDataPtr cpuData = &qemuCaps->kvmCPU;
> > > > > > qemuMonitorCPUModelInfoPtr model = cpuData->info;
> > > > > > if (!model)
> > > > > > return;
> > > > > > 
> > > > > > virQEMUCapsFormatCPUModels
> > > > > > cpus = qemuCaps->kvmCPUModels;
> > > > > > if (!cpus)
> > > > > > return;
> > > > > > 
> > > > > > So to me it looks like all functions are ready to see NULL pointers 
> > > > > > and
> > > > > > just do nothing if that's the case. Thus the only thing this patch
> > > > > > should need to do is to make sure virQEMUCapsInitHostCPUModel does 
> > > > > > not
> > > > > > set something non-NULL there.
> > > > > 
> > > > > Unfortunately, that won't work for the patch series. kvmCPUModels is 
> > > > > renamed to
> > > > > accelCPUModels and kvmCPU is renamed to accelCPU in PATCH 6.
> > > > 
> > > > And how does different name change the behavior?
> > > > 
> > > > > So, virQEMUCapsFormatHostCPUModelInfo looks like:
> > > > > if (virQEMUCapsTypeIsAccelerated(type))
> > > > > cpuData = qemuCaps->accelCPU;
> > > > > else
> > > > > cpuData = qemuCaps->tcgCPU;
> > > > > 
> > > > > and virQEMUCapsFormatCPUModels looks like:
> > > > > if (virQEMUCapsTypeIsAccelerated(type))
> > > > > cpus = qemuCaps->accelCPUModels;
> > > > > else
> > > > > cpus = qemuCaps->tcgCPUModels;
> > > > > 
> > > > > Without the check we'd return CPUs for KVM domain on the platform 
> > > > > that doesn't
> > > > > support it.
> > > > 
> > > > It won't return anything because the code will make sure accelCPUModels
> > > > and accelCPU will be NULL when no accel method is supported.
> > > 
> > > But accelCPU is not NULL on macOS with QEMU_CAPS_HVF and on Linux with
> > > QEMU_CAPS_KVM. That's where the problem arises.
> > 
> > Right, and that's what I think should be changed. Rather then adding
> > checks to the formatting and loading code to ignore something which
> > shouldn't be present in the first place.
> > 
> > > We're going to get additional kvm CPUs on mac and hvf CPUs on Linux
> > > and that will break qemucapabilitiestest.
> > 
> > I think I'm missing something here. There's only one CPU definition
> > describing the host CPU. There are hosts which have several different
> > CPUs, but libvirt is not really prepared to see that and I believe this
> > is not what you're addressing with this series, is it? Or are you
> > talking about some other CPUs?
> > 
> > > In fact they will be the same accelCPUs of the supported accelerator
> > > but with hostCPU's type attribute of the other accelerator.
> > 
> > How would this happen? We have a single accelerator enabled on a host
> > and we generate a host CPU model for it (and just for it, there's no
> > reason to generate a CPU model for something that is not supported on
> > the host).
> > 
> 
> accelCPU will be present on a host where an accelerator is avaialable.
> You said can't have host CPU definitions present twice. I agree with
> that. But if we call virQEMUCapsFormatCPUModels twice for
> VIR_DOMAIN_VIRT_KVM and VIR_DOMAIN_VIRT_HVF without the checks, host cpu
> definitions will be present twice for each accelerator because accelCPU
> is not NULL.
> 
> So we need to call it only once for the supported accelerator.
> The checks help in that. Alternative approach to do only one call is:
> 
>   virDomainVirtType acceleratedDomain = VIR_DOMAIN_VIRT_KVM;
>   if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF))
> acceleratedDomain = VIR_DOMAIN_VIRT_HVF;
> 
>   virQEMUCapsFormatHostCPUModelInfo(qemuCaps, &buf, acceleratedDomain);
>   virQEMUCapsFormatHostCPUModelInfo(qemuCaps, &buf, VIR_DOMAIN_VIRT_QEMU);
> 
>   virQEMUCapsFormatCPUModels(qemuCaps, &buf, acceleratedDomain);
>   virQEMUCapsFormatCPUModels(qemuCaps, &buf, VIR_DOMAIN_VIRT_QEMU);
> 
> Would that work for you?
> 
> --
> Thank you,
> Roman
> 

Hi Jiri,

That's a kind reminder.

Thank you,
Roman

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH v2 0/2] qemu: Don't use -mem-prealloc among with .prealloc=yes

2018-12-12 Thread John Ferlan


On 12/12/18 7:58 AM, Michal Privoznik wrote:
> v2 of:
> 
> https://www.redhat.com/archives/libvir-list/2018-November/msg00159.html
> 
> diff to v1:
> - Patch 01/02 is completely new
> - Patch 02/02 has reworded commit message
> 
> Michal Prívozník (2):
>   qemuBuildMemoryBackendProps: Pass @priv instead of its individual
> members
>   qemu: Don't use -mem-prealloc among with .prealloc=yes
> 
>  src/qemu/qemu_command.c   | 56 ++-
>  src/qemu/qemu_command.h   |  3 +-
>  src/qemu/qemu_domain.c|  7 +++
>  src/qemu/qemu_domain.h|  3 +
>  src/qemu/qemu_hotplug.c   |  2 +-
>  .../hugepages-numa-default-dimm.args  |  2 +-
>  6 files changed, 44 insertions(+), 29 deletions(-)
> 

Adjust commit message for patch2 to spell "fully" instead of "fullly"...


Reviewed-by: John Ferlan 
(series)

John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH v2 0/4] util: Fixing libvirt errors on cavium/thunder-nicvf

2018-12-12 Thread dann frazier
On Sat, Nov 17, 2018 at 1:17 PM Radoslaw Biernacki
 wrote:
>
> ThunderX is Cavium SoC. This platform contain SRIOV NIC.
> Unlike other commonly known network devices it does not have VF functionality
> duplicated in its PF. PF is purely management device (on HW level).
>
> This creates several problems with existing libvirt code as in many places
> libvirt assumes that each VF netdev has PF netdev assigned.
>
> This patch series trying to address issues which can be easily fixed.
> (mostly bug fixes found while working on full featured solution)
>
> First patch in series is most important as it allows to unblock the netdev
> detection and use  on this platform.i  still does not work as it requires bigger changes both on netdev driver
> and in libvirt itself.
> More details about those issues can be found at:
> https://bugs.linaro.org/show_bug.cgi?id=3778
> https://bugs.launchpad.net/charm-nova-compute/+bug/1771662
>
> v2:
> - error reporting taken out of virNetDevGetPhysicalFunction() and moved
>   to calling function virNetDevGetVirtualFunctionInfo()
> - curly braces removed from single line
> - net-> model check removed as STREQ_NULLABLE() follows

Thanks Radoslaw ! I know a v3 is in the works, but just an fyi that we
ran this series through our OpenStack testing on a cluster of ThunderX
nodes and found no issues.

  -dann

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 46/51] qemu: monitor: Implement support for 'JOB_STATUS_CHANGE' event

2018-12-12 Thread Peter Krempa
This new event is a superset of the BLOCK_JOB* events and also covers
jobs which don't bind to a VM disk.

In this patch the monitor part is implemented.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_monitor.c  | 13 +
 src/qemu/qemu_monitor.h  |  9 +
 src/qemu/qemu_monitor_json.c | 26 ++
 3 files changed, 48 insertions(+)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 7d061a48ab..367e3265b8 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1526,6 +1526,19 @@ qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
 }


+int
+qemuMonitorEmitJobStatusChange(qemuMonitorPtr mon,
+   const char *jobname,
+   qemuMonitorJobStatus status)
+{
+int ret = -1;
+VIR_DEBUG("mon=%p", mon);
+
+QEMU_MONITOR_CALLBACK(mon, ret, jobStatusChange, mon->vm, jobname, status);
+return ret;
+}
+
+
 int
 qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
  unsigned long long actual)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index e51177bf44..e7ea8f5b8e 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -222,6 +222,11 @@ typedef int 
(*qemuMonitorDomainBlockJobCallback)(qemuMonitorPtr mon,
  int status,
  const char *error,
  void *opaque);
+typedef int (*qemuMonitorDomainJobStatusChangeCallback)(qemuMonitorPtr mon,
+virDomainObjPtr vm,
+const char *jobname,
+int status,
+void *opaque);
 typedef int (*qemuMonitorDomainTrayChangeCallback)(qemuMonitorPtr mon,
virDomainObjPtr vm,
const char *devAlias,
@@ -341,6 +346,7 @@ struct _qemuMonitorCallbacks {
 qemuMonitorDomainIOErrorCallback domainIOError;
 qemuMonitorDomainGraphicsCallback domainGraphics;
 qemuMonitorDomainBlockJobCallback domainBlockJob;
+qemuMonitorDomainJobStatusChangeCallback jobStatusChange;
 qemuMonitorDomainTrayChangeCallback domainTrayChange;
 qemuMonitorDomainPMWakeupCallback domainPMWakeup;
 qemuMonitorDomainPMSuspendCallback domainPMSuspend;
@@ -452,6 +458,9 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
 int type,
 int status,
 const char *error);
+int qemuMonitorEmitJobStatusChange(qemuMonitorPtr mon,
+   const char *jobname,
+   qemuMonitorJobStatus status);
 int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
  unsigned long long actual);
 int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 101e6ec7cd..a8f6320414 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -84,6 +84,7 @@ static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr 
mon, virJSONValuePtr d
 static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, 
virJSONValuePtr data);
 static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, 
virJSONValuePtr data);
 static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, 
virJSONValuePtr data);
+static void qemuMonitorJSONHandleJobStatusChange(qemuMonitorPtr mon, 
virJSONValuePtr data);
 static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, 
virJSONValuePtr data);
 static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, 
virJSONValuePtr data);
 static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, 
virJSONValuePtr data);
@@ -115,6 +116,7 @@ static qemuEventHandler eventHandlers[] = {
 { "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
 { "DUMP_COMPLETED", qemuMonitorJSONHandleDumpCompleted, },
 { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
+{ "JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange, },
 { "MIGRATION", qemuMonitorJSONHandleMigrationStatus, },
 { "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, },
 { "NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged, },
@@ -1035,6 +1037,30 @@ qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon,
 qemuMonitorEmitBlockJob(mon, device, type, event, error);
 }

+
+static void
+qemuMonitorJSONHandleJobStatusChange(qemuMonitorPtr mon,
+ virJSONValuePtr data)
+{
+const char *jobname = virJSONValueObjectGetString(data, "id");
+const char *statusstr = virJSONValueObjectGetString(data, "status");
+int status;
+
+if (!jobname) {

[libvirt] [PATCH RFC 49/51] qemu: Add handler for job state change event

2018-12-12 Thread Peter Krempa
Add support for handling the event either synchronously or
asynchronously using the event thread.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_domain.c  |  3 ++
 src/qemu/qemu_domain.h  |  1 +
 src/qemu/qemu_driver.c  | 23 ++
 src/qemu/qemu_process.c | 66 +
 4 files changed, 93 insertions(+)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 7845889dec..9467d0fd32 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -13711,6 +13711,9 @@ qemuProcessEventFree(struct qemuProcessEvent *event)
 case QEMU_PROCESS_EVENT_MONITOR_EOF:
 VIR_FREE(event->data);
 break;
+case QEMU_PROCESS_EVENT_JOB_STATUS_CHANGE:
+virObjectUnref(event->data);
+break;
 case QEMU_PROCESS_EVENT_PR_DISCONNECT:
 case QEMU_PROCESS_EVENT_LAST:
 break;
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index a243bdc80e..0a2973aba9 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -485,6 +485,7 @@ typedef enum {
 QEMU_PROCESS_EVENT_NIC_RX_FILTER_CHANGED,
 QEMU_PROCESS_EVENT_SERIAL_CHANGED,
 QEMU_PROCESS_EVENT_BLOCK_JOB,
+QEMU_PROCESS_EVENT_JOB_STATUS_CHANGE,
 QEMU_PROCESS_EVENT_MONITOR_EOF,
 QEMU_PROCESS_EVENT_PR_DISCONNECT,

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f62d153c03..0c38a61adc 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4747,6 +4747,26 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 }


+static void
+processJobStatusChangeEvent(virQEMUDriverPtr driver,
+virDomainObjPtr vm,
+qemuBlockJobDataPtr job)
+{
+if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+return;
+
+if (!virDomainObjIsActive(vm)) {
+VIR_DEBUG("Domain is not running");
+goto endjob;
+}
+
+qemuBlockJobUpdate(vm, job, QEMU_ASYNC_JOB_NONE);
+
+ endjob:
+qemuDomainObjEndJob(driver, vm);
+}
+
+
 static void
 processMonitorEOFEvent(virQEMUDriverPtr driver,
virDomainObjPtr vm)
@@ -4842,6 +4862,9 @@ static void qemuProcessEventHandler(void *data, void 
*opaque)
  processEvent->action,
  processEvent->status);
 break;
+case QEMU_PROCESS_EVENT_JOB_STATUS_CHANGE:
+processJobStatusChangeEvent(driver, vm, processEvent->data);
+break;
 case QEMU_PROCESS_EVENT_MONITOR_EOF:
 processMonitorEOFEvent(driver, vm);
 break;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 255a5acc13..fb687a1fd9 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -981,6 +981,71 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon 
ATTRIBUTE_UNUSED,
 }


+static int
+qemuProcessHandleJobStatusChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm,
+ const char *jobname,
+ int status,
+ void *opaque)
+{
+virQEMUDriverPtr driver = opaque;
+qemuDomainObjPrivatePtr priv;
+struct qemuProcessEvent *processEvent = NULL;
+qemuBlockJobDataPtr job = NULL;
+qemuBlockjobState jobnewstate;
+
+virObjectLock(vm);
+priv = vm->privateData;
+
+VIR_DEBUG("job '%s'(domain: %p,%s) state changed to '%s'(%d)",
+  jobname, vm, vm->def->name,
+  qemuMonitorJobStatusTypeToString(status), status);
+
+if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV)) {
+VIR_DEBUG("job '%s' handled by old blockjob handler", jobname);
+goto cleanup;
+}
+
+jobnewstate = qemuBlockjobConvertMonitorStatus(status);
+
+if (jobnewstate == QEMU_BLOCKJOB_STATE_LAST)
+goto cleanup;
+
+if (!(job = virHashLookup(priv->blockjobs, jobname))) {
+VIR_DEBUG("job '%s' not registered", jobname);
+goto cleanup;
+}
+
+job->newstate = jobnewstate;
+
+if (job->synchronous) {
+VIR_DEBUG("job '%s' handled synchronously", jobname);
+virDomainObjBroadcast(vm);
+} else {
+VIR_DEBUG("job '%s' handled by event thread", jobname);
+if (VIR_ALLOC(processEvent) < 0)
+goto cleanup;
+
+processEvent->eventType = QEMU_PROCESS_EVENT_JOB_STATUS_CHANGE;
+processEvent->vm = virObjectRef(vm);
+VIR_STEAL_PTR(processEvent->data, job);
+
+if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
+ignore_value(virObjectUnref(vm));
+goto cleanup;
+}
+
+processEvent = NULL;
+}
+
+ cleanup:
+qemuProcessEventFree(processEvent);
+virObjectUnref(job);
+virObjectUnlock(vm);
+return 0;
+}
+
+
 static int
 qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
   virDomainObjPtr vm,
@@ -1735,6 +1800,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
 

[libvirt] [PATCH RFC 47/51] qemu: process: Don't trigger BLOCK_JOB* events with -blockdev

2018-12-12 Thread Peter Krempa
With blockdev we'll need to use the JOB_STATUS_CHANGE so gate the old
events by the blockdev capability.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_process.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 4b57411856..255a5acc13 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -923,6 +923,7 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon 
ATTRIBUTE_UNUSED,
   const char *error,
   void *opaque)
 {
+qemuDomainObjPrivatePtr priv;
 virQEMUDriverPtr driver = opaque;
 struct qemuProcessEvent *processEvent = NULL;
 virDomainDiskDefPtr disk;
@@ -931,6 +932,12 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon 
ATTRIBUTE_UNUSED,

 virObjectLock(vm);

+priv = vm->privateData;
+
+/* with QEMU_CAPS_BLOCKDEV we handle block job events via 
JOB_STATUS_CHANGE */
+if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
+goto cleanup;
+
 VIR_DEBUG("Block job for device %s (domain: %p,%s) type %d status %d",
   diskAlias, vm, vm->def->name, type, status);

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 48/51] qemu: blockjob: Add helper to convert monitor job status to internal state

2018-12-12 Thread Peter Krempa
Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 41 
 src/qemu/qemu_blockjob.h |  3 +++
 2 files changed, 44 insertions(+)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index ee545fc8de..020e7b3994 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -480,3 +480,44 @@ qemuBlockJobGetByDisk(virDomainDiskDefPtr disk)

 return virObjectRef(job);
 }
+
+
+/**
+ * @monitorstatus: Status of the blockjob from qemu monitor 
(qemuMonitorJobStatus)
+ *
+ * Converts the block job status from the monitor to the one used by
+ * qemuBlockJobData. If the status is unknown or does not require any handling
+ * QEMU_BLOCKJOB_TYPE_LAST is returned.
+ */
+qemuBlockjobState
+qemuBlockjobConvertMonitorStatus(int monitorstatus)
+{
+qemuBlockjobState ret = QEMU_BLOCKJOB_TYPE_LAST;
+
+switch ((qemuMonitorJobStatus) monitorstatus) {
+case QEMU_MONITOR_JOB_STATUS_READY:
+ret = QEMU_BLOCKJOB_STATE_READY;
+break;
+
+case QEMU_MONITOR_JOB_STATUS_CONCLUDED:
+ret = QEMU_BLOCKJOB_STATE_CONCLUDED;
+break;
+
+case QEMU_MONITOR_JOB_STATUS_UNKNOWN:
+case QEMU_MONITOR_JOB_STATUS_CREATED:
+case QEMU_MONITOR_JOB_STATUS_RUNNING:
+case QEMU_MONITOR_JOB_STATUS_PAUSED:
+case QEMU_MONITOR_JOB_STATUS_STANDBY:
+case QEMU_MONITOR_JOB_STATUS_WAITING:
+case QEMU_MONITOR_JOB_STATUS_PENDING:
+case QEMU_MONITOR_JOB_STATUS_ABORTING:
+case QEMU_MONITOR_JOB_STATUS_UNDEFINED:
+case QEMU_MONITOR_JOB_STATUS_NULL:
+case QEMU_MONITOR_JOB_STATUS_LAST:
+default:
+break;
+}
+
+return ret;
+
+}
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index c8a6d8cf4c..9a2d047d03 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -118,4 +118,7 @@ qemuBlockJobDataPtr
 qemuBlockJobGetByDisk(virDomainDiskDefPtr disk)
 ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;

+qemuBlockjobState
+qemuBlockjobConvertMonitorStatus(int monitorstatus);
+
 #endif /* __QEMU_BLOCKJOB_H__ */
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 51/51] qemu: process: Refresh -blockdev based blockjobs on reconnect to qemu

2018-12-12 Thread Peter Krempa
Refresh the state of the jobs and process any events that might have
happened while libvirt was not running.

The job state processing requires some care to figure out if a job
needs to be bumped.t

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 57 
 src/qemu/qemu_blockjob.h |  4 +++
 src/qemu/qemu_process.c  |  7 -
 3 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 6aa8b1df51..8631db7986 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -222,6 +222,63 @@ qemuBlockJobIsRunning(qemuBlockJobDataPtr job)
 }


+int
+qemuBlockJobRefreshJobs(virQEMUDriverPtr driver,
+virDomainObjPtr vm)
+{
+qemuDomainObjPrivatePtr priv = vm->privateData;
+qemuMonitorJobInfoPtr *jobinfo = NULL;
+size_t njobinfo = 0;
+qemuBlockJobDataPtr job = NULL;
+qemuBlockjobState newstate;
+size_t i;
+int ret = -1;
+int rc;
+
+qemuDomainObjEnterMonitor(driver, vm);
+
+rc = qemuMonitorGetJobInfo(priv->mon, &jobinfo, &njobinfo);
+
+if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
+goto cleanup;
+
+for (i = 0; i < njobinfo; i++) {
+if (!(job = virHashLookup(priv->blockjobs, jobinfo[i]->id))) {
+VIR_DEBUG("ignoring untracked job '%s'", jobinfo[i]->id);
+continue;
+}
+
+newstate = qemuBlockjobConvertMonitorStatus(jobinfo[i]->status);
+if (newstate == QEMU_BLOCKJOB_STATE_LAST)
+continue;
+
+if (newstate != job->state) {
+if ((job->state == QEMU_BLOCKJOB_STATE_FAILED ||
+ job->state == QEMU_BLOCKJOB_STATE_COMPLETED)) {
+/* preserve the old state but allow the job to be bumped to
+ * execute the finishing steps */
+job->newstate = job->state;
+} else {
+job->newstate = newstate;
+}
+}
+
+/* qemuBlockJobUpdate checks whether something is needed */
+qemuBlockJobUpdate(vm, job, QEMU_ASYNC_JOB_NONE);
+job = NULL; /* job may have become invalid here */
+}
+
+ret = 0;
+
+ cleanup:
+for (i = 0; i < njobinfo; i++)
+qemuMonitorJobInfoFree(jobinfo[i]);
+VIR_FREE(jobinfo);
+
+return ret;
+}
+
+
 /**
  * qemuBlockJobEmitEvents:
  *
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 9a2d047d03..6e86c78a9b 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -105,6 +105,10 @@ void
 qemuBlockJobStartupFinalize(virDomainObjPtr vm,
 qemuBlockJobDataPtr job);

+int
+qemuBlockJobRefreshJobs(virQEMUDriverPtr driver,
+virDomainObjPtr vm);
+
 int qemuBlockJobUpdate(virDomainObjPtr vm,
qemuBlockJobDataPtr job,
int asyncJob);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index fb687a1fd9..75edced15d 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -7895,7 +7895,12 @@ static int
 qemuProcessRefreshBlockjobs(virQEMUDriverPtr driver,
 virDomainObjPtr vm)
 {
-return qemuProcessRefreshLegacyBlockjobs(driver, vm);
+qemuDomainObjPrivatePtr priv = vm->privateData;
+
+if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
+return qemuBlockJobRefreshJobs(driver, vm);
+else
+return qemuProcessRefreshLegacyBlockjobs(driver, vm);
 }


-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 50/51] qemu: blockjob: Add modern block job event handler

2018-12-12 Thread Peter Krempa
Add the infrastructure to handle block job events in the -blockdev era.

Some complexity is required as qemu does not bother to notify whether
the job was concluded successfully or failed. Thus it's necessary to
re-query the monitor.

To minimize the possibility of stuck jobs save the state into the XML
prior to handling everything so that the reconnect code can potentially
continue with the cleanup.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 123 ++-
 1 file changed, 122 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 020e7b3994..6aa8b1df51 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -390,6 +390,124 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
 }


+static int
+qemuBlockJobEventProcessConcluded(qemuBlockJobDataPtr job,
+  virQEMUDriverPtr driver,
+  virDomainObjPtr vm,
+  qemuDomainAsyncJob asyncJob,
+  virQEMUDriverConfigPtr cfg)
+{
+qemuMonitorJobInfoPtr *jobinfo = NULL;
+size_t njobinfo = 0;
+size_t i;
+int ret = -1;
+int rc = 0;
+bool refreshstate = job->state == QEMU_BLOCKJOB_STATE_CONCLUDED;
+
+if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+goto cleanup;
+
+/* fetch job state */
+if (refreshstate)
+rc = qemuMonitorGetJobInfo(qemuDomainGetMonitor(vm), &jobinfo, 
&njobinfo);
+/* dismiss job in qemu */
+if (rc >= 0)
+rc = qemuMonitorJobDismiss(qemuDomainGetMonitor(vm), job->name);
+
+if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
+goto cleanup;
+
+/* we need to fetch the error state as the event does not propagate it */
+if (refreshstate) {
+for (i = 0; i < njobinfo; i++) {
+if (STRNEQ_NULLABLE(job->name, jobinfo[i]->id))
+continue;
+
+if (VIR_STRDUP(job->errmsg, jobinfo[i]->error) < 0)
+goto cleanup;
+}
+
+if (i == njobinfo) {
+virReportError(VIR_ERR_INTERNAL_ERROR, _("failed to refresh job 
'%s'"),
+   job->name);
+goto cleanup;
+}
+
+if (job->errmsg)
+job->state = QEMU_BLOCKJOB_STATE_FAILED;
+else
+job->state = QEMU_BLOCKJOB_STATE_COMPLETED;
+
+/* write status XML */
+if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, 
driver->caps) < 0)
+VIR_WARN("Unable to save status on vm %s after block job", 
vm->def->name);
+}
+
+/* TODO: implement handlers for job types */
+switch (job->type) {
+case QEMU_BLOCKJOB_TYPE_PULL:
+case QEMU_BLOCKJOB_TYPE_COPY:
+case QEMU_BLOCKJOB_TYPE_COMMIT:
+case QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT:
+case QEMU_BLOCKJOB_TYPE_NONE:
+case QEMU_BLOCKJOB_TYPE_INTERNAL:
+case QEMU_BLOCKJOB_TYPE_LAST:
+break;
+}
+
+ret = 0;
+
+ cleanup:
+for (i = 0; i < njobinfo; i++)
+qemuMonitorJobInfoFree(jobinfo[i]);
+VIR_FREE(jobinfo);
+
+return ret;
+}
+
+
+static void
+qemuBlockJobEventProcess(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ qemuBlockJobDataPtr job,
+ qemuDomainAsyncJob asyncJob)
+
+{
+virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+
+switch (job->newstate) {
+case QEMU_BLOCKJOB_STATE_COMPLETED:
+case QEMU_BLOCKJOB_STATE_FAILED:
+case QEMU_BLOCKJOB_STATE_CANCELLED:
+case QEMU_BLOCKJOB_STATE_CONCLUDED:
+qemuBlockJobEventProcessConcluded(job, driver, vm, asyncJob, cfg);
+break;
+
+case QEMU_BLOCKJOB_STATE_READY:
+if (job->disk && job->disk->mirror) {
+job->disk->mirrorState = VIR_DOMAIN_BLOCK_JOB_READY;
+qemuBlockJobEmitEvents(driver, vm, job->disk, job->type, 
job->newstate);
+}
+job->state = job->newstate;
+break;
+
+case QEMU_BLOCKJOB_STATE_NEW:
+case QEMU_BLOCKJOB_STATE_RUNNING:
+case QEMU_BLOCKJOB_STATE_LAST:
+goto cleanup;
+}
+
+/* write status XML */
+if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 
0)
+VIR_WARN("Unable to save status on vm %s after block job", 
vm->def->name);
+
+ cleanup:
+job->newstate = -1;
+virObjectUnref(cfg);
+return;
+}
+
+
 /**
  * qemuBlockJobUpdateDisk:
  * @vm: domain
@@ -411,7 +529,10 @@ qemuBlockJobUpdate(virDomainObjPtr vm,
 if (job->newstate == -1)
 return -1;

-qemuBlockJobEventProcessLegacy(priv->driver, vm, job, asyncJob);
+if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
+qemuBlockJobEventProcess(priv->driver, vm, job, asyncJob);
+else
+qemuBlockJobEventProcessLegacy(priv->driver, vm, job, asyncJob);

 return job->state;
 }
-- 
2.19.2

--
libvir-list mailing list
li

[libvirt] [PATCH RFC 41/51] qemu: monitor: Add support for 'job-dismiss' command

2018-12-12 Thread Peter Krempa
This belongs to the new job management API which can manage also
non-block based jobs.

The dismiss command is meant to remove a concluded job after we were
able to get the final status.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 27 +++
 src/qemu/qemu_monitor_json.h |  4 
 tests/qemumonitorjsontest.c  |  2 ++
 5 files changed, 49 insertions(+)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 23579b98ee..6b73b97334 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3485,6 +3485,18 @@ qemuMonitorGetBlockJobInfo(qemuMonitorPtr mon,
 }


+int
+qemuMonitorJobDismiss(qemuMonitorPtr mon,
+  const char *jobname)
+{
+VIR_DEBUG("jobname=%s", jobname);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONJobDismiss(mon, jobname);
+}
+
+
 int
 qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
   const char *drivealias,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 64a7086a00..04ddc763a4 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -945,6 +945,10 @@ int qemuMonitorGetBlockJobInfo(qemuMonitorPtr mon,
qemuMonitorBlockJobInfoPtr info)
 ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);

+int qemuMonitorJobDismiss(qemuMonitorPtr mon,
+  const char *jobname)
+ATTRIBUTE_NONNULL(2);
+
 int qemuMonitorOpenGraphics(qemuMonitorPtr mon,
 const char *protocol,
 int fd,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 24388dab3b..bcbab10d90 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4956,6 +4956,33 @@ qemuMonitorJSONDrivePivot(qemuMonitorPtr mon,
 }


+int
+qemuMonitorJSONJobDismiss(qemuMonitorPtr mon,
+  const char *jobname)
+{
+int ret = -1;
+virJSONValuePtr cmd;
+virJSONValuePtr reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("job-dismiss",
+   "s:id", jobname,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+goto cleanup;
+
+if (qemuMonitorJSONBlockJobError(cmd, reply, jobname) < 0)
+goto cleanup;
+
+ret = 0;
+ cleanup:
+virJSONValueFree(cmd);
+virJSONValueFree(reply);
+return ret;
+}
+
+
 int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
 const char *protocol,
 const char *fdname,
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index df772e64c1..ec44292fab 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -332,6 +332,10 @@ int qemuMonitorJSONBlockJobSetSpeed(qemuMonitorPtr mon,
 virHashTablePtr qemuMonitorJSONGetAllBlockJobInfo(qemuMonitorPtr mon)
 ATTRIBUTE_NONNULL(1);

+int qemuMonitorJSONJobDismiss(qemuMonitorPtr mon,
+  const char *jobname)
+ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 int qemuMonitorJSONSetLink(qemuMonitorPtr mon,
const char *name,
virDomainNetInterfaceLinkState state);
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index 2ac4ca1f69..4132182a5d 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -1359,6 +1359,7 @@ GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayOpen, "foodev", 
true)
 GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayClose, "foodev")
 GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumRemove, "foodev")
 GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumInsert, "foodev", "newnode")
+GEN_TEST_FUNC(qemuMonitorJSONJobDismiss, "jobname")

 static bool
 testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(struct 
qemuMonitorQueryCpusEntry *a,
@@ -3005,6 +3006,7 @@ mymain(void)
 DO_TEST_GEN(qemuMonitorJSONBlockdevTrayClose);
 DO_TEST_GEN(qemuMonitorJSONBlockdevMediumRemove);
 DO_TEST_GEN(qemuMonitorJSONBlockdevMediumInsert);
+DO_TEST_GEN(qemuMonitorJSONJobDismiss);
 DO_TEST(qemuMonitorJSONGetBalloonInfo);
 DO_TEST(qemuMonitorJSONGetBlockInfo);
 DO_TEST(qemuMonitorJSONGetAllBlockStatsInfo);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 45/51] qemu: blockjob: Add 'concluded' state for a block job

2018-12-12 Thread Peter Krempa
This new state is entered when qemu finished the job but libvirt does
not know whether it was successful or not.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 2 +-
 src/qemu/qemu_blockjob.h | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 24a0efe36f..ee545fc8de 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -45,7 +45,7 @@ VIR_LOG_INIT("qemu.qemu_blockjob");
 /* Note that qemuBlockjobState and qemuBlockjobType values are formatted into
  * the status XML */
 VIR_ENUM_IMPL(qemuBlockjobState, QEMU_BLOCKJOB_STATE_LAST,
-  "completed", "failed", "cancelled", "ready", "new", "running");
+  "completed", "failed", "cancelled", "ready", "new", "running", 
"concluded");

 VIR_ENUM_IMPL(qemuBlockjob, QEMU_BLOCKJOB_TYPE_LAST,
   "", "pull", "copy", "commit", "active-commit", "");
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index d1e94dc066..c8a6d8cf4c 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -37,6 +37,8 @@ typedef enum {
 QEMU_BLOCKJOB_STATE_READY = VIR_DOMAIN_BLOCK_JOB_READY,
 QEMU_BLOCKJOB_STATE_NEW = VIR_DOMAIN_BLOCK_JOB_LAST,
 QEMU_BLOCKJOB_STATE_RUNNING,
+QEMU_BLOCKJOB_STATE_CONCLUDED, /* job has finished, but it's unknown
+  whether it has failed or not */
 QEMU_BLOCKJOB_STATE_LAST
 } qemuBlockjobState;
 verify((int)QEMU_BLOCKJOB_STATE_NEW == VIR_DOMAIN_BLOCK_JOB_LAST);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 40/51] qemu: monitor: Add new fields for 'blockdev-mirror' command

2018-12-12 Thread Peter Krempa
Allow using the delayed dismiss of the job so that we can reap the state
even if libvirtd was not running when qemu emitted the job completion
event.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_migration.c|  2 +-
 src/qemu/qemu_monitor.c  |  9 +
 src/qemu/qemu_monitor.h  |  3 ++-
 src/qemu/qemu_monitor_json.c | 10 ++
 src/qemu/qemu_monitor_json.h |  3 ++-
 tests/qemumonitorjsontest.c  |  2 +-
 6 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 87eeec3d84..f8daa2bce0 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -831,7 +831,7 @@ qemuMigrationSrcNBDStorageCopyBlockdev(virQEMUDriverPtr 
driver,
 mon_ret = qemuBlockStorageSourceAttachApply(qemuDomainGetMonitor(vm), 
data);

 if (mon_ret == 0)
-mon_ret = qemuMonitorBlockdevMirror(qemuDomainGetMonitor(vm), NULL,
+mon_ret = qemuMonitorBlockdevMirror(qemuDomainGetMonitor(vm), NULL, 
false,
 diskAlias, copysrc->nodeformat,
 mirror_speed, 0, 0, mirror_flags);

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index fe8d8d1bf7..23579b98ee 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3247,6 +3247,7 @@ qemuMonitorDriveMirror(qemuMonitorPtr mon,
 int
 qemuMonitorBlockdevMirror(qemuMonitorPtr mon,
   const char *jobname,
+  bool persistjob,
   const char *device,
   const char *target,
   unsigned long long bandwidth,
@@ -3254,15 +3255,15 @@ qemuMonitorBlockdevMirror(qemuMonitorPtr mon,
   unsigned long long buf_size,
   unsigned int flags)
 {
-VIR_DEBUG("jobname=%s, device=%s, target=%s, bandwidth=%lld, "
+VIR_DEBUG("jobname=%s, persistjob=%d, device=%s, target=%s, 
bandwidth=%lld, "
   "granularity=%#x, buf_size=%lld, flags=0x%x",
-  NULLSTR(jobname), device, target, bandwidth, granularity,
+  NULLSTR(jobname), persistjob, device, target, bandwidth, 
granularity,
   buf_size, flags);

 QEMU_CHECK_MONITOR(mon);

-return qemuMonitorJSONBlockdevMirror(mon, jobname, device, target, 
bandwidth,
- granularity, buf_size, flags);
+return qemuMonitorJSONBlockdevMirror(mon, jobname, persistjob, device, 
target,
+ bandwidth, granularity, buf_size, 
flags);
 }


diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 9cbd442f6c..64a7086a00 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -864,13 +864,14 @@ int qemuMonitorDriveMirror(qemuMonitorPtr mon,
 ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
 int qemuMonitorBlockdevMirror(qemuMonitorPtr mon,
   const char *jobname,
+  bool persistjob,
   const char *device,
   const char *target,
   unsigned long long bandwidth,
   unsigned int granularity,
   unsigned long long buf_size,
   unsigned int flags)
-ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
+ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
 int qemuMonitorDrivePivot(qemuMonitorPtr mon,
   const char *jobname)
 ATTRIBUTE_NONNULL(2);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 03e14ad79c..24388dab3b 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4303,6 +4303,7 @@ qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
 int
 qemuMonitorJSONBlockdevMirror(qemuMonitorPtr mon,
   const char *jobname,
+  bool persistjob,
   const char *device,
   const char *target,
   unsigned long long speed,
@@ -4314,6 +4315,13 @@ qemuMonitorJSONBlockdevMirror(qemuMonitorPtr mon,
 virJSONValuePtr cmd;
 virJSONValuePtr reply = NULL;
 bool shallow = (flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) != 0;
+virTristateBool autofinalize = VIR_TRISTATE_BOOL_ABSENT;
+virTristateBool autodismiss = VIR_TRISTATE_BOOL_ABSENT;
+
+if (persistjob) {
+autofinalize = VIR_TRISTATE_BOOL_YES;
+autodismiss = VIR_TRISTATE_BOOL_NO;
+}

 cmd = qemuMonitorJSONMakeCommand("blockdev-mirror",
  "S:job-id", jobname,
@@ -4323,6 +4331,8 @@ qemuMonitorJSONBlockdevMirror(qemuMonitorPtr mon,
  "z:granularity", granularity,
  "P:buf-size", buf_size,
  "s:sync", shallow ? "top" : "f

[libvirt] [PATCH RFC 42/51] qemu: monitor: Add support for 'job-cancel' command

2018-12-12 Thread Peter Krempa
This belongs to the new job management API which can manage also
non-block based jobs.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 27 +++
 src/qemu/qemu_monitor_json.h |  4 
 tests/qemumonitorjsontest.c  |  2 ++
 5 files changed, 49 insertions(+)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 6b73b97334..294b2a3785 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3497,6 +3497,18 @@ qemuMonitorJobDismiss(qemuMonitorPtr mon,
 }


+int
+qemuMonitorJobCancel(qemuMonitorPtr mon,
+ const char *jobname)
+{
+VIR_DEBUG("jobname=%s", jobname);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONJobCancel(mon, jobname);
+}
+
+
 int
 qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
   const char *drivealias,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 04ddc763a4..13ba7be304 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -949,6 +949,10 @@ int qemuMonitorJobDismiss(qemuMonitorPtr mon,
   const char *jobname)
 ATTRIBUTE_NONNULL(2);

+int qemuMonitorJobCancel(qemuMonitorPtr mon,
+ const char *jobname)
+ATTRIBUTE_NONNULL(2);
+
 int qemuMonitorOpenGraphics(qemuMonitorPtr mon,
 const char *protocol,
 int fd,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index bcbab10d90..d780a916a6 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4983,6 +4983,33 @@ qemuMonitorJSONJobDismiss(qemuMonitorPtr mon,
 }


+int
+qemuMonitorJSONJobCancel(qemuMonitorPtr mon,
+ const char *jobname)
+{
+int ret = -1;
+virJSONValuePtr cmd;
+virJSONValuePtr reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("job-cancel",
+   "s:id", jobname,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+goto cleanup;
+
+if (qemuMonitorJSONBlockJobError(cmd, reply, jobname) < 0)
+goto cleanup;
+
+ret = 0;
+ cleanup:
+virJSONValueFree(cmd);
+virJSONValueFree(reply);
+return ret;
+}
+
+
 int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
 const char *protocol,
 const char *fdname,
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index ec44292fab..5c6228e88a 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -336,6 +336,10 @@ int qemuMonitorJSONJobDismiss(qemuMonitorPtr mon,
   const char *jobname)
 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);

+int qemuMonitorJSONJobCancel(qemuMonitorPtr mon,
+ const char *jobname)
+ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 int qemuMonitorJSONSetLink(qemuMonitorPtr mon,
const char *name,
virDomainNetInterfaceLinkState state);
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index 4132182a5d..7065f0f49b 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -1360,6 +1360,7 @@ GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayClose, "foodev")
 GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumRemove, "foodev")
 GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumInsert, "foodev", "newnode")
 GEN_TEST_FUNC(qemuMonitorJSONJobDismiss, "jobname")
+GEN_TEST_FUNC(qemuMonitorJSONJobCancel, "jobname")

 static bool
 testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(struct 
qemuMonitorQueryCpusEntry *a,
@@ -3007,6 +3008,7 @@ mymain(void)
 DO_TEST_GEN(qemuMonitorJSONBlockdevMediumRemove);
 DO_TEST_GEN(qemuMonitorJSONBlockdevMediumInsert);
 DO_TEST_GEN(qemuMonitorJSONJobDismiss);
+DO_TEST_GEN(qemuMonitorJSONJobCancel);
 DO_TEST(qemuMonitorJSONGetBalloonInfo);
 DO_TEST(qemuMonitorJSONGetBlockInfo);
 DO_TEST(qemuMonitorJSONGetAllBlockStatsInfo);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 43/51] qemu: monitor: Add support for 'job-complete' command

2018-12-12 Thread Peter Krempa
This belongs to the new job management API which can manage also
non-block based jobs.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_monitor.c  | 12 
 src/qemu/qemu_monitor.h  |  4 
 src/qemu/qemu_monitor_json.c | 27 +++
 src/qemu/qemu_monitor_json.h |  4 
 tests/qemumonitorjsontest.c  |  2 ++
 5 files changed, 49 insertions(+)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 294b2a3785..398d3b4d8b 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3509,6 +3509,18 @@ qemuMonitorJobCancel(qemuMonitorPtr mon,
 }


+int
+qemuMonitorJobComplete(qemuMonitorPtr mon,
+   const char *jobname)
+{
+VIR_DEBUG("jobname=%s", jobname);
+
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONJobComplete(mon, jobname);
+}
+
+
 int
 qemuMonitorSetBlockIoThrottle(qemuMonitorPtr mon,
   const char *drivealias,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 13ba7be304..7feed8a427 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -953,6 +953,10 @@ int qemuMonitorJobCancel(qemuMonitorPtr mon,
  const char *jobname)
 ATTRIBUTE_NONNULL(2);

+int qemuMonitorJobComplete(qemuMonitorPtr mon,
+   const char *jobname)
+ATTRIBUTE_NONNULL(2);
+
 int qemuMonitorOpenGraphics(qemuMonitorPtr mon,
 const char *protocol,
 int fd,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index d780a916a6..0a63cff7e2 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -5010,6 +5010,33 @@ qemuMonitorJSONJobCancel(qemuMonitorPtr mon,
 }


+int
+qemuMonitorJSONJobComplete(qemuMonitorPtr mon,
+   const char *jobname)
+{
+int ret = -1;
+virJSONValuePtr cmd;
+virJSONValuePtr reply = NULL;
+
+if (!(cmd = qemuMonitorJSONMakeCommand("job-complete",
+   "s:id", jobname,
+   NULL)))
+return -1;
+
+if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+goto cleanup;
+
+if (qemuMonitorJSONBlockJobError(cmd, reply, jobname) < 0)
+goto cleanup;
+
+ret = 0;
+ cleanup:
+virJSONValueFree(cmd);
+virJSONValueFree(reply);
+return ret;
+}
+
+
 int qemuMonitorJSONOpenGraphics(qemuMonitorPtr mon,
 const char *protocol,
 const char *fdname,
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 5c6228e88a..8de1d8d547 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -340,6 +340,10 @@ int qemuMonitorJSONJobCancel(qemuMonitorPtr mon,
  const char *jobname)
 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);

+int qemuMonitorJSONJobComplete(qemuMonitorPtr mon,
+   const char *jobname)
+ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
 int qemuMonitorJSONSetLink(qemuMonitorPtr mon,
const char *name,
virDomainNetInterfaceLinkState state);
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index 7065f0f49b..5284fe60c6 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -1361,6 +1361,7 @@ GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumRemove, 
"foodev")
 GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumInsert, "foodev", "newnode")
 GEN_TEST_FUNC(qemuMonitorJSONJobDismiss, "jobname")
 GEN_TEST_FUNC(qemuMonitorJSONJobCancel, "jobname")
+GEN_TEST_FUNC(qemuMonitorJSONJobComplete, "jobname")

 static bool
 testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(struct 
qemuMonitorQueryCpusEntry *a,
@@ -3009,6 +3010,7 @@ mymain(void)
 DO_TEST_GEN(qemuMonitorJSONBlockdevMediumInsert);
 DO_TEST_GEN(qemuMonitorJSONJobDismiss);
 DO_TEST_GEN(qemuMonitorJSONJobCancel);
+DO_TEST_GEN(qemuMonitorJSONJobComplete);
 DO_TEST(qemuMonitorJSONGetBalloonInfo);
 DO_TEST(qemuMonitorJSONGetBlockInfo);
 DO_TEST(qemuMonitorJSONGetAllBlockStatsInfo);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 44/51] qemu: monitor: Add infrastructure for 'query-jobs'

2018-12-12 Thread Peter Krempa
Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_monitor.c   | 23 +
 src/qemu/qemu_monitor.h   | 49 ++
 src/qemu/qemu_monitor_json.c  | 86 ++
 src/qemu/qemu_monitor_json.h  |  6 ++
 .../query-jobs-create.json| 20 +
 .../query-jobs-create.result  | 11 +++
 .../qemumonitorjsondata/query-jobs-empty.json |  1 +
 .../query-jobs-empty.result   |  0
 tests/qemumonitorjsontest.c   | 89 +++
 9 files changed, 285 insertions(+)
 create mode 100644 tests/qemumonitorjsondata/query-jobs-create.json
 create mode 100644 tests/qemumonitorjsondata/query-jobs-create.result
 create mode 100644 tests/qemumonitorjsondata/query-jobs-empty.json
 create mode 100644 tests/qemumonitorjsondata/query-jobs-empty.result

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 398d3b4d8b..7d061a48ab 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4505,3 +4505,26 @@ qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon,
 virHashFree(info);
 return ret;
 }
+
+
+void
+qemuMonitorJobInfoFree(qemuMonitorJobInfoPtr job)
+{
+if (!job)
+return;
+
+VIR_FREE(job->id);
+VIR_FREE(job->error);
+VIR_FREE(job);
+}
+
+
+int
+qemuMonitorGetJobInfo(qemuMonitorPtr mon,
+  qemuMonitorJobInfoPtr **jobs,
+  size_t *njobs)
+{
+QEMU_CHECK_MONITOR(mon);
+
+return qemuMonitorJSONGetJobInfo(mon, jobs, njobs);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 7feed8a427..e51177bf44 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -109,6 +109,49 @@ struct _qemuMonitorEventPanicInfo {
 } data;
 };

+
+typedef enum {
+QEMU_MONITOR_JOB_TYPE_UNKNOWN, /* internal value, not exposed by qemu */
+QEMU_MONITOR_JOB_TYPE_COMMIT,
+QEMU_MONITOR_JOB_TYPE_STREAM,
+QEMU_MONITOR_JOB_TYPE_MIRROR,
+QEMU_MONITOR_JOB_TYPE_BACKUP,
+QEMU_MONITOR_JOB_TYPE_CREATE,
+QEMU_MONITOR_JOB_TYPE_LAST
+} qemuMonitorJobType;
+
+VIR_ENUM_DECL(qemuMonitorJob)
+
+typedef enum {
+QEMU_MONITOR_JOB_STATUS_UNKNOWN, /* internal value, not exposed by qemu */
+QEMU_MONITOR_JOB_STATUS_CREATED,
+QEMU_MONITOR_JOB_STATUS_RUNNING,
+QEMU_MONITOR_JOB_STATUS_PAUSED,
+QEMU_MONITOR_JOB_STATUS_READY,
+QEMU_MONITOR_JOB_STATUS_STANDBY,
+QEMU_MONITOR_JOB_STATUS_WAITING,
+QEMU_MONITOR_JOB_STATUS_PENDING,
+QEMU_MONITOR_JOB_STATUS_ABORTING,
+QEMU_MONITOR_JOB_STATUS_CONCLUDED,
+QEMU_MONITOR_JOB_STATUS_UNDEFINED, /* the job states below should not be 
visible outside of qemu */
+QEMU_MONITOR_JOB_STATUS_NULL,
+QEMU_MONITOR_JOB_STATUS_LAST
+} qemuMonitorJobStatus;
+
+VIR_ENUM_DECL(qemuMonitorJobStatus)
+
+typedef struct _qemuMonitorJobInfo qemuMonitorJobInfo;
+typedef qemuMonitorJobInfo *qemuMonitorJobInfoPtr;
+struct _qemuMonitorJobInfo {
+char *id;
+qemuMonitorJobType type;
+qemuMonitorJobStatus status;
+char *error;
+long long progressCurrent;
+long long progressTotal;
+};
+
+
 char *qemuMonitorGuestPanicEventInfoFormatMsg(qemuMonitorEventPanicInfoPtr 
info);
 void qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfoPtr info);

@@ -1217,4 +1260,10 @@ struct _qemuMonitorPRManagerInfo {
 int qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon,
 virHashTablePtr *retinfo);

+void qemuMonitorJobInfoFree(qemuMonitorJobInfoPtr job);
+
+int qemuMonitorGetJobInfo(qemuMonitorPtr mon,
+  qemuMonitorJobInfoPtr **jobs,
+  size_t *njobs);
+
 #endif /* QEMU_MONITOR_H */
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 0a63cff7e2..101e6ec7cd 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -58,6 +58,12 @@ VIR_LOG_INIT("qemu.qemu_monitor_json");

 #define LINE_ENDING "\r\n"

+VIR_ENUM_IMPL(qemuMonitorJob, QEMU_MONITOR_JOB_TYPE_LAST,
+  "", "commit", "stream", "mirror", "backup", "create");
+VIR_ENUM_IMPL(qemuMonitorJobStatus, QEMU_MONITOR_JOB_STATUS_LAST,
+  "", "created", "running", "paused", "ready", "standby", 
"waiting",
+  "pending", "aborting", "concluded", "undefined", "null");
+
 static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr 
data);
 static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr 
data);
 static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr 
data);
@@ -8567,3 +8573,83 @@ qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
 return ret;

 }
+
+
+static qemuMonitorJobInfoPtr
+qemuMonitorJSONGetJobInfoOne(virJSONValuePtr data)
+{
+const char *id = virJSONValueObjectGetString(data, "id");
+const char *type = virJSONValueObjectGetString(data, "type");
+const char *status = virJSONValueObjectGetString(data, "status");
+const char 

[libvirt] [PATCH RFC 11/51] qemu: migration: Properly note that non-shared-storage migration uses a blockjob

2018-12-12 Thread Peter Krempa
Internally we do a 'block-copy' to accomodate non-shared storage
migration but the code did not fill in that the block job was active on
the disk when starting the copy job. Since we handle block jobs finishes
regardless of having it registered it's not a problem but soon will
become one.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_migration.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 8720b34311..5d2eb60f03 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -977,6 +977,7 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver,

 VIR_FREE(diskAlias);
 diskPriv->migrating = true;
+diskPriv->blockjob->started = true;

 if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, 
driver->caps) < 0) {
 VIR_WARN("Failed to save status on vm %s", vm->def->name);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 39/51] qemu: monitor: Add new fields for 'block-commit' command

2018-12-12 Thread Peter Krempa
Allow using the node name to specify the base and top of the 'commit'
operation, allow specifying explicit job name and add support for
delayed dismiss of the job so that we can reap the state even if
libvirtd was not running when qemu emitted the job completion event.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_driver.c   |  4 ++--
 src/qemu/qemu_monitor.c  | 21 +++--
 src/qemu/qemu_monitor.h  |  6 +-
 src/qemu/qemu_monitor_json.c | 22 --
 src/qemu/qemu_monitor_json.h |  4 
 tests/qemumonitorjsontest.c  |  2 +-
 6 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 133bfcfbf3..f62d153c03 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -18226,8 +18226,8 @@ qemuDomainBlockCommit(virDomainPtr dom,
 topPath = qemuMonitorDiskNameLookup(priv->mon, device, disk->src,
 topSource);
 if (basePath && topPath)
-ret = qemuMonitorBlockCommit(priv->mon, device,
- topPath, basePath, backingPath,
+ret = qemuMonitorBlockCommit(priv->mon, device, NULL, false,
+ topPath, NULL, basePath, NULL, 
backingPath,
  speed);
 if (qemuDomainObjExitMonitor(driver, vm) < 0) {
 ret = -1;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index d6cad63863..fe8d8d1bf7 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3280,18 +3280,27 @@ qemuMonitorTransaction(qemuMonitorPtr mon, 
virJSONValuePtr *actions)

 /* Start a block-commit block job.  bandwidth is in bytes/sec.  */
 int
-qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
-   const char *top, const char *base,
+qemuMonitorBlockCommit(qemuMonitorPtr mon,
+   const char *device,
+   const char *jobname,
+   bool persistjob,
+   const char *top,
+   const char *topNode,
+   const char *base,
+   const char *baseNode,
const char *backingName,
unsigned long long bandwidth)
 {
-VIR_DEBUG("device=%s, top=%s, base=%s, backingName=%s, bandwidth=%llu",
-  device, top, base, NULLSTR(backingName), bandwidth);
+VIR_DEBUG("device=%s, jobname=%s, persistjob=%d, top=%s, topNode=%s, "
+  "base=%s, baseNode=%s, backingName=%s, bandwidth=%llu",
+  device, NULLSTR(jobname), persistjob, NULLSTR(top), 
NULLSTR(topNode),
+  NULLSTR(base), NULLSTR(baseNode), NULLSTR(backingName), 
bandwidth);

 QEMU_CHECK_MONITOR(mon);

-return qemuMonitorJSONBlockCommit(mon, device, top, base,
- backingName, bandwidth);
+return qemuMonitorJSONBlockCommit(mon, device, jobname, persistjob, top,
+  topNode, base, baseNode, backingName,
+  bandwidth);
 }


diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index bbdf88ae60..9cbd442f6c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -877,11 +877,15 @@ int qemuMonitorDrivePivot(qemuMonitorPtr mon,

 int qemuMonitorBlockCommit(qemuMonitorPtr mon,
const char *device,
+   const char *jobname,
+   bool persistjob,
const char *top,
+   const char *topNode,
const char *base,
+   const char *baseNode,
const char *backingName,
unsigned long long bandwidth)
-ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
+ATTRIBUTE_NONNULL(2);
 bool qemuMonitorSupportsActiveCommit(qemuMonitorPtr mon);
 char *qemuMonitorDiskNameLookup(qemuMonitorPtr mon,
 const char *device,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index fe16a3d13c..03e14ad79c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4401,21 +4401,39 @@ qemuMonitorJSONSupportsActiveCommit(qemuMonitorPtr mon)
 /* speed is in bytes/sec. Returns 0 on success, -1 with error message
  * emitted on failure. */
 int
-qemuMonitorJSONBlockCommit(qemuMonitorPtr mon, const char *device,
-   const char *top, const char *base,
+qemuMonitorJSONBlockCommit(qemuMonitorPtr mon,
+   const char *device,
+   const char *jobname,
+   bool persistjob,
+   const char *top,
+   const char *topNode,
+   const char *base,
+   const char *baseNode,

[libvirt] [PATCH RFC 35/51] qemu: blockjob: Add string convertors for blockjob type and state enums

2018-12-12 Thread Peter Krempa
Later on we'll format these values into the status XML so the from/to
string functions will come handy. The implementation also notes that
these will be used in the status XML to avoid somebody changing the
values.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 7 +++
 src/qemu/qemu_blockjob.h | 4 
 2 files changed, 11 insertions(+)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 97b9d7e5a6..24a0efe36f 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -42,6 +42,13 @@

 VIR_LOG_INIT("qemu.qemu_blockjob");

+/* Note that qemuBlockjobState and qemuBlockjobType values are formatted into
+ * the status XML */
+VIR_ENUM_IMPL(qemuBlockjobState, QEMU_BLOCKJOB_STATE_LAST,
+  "completed", "failed", "cancelled", "ready", "new", "running");
+
+VIR_ENUM_IMPL(qemuBlockjob, QEMU_BLOCKJOB_TYPE_LAST,
+  "", "pull", "copy", "commit", "active-commit", "");

 static virClassPtr qemuBlockJobDataClass;

diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 6f58d323d0..d1e94dc066 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -41,6 +41,8 @@ typedef enum {
 } qemuBlockjobState;
 verify((int)QEMU_BLOCKJOB_STATE_NEW == VIR_DOMAIN_BLOCK_JOB_LAST);

+VIR_ENUM_DECL(qemuBlockjobState)
+
 /**
  * This enum has to map all known block job types from enum 
virDomainBlockJobType
  * to the same values. All internal blockjobs can be mapped after and don't
@@ -57,6 +59,8 @@ typedef enum {
 } qemuBlockjobType;
 verify((int)QEMU_BLOCKJOB_TYPE_INTERNAL == VIR_DOMAIN_BLOCK_JOB_TYPE_LAST);

+VIR_ENUM_DECL(qemuBlockjob)
+
 typedef struct _qemuBlockJobData qemuBlockJobData;
 typedef qemuBlockJobData *qemuBlockJobDataPtr;

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 12/51] qemu: process: refresh block jobs on reconnect

2018-12-12 Thread Peter Krempa
Block job state was widely untracked by libvirt across restarts which
was allowed by a stateless block job finishing handler which discarded
disk state and redetected it. This is undesirable since we'll need to
track more information for individual blockjobs due to -blockdev
integration requirements.

In case of legacy blockjobs we can recover whether the job is present at
reconnect time by querying qemu. Adding tracking whether a job is
present will allow simplification of the non-shared-storage cancellation
code.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_process.c | 67 +
 1 file changed, 67 insertions(+)

diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 3fccbc79bb..471e5f 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -7755,6 +7755,70 @@ qemuProcessRefreshCPU(virQEMUDriverPtr driver,
 }


+static int
+qemuProcessRefreshLegacyBlockjob(void *payload,
+ const void *name,
+ void *opaque)
+{
+const char *jobname = name;
+virDomainObjPtr vm = opaque;
+qemuMonitorBlockJobInfoPtr info = payload;
+virDomainDiskDefPtr disk;
+qemuDomainDiskPrivatePtr diskPriv;
+qemuBlockJobDataPtr job;
+
+if (!(disk = qemuProcessFindDomainDiskByAliasOrQOM(vm, jobname, jobname))) 
{
+VIR_DEBUG("could not find disk for block job '%s'", jobname);
+return 0;
+}
+
+diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+job = diskPriv->blockjob;
+
+if (disk->mirror) {
+if (info->ready == 1 ||
+(info->ready == -1 && info->end == info->cur))
+disk->mirrorState = VIR_DOMAIN_BLOCK_JOB_READY;
+}
+
+job->started = true;
+job->status = -1;
+
+return 0;
+}
+
+
+static int
+qemuProcessRefreshLegacyBlockjobs(virQEMUDriverPtr driver,
+  virDomainObjPtr vm)
+{
+virHashTablePtr blockJobs = NULL;
+int ret = -1;
+
+qemuDomainObjEnterMonitor(driver, vm);
+blockJobs = qemuMonitorGetAllBlockJobInfo(qemuDomainGetMonitor(vm));
+if (qemuDomainObjExitMonitor(driver, vm) < 0 || !blockJobs)
+goto cleanup;
+
+if (virHashForEach(blockJobs, qemuProcessRefreshLegacyBlockjob, vm) < 0)
+goto cleanup;
+
+ret = 0;
+
+ cleanup:
+virHashFree(blockJobs);
+return ret;
+}
+
+
+static int
+qemuProcessRefreshBlockjobs(virQEMUDriverPtr driver,
+virDomainObjPtr vm)
+{
+return qemuProcessRefreshLegacyBlockjobs(driver, vm);
+}
+
+
 struct qemuProcessReconnectData {
 virQEMUDriverPtr driver;
 virDomainObjPtr obj;
@@ -7958,6 +8022,9 @@ qemuProcessReconnect(void *opaque)
 qemuBlockNodeNamesDetect(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
 goto error;

+if (qemuProcessRefreshBlockjobs(driver, obj) < 0)
+goto error;
+
 if (qemuRefreshVirtioChannelState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
 goto error;

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 16/51] qemu: blockjob: Clarify that job 'status' field contains new state

2018-12-12 Thread Peter Krempa
The field is used to note the state the job has transitioned to while
handling the blockjob state change event. Rename the field so that it's
obvious that this is the new state and not the general state of the
blockjob.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 12 ++--
 src/qemu/qemu_blockjob.h |  3 ++-
 src/qemu/qemu_driver.c   |  2 +-
 src/qemu/qemu_process.c  |  4 ++--
 4 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index cf1710a0e8..252f1640b2 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -261,22 +261,22 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,
 {
 qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
 qemuDomainObjPrivatePtr priv = vm->privateData;
-int status = job->status;
+int state = job->newstate;

 if (error)
 *error = NULL;

-if (status != -1) {
+if (state != -1) {
 qemuBlockJobEventProcessLegacy(priv->driver, vm, disk, asyncJob,
-   job->type, status);
-job->status = -1;
+   job->type, state);
+job->newstate = -1;
 if (error)
 VIR_STEAL_PTR(*error, job->errmsg);
 else
 VIR_FREE(job->errmsg);
 }

-return status;
+return state;
 }


@@ -300,7 +300,7 @@ qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk)

 VIR_DEBUG("disk=%s", disk->dst);
 job->synchronous = true;
-job->status = -1;
+job->newstate = -1;
 }


diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index de1ad7039d..7761eee6ae 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -34,9 +34,10 @@ struct _qemuBlockJobData {

 bool started;
 int type;
-int status;
 char *errmsg;
 bool synchronous; /* API call is waiting for this job */
+
+int newstate; /* virConnectDomainEventBlockJobStatus - new state to be 
processed */
 };

 qemuBlockJobDataPtr qemuBlockJobDataNew(void);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0598f6e5c7..637307806b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4734,7 +4734,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;

 job->type = type;
-job->status = status;
+job->newstate = status;

 qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk, NULL);

diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 471e5f..2cead713f6 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -942,7 +942,7 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon 
ATTRIBUTE_UNUSED,
 if (job->synchronous) {
 /* We have a SYNC API waiting for this event, dispatch it back */
 job->type = type;
-job->status = status;
+job->newstate = status;
 VIR_FREE(job->errmsg);
 ignore_value(VIR_STRDUP_QUIET(job->errmsg, error));
 virDomainObjBroadcast(vm);
@@ -7782,7 +7782,7 @@ qemuProcessRefreshLegacyBlockjob(void *payload,
 }

 job->started = true;
-job->status = -1;
+job->newstate = -1;

 return 0;
 }
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 10/51] qemu: blockjob: Split out handling of comlpleted jobs

2018-12-12 Thread Peter Krempa
qemuBlockJobEventProcessLegacy was getting too big. Remove handling of
completed jobs in a separate function.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 118 +--
 1 file changed, 65 insertions(+), 53 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 5934d58480..a7cdc3c068 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -80,6 +80,70 @@ qemuBlockJobEmitEvents(virQEMUDriverPtr driver,
 }


+static void
+qemuBlockJobEventProcessLegacyCompleted(virQEMUDriverPtr driver,
+virDomainObjPtr vm,
+virDomainDiskDefPtr disk,
+int asyncJob)
+{
+qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+virDomainDiskDefPtr persistDisk = NULL;
+
+if (disk->mirrorState == VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT) {
+if (vm->newDef) {
+virStorageSourcePtr copy = NULL;
+
+if ((persistDisk = virDomainDiskByName(vm->newDef,
+   disk->dst, false))) {
+copy = virStorageSourceCopy(disk->mirror, false);
+if (!copy ||
+virStorageSourceInitChainElement(copy,
+ persistDisk->src,
+ true) < 0) {
+VIR_WARN("Unable to update persistent definition "
+ "on vm %s after block job",
+ vm->def->name);
+virStorageSourceFree(copy);
+copy = NULL;
+persistDisk = NULL;
+}
+}
+if (copy) {
+virStorageSourceFree(persistDisk->src);
+persistDisk->src = copy;
+}
+}
+
+/* XXX We want to revoke security labels as well as audit that
+ * revocation, before dropping the original source.  But it gets
+ * tricky if both source and mirror share common backing files (we
+ * want to only revoke the non-shared portion of the chain); so for
+ * now, we leak the access to the original.  */
+virDomainLockImageDetach(driver->lockManager, vm, disk->src);
+virStorageSourceFree(disk->src);
+disk->src = disk->mirror;
+} else {
+if (disk->mirror) {
+virDomainLockImageDetach(driver->lockManager, vm, disk->mirror);
+virStorageSourceFree(disk->mirror);
+}
+}
+
+/* Recompute the cached backing chain to match our
+ * updates.  Better would be storing the chain ourselves
+ * rather than reprobing, but we haven't quite completed
+ * that conversion to use our XML tracking. */
+disk->mirror = NULL;
+disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
+disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
+disk->src->id = 0;
+virStorageSourceBackingStoreClear(disk->src);
+ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk, true));
+ignore_value(qemuBlockNodeNamesDetect(driver, vm, asyncJob));
+diskPriv->blockjob->started = false;
+}
+
+
 /**
  * qemuBlockJobEventProcessLegacy:
  * @driver: qemu driver
@@ -101,7 +165,6 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
int status)
 {
 virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-virDomainDiskDefPtr persistDisk = NULL;
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);

 VIR_DEBUG("disk=%s, mirrorState=%s, type=%d, status=%d",
@@ -120,58 +183,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
  * to match.  */
 switch ((virConnectDomainEventBlockJobStatus) status) {
 case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
-if (disk->mirrorState == VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT) {
-if (vm->newDef) {
-virStorageSourcePtr copy = NULL;
-
-if ((persistDisk = virDomainDiskByName(vm->newDef,
-   disk->dst, false))) {
-copy = virStorageSourceCopy(disk->mirror, false);
-if (!copy ||
-virStorageSourceInitChainElement(copy,
- persistDisk->src,
- true) < 0) {
-VIR_WARN("Unable to update persistent definition "
- "on vm %s after block job",
- vm->def->name);
-virStorageSourceFree(copy);
-copy = NULL;
-persistDisk = NULL;
-}
-}
-if (copy) {
-virStorageSourceFree(persistDisk->src);
-  

[libvirt] [PATCH RFC 07/51] qemu: Consolidate disk blockjob variables into a structure

2018-12-12 Thread Peter Krempa
Struct qemuDomainDiskPrivate was holding multiple variables connected to
a disk block job. Consolidate them into a new struct qemuBlockJobData.

This will also allow simpler extensions to the block job mechanisms.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 36 +++-
 src/qemu/qemu_blockjob.h | 15 +++
 src/qemu/qemu_domain.c   | 12 +---
 src/qemu/qemu_domain.h   |  9 ++---
 src/qemu/qemu_driver.c   | 16 
 src/qemu/qemu_process.c  | 15 ---
 6 files changed, 65 insertions(+), 38 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 1b6d16cbb9..b1a30b1edb 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -42,6 +42,17 @@
 VIR_LOG_INIT("qemu.qemu_blockjob");


+void
+qemuBlockJobDataFree(qemuBlockJobDataPtr job)
+{
+if (!job)
+return;
+
+VIR_FREE(job->errmsg);
+VIR_FREE(job);
+}
+
+
 /**
  * qemuBlockJobEmitEvents:
  *
@@ -160,7 +171,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
 virStorageSourceBackingStoreClear(disk->src);
 ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk, true));
 ignore_value(qemuBlockNodeNamesDetect(driver, vm, asyncJob));
-diskPriv->blockjob = false;
+diskPriv->blockjob->started = false;
 break;

 case VIR_DOMAIN_BLOCK_JOB_READY:
@@ -176,7 +187,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
 }
 disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
 disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
-diskPriv->blockjob = false;
+diskPriv->blockjob->started = false;
 break;

 case VIR_DOMAIN_BLOCK_JOB_LAST:
@@ -213,22 +224,21 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,
virDomainDiskDefPtr disk,
char **error)
 {
-qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
 qemuDomainObjPrivatePtr priv = vm->privateData;
-int status = diskPriv->blockJobStatus;
+int status = job->status;

 if (error)
 *error = NULL;

 if (status != -1) {
 qemuBlockJobEventProcess(priv->driver, vm, disk, asyncJob,
- diskPriv->blockJobType,
- diskPriv->blockJobStatus);
-diskPriv->blockJobStatus = -1;
+ job->type, status);
+job->status = -1;
 if (error)
-VIR_STEAL_PTR(*error, diskPriv->blockJobError);
+VIR_STEAL_PTR(*error, job->errmsg);
 else
-VIR_FREE(diskPriv->blockJobError);
+VIR_FREE(job->errmsg);
 }

 return status;
@@ -251,11 +261,11 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,
 void
 qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk)
 {
-qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;

 VIR_DEBUG("disk=%s", disk->dst);
-diskPriv->blockJobSync = true;
-diskPriv->blockJobStatus = -1;
+job->synchronous = true;
+job->status = -1;
 }


@@ -274,5 +284,5 @@ qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
 {
 VIR_DEBUG("disk=%s", disk->dst);
 qemuBlockJobUpdateDisk(vm, asyncJob, disk, NULL);
-QEMU_DOMAIN_DISK_PRIVATE(disk)->blockJobSync = false;
+QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob->synchronous = false;
 }
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 0c440757f2..1479c6f720 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -25,6 +25,21 @@
 # include "internal.h"
 # include "qemu_conf.h"

+
+typedef struct _qemuBlockJobData qemuBlockJobData;
+typedef qemuBlockJobData *qemuBlockJobDataPtr;
+
+struct _qemuBlockJobData {
+bool started;
+int type;
+int status;
+char *errmsg;
+bool synchronous; /* API call is waiting for this job */
+};
+
+void
+qemuBlockJobDataFree(qemuBlockJobDataPtr job);
+
 int qemuBlockJobUpdateDisk(virDomainObjPtr vm,
int asyncJob,
virDomainDiskDefPtr disk,
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 1eb0e31df0..5a64231f95 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1062,6 +1062,11 @@ qemuDomainDiskPrivateNew(void)
 if (!(priv = virObjectNew(qemuDomainDiskPrivateClass)))
 return NULL;

+if (VIR_ALLOC(priv->blockjob) < 0) {
+virObjectUnref(priv);
+priv = NULL;
+}
+
 return (virObjectPtr) priv;
 }

@@ -1070,10 +1075,10 @@ qemuDomainDiskPrivateDispose(void *obj)
 {
 qemuDomainDiskPrivatePtr priv = obj;

-VIR_FREE(priv->blockJobError);
 virStorageSourceFree(priv->migrSource);
 VIR_FREE(priv->qomName);
 VIR_FREE(priv->nodeCopyOnRead);
+qemuBlockJobDataFree(priv->blockjob);
 }

 static vir

[libvirt] [PATCH RFC 14/51] qemu: migration: Simplify cancellation of migration blockjobs

2018-12-12 Thread Peter Krempa
When cancelling job after a reconnect we can now use the disk block job
state rather than having to re-detect it in the migration code.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_migration.c | 63 +++
 1 file changed, 18 insertions(+), 45 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 5d2eb60f03..5f4fcb4bad 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -678,7 +678,9 @@ qemuMigrationSrcNBDCopyCancelOne(virQEMUDriverPtr driver,
  * @check: if true report an error when some of the mirrors fails
  *
  * Cancel all drive-mirrors started by qemuMigrationSrcNBDStorageCopy.
- * Any pending block job events for the affected disks will be processed.
+ * Any pending block job events for the affected disks will be processed and
+ * synchronous block job terminated regardless of return value unless qemu
+ * has crashed.
  *
  * Returns 0 on success, -1 otherwise.
  */
@@ -701,6 +703,11 @@ qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver,
 virDomainDiskDefPtr disk = vm->def->disks[i];
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);

+if (!diskPriv->blockjob->started) {
+qemuBlockJobSyncEndDisk(vm, asyncJob, disk);
+diskPriv->migrating = false;
+}
+
 if (!diskPriv->migrating)
 continue;

@@ -5345,7 +5352,6 @@ qemuMigrationSrcCancel(virQEMUDriverPtr driver,
virDomainObjPtr vm)
 {
 qemuDomainObjPrivatePtr priv = vm->privateData;
-virHashTablePtr blockJobs = NULL;
 bool storage = false;
 size_t i;
 int ret = -1;
@@ -5353,67 +5359,34 @@ qemuMigrationSrcCancel(virQEMUDriverPtr driver,
 VIR_DEBUG("Canceling unfinished outgoing migration of domain %s",
   vm->def->name);

-for (i = 0; i < vm->def->ndisks; i++) {
-virDomainDiskDefPtr disk = vm->def->disks[i];
-if (QEMU_DOMAIN_DISK_PRIVATE(disk)->migrating) {
-qemuBlockJobSyncBeginDisk(disk);
-storage = true;
-}
-}
-
 qemuDomainObjEnterMonitor(driver, vm);
-
 ignore_value(qemuMonitorMigrateCancel(priv->mon));
-if (storage)
-blockJobs = qemuMonitorGetAllBlockJobInfo(priv->mon);
-
-if (qemuDomainObjExitMonitor(driver, vm) < 0 || (storage && !blockJobs))
-goto endsyncjob;
-
-if (!storage) {
-ret = 0;
+if (qemuDomainObjExitMonitor(driver, vm) < 0)
 goto cleanup;
-}

 for (i = 0; i < vm->def->ndisks; i++) {
 virDomainDiskDefPtr disk = vm->def->disks[i];
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);

-if (!diskPriv->migrating)
-continue;
-
-if (virHashLookup(blockJobs, disk->info.alias)) {
-VIR_DEBUG("Drive mirror on disk %s is still running", disk->dst);
-} else {
-VIR_DEBUG("Drive mirror on disk %s is gone", disk->dst);
-qemuBlockJobSyncEndDisk(vm, QEMU_ASYNC_JOB_NONE, disk);
+if (!diskPriv->blockjob->started)
 diskPriv->migrating = false;
+
+if (diskPriv->migrating) {
+qemuBlockJobSyncBeginDisk(disk);
+storage = true;
 }
 }

-if (qemuMigrationSrcNBDCopyCancel(driver, vm, false,
+
+if (storage &&
+qemuMigrationSrcNBDCopyCancel(driver, vm, false,
   QEMU_ASYNC_JOB_NONE, NULL) < 0)
-goto endsyncjob;
+goto cleanup;

 ret = 0;

  cleanup:
-virHashFree(blockJobs);
 return ret;
-
- endsyncjob:
-if (storage) {
-for (i = 0; i < vm->def->ndisks; i++) {
-virDomainDiskDefPtr disk = vm->def->disks[i];
-qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
-
-if (diskPriv->migrating) {
-qemuBlockJobSyncEndDisk(vm, QEMU_ASYNC_JOB_NONE, disk);
-diskPriv->migrating = false;
-}
-}
-}
-goto cleanup;
 }


-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 13/51] qemu: driver: Remove block job status reprobing from qemuDomainBlockPivot

2018-12-12 Thread Peter Krempa
Now that we reprobe the status of blockjobs when reconnecting in
addition to handling job status events, the status reprobing can be
removed as we always track the correct status internally.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_driver.c | 20 +---
 1 file changed, 1 insertion(+), 19 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d06eabb265..0598f6e5c7 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17090,9 +17090,8 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
  const char *device,
  virDomainDiskDefPtr disk)
 {
-int ret = -1, rc;
+int ret = -1;
 qemuDomainObjPrivatePtr priv = vm->privateData;
-qemuMonitorBlockJobInfo info;
 virStorageSourcePtr oldsrc = NULL;
 virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);

@@ -17103,23 +17102,6 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
 goto cleanup;
 }

-/* Probe the status, if needed.  */
-if (!disk->mirrorState) {
-qemuDomainObjEnterMonitor(driver, vm);
-rc = qemuMonitorGetBlockJobInfo(priv->mon, disk->info.alias, &info);
-if (qemuDomainObjExitMonitor(driver, vm) < 0)
-goto cleanup;
-if (rc < 0)
-goto cleanup;
-if (rc == 1 &&
-(info.ready == 1 ||
- (info.ready == -1 &&
-  info.end == info.cur &&
-  (info.type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY ||
-   info.type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT
-disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
-}
-
 if (disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_READY) {
 virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
_("disk '%s' not ready for pivot yet"),
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 32/51] qemu: blockjob: Add job name into the data

2018-12-12 Thread Peter Krempa
Currently the job name corresponds to the disk the job belongs to. For
jobs which will not correspond to disks we'll need to track the name
separately.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 20 
 src/qemu/qemu_blockjob.h  |  7 +--
 src/qemu/qemu_driver.c|  8 
 src/qemu/qemu_migration.c |  2 +-
 src/qemu/qemu_process.c   |  2 +-
 5 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index c98d393f4b..27e854e2b2 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -36,6 +36,7 @@
 #include "virtime.h"
 #include "locking/domain_lock.h"
 #include "viralloc.h"
+#include "virstring.h"

 #define VIR_FROM_THIS VIR_FROM_QEMU

@@ -50,6 +51,7 @@ qemuBlockJobDataDispose(void *obj)
 {
 qemuBlockJobDataPtr job = obj;

+VIR_FREE(job->name);
 VIR_FREE(job->errmsg);
 }

@@ -67,9 +69,11 @@ qemuBlockJobDataOnceInit(void)
 VIR_ONCE_GLOBAL_INIT(qemuBlockJobData)

 static qemuBlockJobDataPtr
-qemuBlockJobDataNew(qemuBlockjobType type)
+qemuBlockJobDataNew(qemuBlockjobType type,
+const char *name)
 {
 qemuBlockJobDataPtr job = NULL;
+qemuBlockJobDataPtr ret = NULL;

 if (qemuBlockJobDataInitialize() < 0)
 return NULL;
@@ -77,11 +81,18 @@ qemuBlockJobDataNew(qemuBlockjobType type)
 if (!(job = virObjectNew(qemuBlockJobDataClass)))
 return NULL;

+if (VIR_STRDUP(job->name, name) < 0)
+goto cleanup;
+
 job->state = QEMU_BLOCKJOB_STATE_NEW;
 job->newstate = -1;
 job->type = type;

-return job;
+VIR_STEAL_PTR(ret, job);
+
+ cleanup:
+virObjectUnref(job);
+return ret;
 }


@@ -95,11 +106,12 @@ qemuBlockJobDataNew(qemuBlockjobType type)
  */
 qemuBlockJobDataPtr
 qemuBlockJobDiskNew(virDomainDiskDefPtr disk,
-qemuBlockjobType type)
+qemuBlockjobType type,
+const char *jobname)
 {
 qemuBlockJobDataPtr job = NULL;

-if (!(job = qemuBlockJobDataNew(type)))
+if (!(job = qemuBlockJobDataNew(type, jobname)))
 return NULL;

 job->disk = disk;
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 0ec9fd17b7..f67b0f39be 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -63,6 +63,8 @@ typedef qemuBlockJobData *qemuBlockJobDataPtr;
 struct _qemuBlockJobData {
 virObject parent;

+char *name;
+
 virDomainDiskDefPtr disk; /* may be NULL, if blockjob does not corrspond 
to any disk */

 int type; /* qemuBlockjobType */
@@ -76,8 +78,9 @@ struct _qemuBlockJobData {

 qemuBlockJobDataPtr
 qemuBlockJobDiskNew(virDomainDiskDefPtr disk,
-qemuBlockjobType type)
-ATTRIBUTE_NONNULL(1);
+qemuBlockjobType type,
+const char *jobname)
+ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);

 qemuBlockJobDataPtr
 qemuBlockJobDiskGetJob(virDomainDiskDefPtr disk)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ff113ae57b..5675d2dc87 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4732,7 +4732,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 }

 if (!(job = qemuBlockJobDiskGetJob(disk))) {
-if (!(job = qemuBlockJobDiskNew(disk, type)))
+if (!(job = qemuBlockJobDiskNew(disk, type, diskAlias)))
 goto endjob;
 qemuBlockJobStarted(job);
 }
@@ -17268,7 +17268,7 @@ qemuDomainBlockPullCommon(virQEMUDriverPtr driver,
 speed <<= 20;
 }

-if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_PULL)))
+if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_PULL, device)))
 goto endjob;

 qemuDomainObjEnterMonitor(driver, vm);
@@ -17803,7 +17803,7 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
 goto endjob;
 }

-if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_COPY)))
+if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_COPY, device)))
 goto endjob;

 /* Actually start the mirroring */
@@ -18217,7 +18217,7 @@ qemuDomainBlockCommit(virDomainPtr dom,
 jobtype = QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT;
 }

-if (!(job = qemuBlockJobDiskNew(disk, jobtype)))
+if (!(job = qemuBlockJobDiskNew(disk, jobtype, device)))
 goto endjob;

 qemuDomainObjEnterMonitor(driver, vm);
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 4a6f631689..4ce3141465 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -914,7 +914,7 @@ qemuMigrationSrcNBDStorageCopyOne(virQEMUDriverPtr driver,
 if (!(diskAlias = qemuAliasDiskDriveFromDisk(disk)))
 goto cleanup;

-if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_COPY)))
+if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_COPY, diskAlias)))
 goto cleanup;

 qemuBlockJobSyncBegin(job);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c

[libvirt] [PATCH RFC 33/51] qemu: domain: Add global table of blockjobs

2018-12-12 Thread Peter Krempa
Block jobs currently belong to disks only so we can look up the block
job data for them in the corresponding disks. This won't be the case
when using blockdev as certain jobs don't even correspond to a disk and
most of them can run on a part of the backing chain.

Add a global table of blockjobs which can be used to look up the data
for the blockjobs when the job events need to be processed.

The table is a hash table organized by job name and has a reference to
the job. New and running jobs will later be added to this table.
Reference counting will allow to reap job state for synchronous callers.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_domain.c | 7 +++
 src/qemu/qemu_domain.h | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 9961ba67d8..7a9a94efcf 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1906,6 +1906,9 @@ qemuDomainObjPrivateAlloc(void *opaque)
 if (!(priv->devs = virChrdevAlloc()))
 goto error;

+if (!(priv->blockjobs = virHashCreate(5, virObjectFreeHashData)))
+goto error;
+
 priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX;
 priv->driver = opaque;

@@ -1973,6 +1976,8 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivatePtr 
priv)

 qemuDomainObjResetJob(priv);
 qemuDomainObjResetAsyncJob(priv);
+
+virHashRemoveAll(priv->blockjobs);
 }


@@ -2004,6 +2009,8 @@ qemuDomainObjPrivateFree(void *data)
 qemuDomainSecretInfoFree(&priv->migSecinfo);
 qemuDomainMasterKeyFree(priv);

+virHashFree(priv->blockjobs);
+
 VIR_FREE(priv);
 }

diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index a03950e77b..a243bdc80e 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -373,6 +373,9 @@ struct _qemuDomainObjPrivate {

 /* true if libvirt remembers the original owner for files */
 bool rememberOwner;
+
+/* running block jobs */
+virHashTablePtr blockjobs;
 };

 # define QEMU_DOMAIN_PRIVATE(vm) \
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 34/51] qemu: blockjob: Register new and running blockjobs in the global table

2018-12-12 Thread Peter Krempa
Add the job structure to the table when instantiating a new job and
remove it when it terminates/fails.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 31 ---
 src/qemu/qemu_blockjob.h  |  6 --
 src/qemu/qemu_driver.c| 16 
 src/qemu/qemu_migration.c |  4 ++--
 src/qemu/qemu_process.c   |  6 +++---
 5 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 27e854e2b2..97b9d7e5a6 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -105,20 +105,32 @@ qemuBlockJobDataNew(qemuBlockjobType type,
  * Returns 0 on success and -1 on failure.
  */
 qemuBlockJobDataPtr
-qemuBlockJobDiskNew(virDomainDiskDefPtr disk,
+qemuBlockJobDiskNew(virDomainObjPtr vm,
+virDomainDiskDefPtr disk,
 qemuBlockjobType type,
 const char *jobname)
 {
+qemuDomainObjPrivatePtr priv = vm->privateData;
 qemuBlockJobDataPtr job = NULL;
+qemuBlockJobDataPtr ret = NULL;

 if (!(job = qemuBlockJobDataNew(type, jobname)))
 return NULL;

+if (virHashAddEntry(priv->blockjobs, jobname, virObjectRef(job)) < 0) {
+virObjectUnref(job);
+goto cleanup;
+}
+
 job->disk = disk;
 if (disk)
 QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob = virObjectRef(job);

-return job;
+VIR_STEAL_PTR(ret, job);
+
+ cleanup:
+virObjectUnref(job);
+return ret;
 }


@@ -154,10 +166,14 @@ qemuBlockJobStarted(qemuBlockJobDataPtr job)


 static void
-qemuBlockJobTerminate(qemuBlockJobDataPtr job)
+qemuBlockJobTerminate(virDomainObjPtr vm,
+  qemuBlockJobDataPtr job)
 {
+qemuDomainObjPrivatePtr priv = vm->privateData;
 qemuDomainDiskPrivatePtr diskPriv;

+virHashRemoveEntry(priv->blockjobs, job->name);
+
 if (job->disk) {
 diskPriv = QEMU_DOMAIN_DISK_PRIVATE(job->disk);

@@ -178,13 +194,14 @@ qemuBlockJobTerminate(qemuBlockJobDataPtr job)
  * to @job if it was started.
  */
 void
-qemuBlockJobStartupFinalize(qemuBlockJobDataPtr job)
+qemuBlockJobStartupFinalize(virDomainObjPtr vm,
+qemuBlockJobDataPtr job)
 {
 if (!job)
 return;

 if (job->state == QEMU_BLOCKJOB_STATE_NEW)
-qemuBlockJobTerminate(job);
+qemuBlockJobTerminate(vm, job);

 virObjectUnref(job);
 }
@@ -288,7 +305,7 @@ qemuBlockJobEventProcessLegacyCompleted(virQEMUDriverPtr 
driver,
 virStorageSourceBackingStoreClear(disk->src);
 ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk, true));
 ignore_value(qemuBlockNodeNamesDetect(driver, vm, asyncJob));
-qemuBlockJobTerminate(job);
+qemuBlockJobTerminate(vm, job);
 }


@@ -343,7 +360,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
 }
 disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
 disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
-qemuBlockJobTerminate(job);
+qemuBlockJobTerminate(vm, job);
 break;

 case VIR_DOMAIN_BLOCK_JOB_LAST:
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index f67b0f39be..6f58d323d0 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -77,7 +77,8 @@ struct _qemuBlockJobData {


 qemuBlockJobDataPtr
-qemuBlockJobDiskNew(virDomainDiskDefPtr disk,
+qemuBlockJobDiskNew(virDomainObjPtr vm,
+virDomainDiskDefPtr disk,
 qemuBlockjobType type,
 const char *jobname)
 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
@@ -95,7 +96,8 @@ qemuBlockJobIsRunning(qemuBlockJobDataPtr job)
 ATTRIBUTE_NONNULL(1);

 void
-qemuBlockJobStartupFinalize(qemuBlockJobDataPtr job);
+qemuBlockJobStartupFinalize(virDomainObjPtr vm,
+qemuBlockJobDataPtr job);

 int qemuBlockJobUpdate(virDomainObjPtr vm,
qemuBlockJobDataPtr job,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5675d2dc87..1b31132807 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4732,7 +4732,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 }

 if (!(job = qemuBlockJobDiskGetJob(disk))) {
-if (!(job = qemuBlockJobDiskNew(disk, type, diskAlias)))
+if (!(job = qemuBlockJobDiskNew(vm, disk, type, diskAlias)))
 goto endjob;
 qemuBlockJobStarted(job);
 }
@@ -4742,7 +4742,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 qemuBlockJobUpdate(vm, job, QEMU_ASYNC_JOB_NONE);

  endjob:
-qemuBlockJobStartupFinalize(job);
+qemuBlockJobStartupFinalize(vm, job);
 qemuDomainObjEndJob(driver, vm);
 }

@@ -17268,7 +17268,7 @@ qemuDomainBlockPullCommon(virQEMUDriverPtr driver,
 speed <<= 20;
 }

-if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_PULL, device)))
+if (!(job = qemuBlockJobDiskNew(vm, disk, QEMU_BLOCKJOB_TYPE_PULL, 
device)))
 goto endjob;

 

[libvirt] [PATCH RFC 08/51] qemu: process: Consolidate error paths in qemuProcessHandleBlockJob

2018-12-12 Thread Peter Krempa
'cleanup' label was accessed only from a jump to 'error'. Consolidate
everyting into 'cleanup'.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_process.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 72725fcdf1..3fccbc79bb 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -935,7 +935,7 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon 
ATTRIBUTE_UNUSED,
   diskAlias, vm, vm->def->name, type, status);

 if (!(disk = qemuProcessFindDomainDiskByAliasOrQOM(vm, diskAlias, NULL)))
-goto error;
+goto cleanup;

 job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;

@@ -949,11 +949,11 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon 
ATTRIBUTE_UNUSED,
 } else {
 /* there is no waiting SYNC API, dispatch the update to a thread */
 if (VIR_ALLOC(processEvent) < 0)
-goto error;
+goto cleanup;

 processEvent->eventType = QEMU_PROCESS_EVENT_BLOCK_JOB;
 if (VIR_STRDUP(data, diskAlias) < 0)
-goto error;
+goto cleanup;
 processEvent->data = data;
 processEvent->vm = virObjectRef(vm);
 processEvent->action = type;
@@ -961,16 +961,16 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon 
ATTRIBUTE_UNUSED,

 if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
 ignore_value(virObjectUnref(vm));
-goto error;
+goto cleanup;
 }
+
+processEvent = NULL;
 }

  cleanup:
+qemuProcessEventFree(processEvent);
 virObjectUnlock(vm);
 return 0;
- error:
-qemuProcessEventFree(processEvent);
-goto cleanup;
 }


-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 28/51] qemu: blockjob: Pass job into qemuBlockJobUpdateDisk and rename it

2018-12-12 Thread Peter Krempa
Instead of passing in the disk information, pass in the job and name the
function accordingly.

Few callers needed to be modified to have the job pointer handy.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 20 
 src/qemu/qemu_blockjob.h  |  6 +++---
 src/qemu/qemu_driver.c|  6 +++---
 src/qemu/qemu_migration.c | 40 +++
 4 files changed, 46 insertions(+), 26 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 49e747ebbb..c1826baa3c 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -333,7 +333,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,


 /**
- * qemuBlockJobUpdateDisk:
+ * qemuBlockJobUpdate:
  * @vm: domain
  * @disk: domain disk
  * @error: error (output parameter)
@@ -344,11 +344,10 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
  * Returns the block job event processed or -1 if there was no pending event.
  */
 int
-qemuBlockJobUpdateDisk(virDomainObjPtr vm,
-   int asyncJob,
-   virDomainDiskDefPtr disk)
+qemuBlockJobUpdate(virDomainObjPtr vm,
+   qemuBlockJobDataPtr job,
+   int asyncJob)
 {
-qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
 qemuDomainObjPrivatePtr priv = vm->privateData;

 if (job->newstate == -1)
@@ -370,7 +369,7 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,
  *
  * During a synchronous block job, a block job event for @disk
  * will not be processed asynchronously. Instead, it will be
- * processed only when qemuBlockJobUpdateDisk or qemuBlockJobSyncEndDisk
+ * processed only when qemuBlockJobUpdate or qemuBlockJobSyncEndDisk
  * is called.
  */
 void
@@ -402,7 +401,12 @@ qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
 int asyncJob,
 virDomainDiskDefPtr disk)
 {
+qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+
+if (!job)
+return;
+
 VIR_DEBUG("disk=%s", disk->dst);
-qemuBlockJobUpdateDisk(vm, asyncJob, disk);
-QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob->synchronous = false;
+qemuBlockJobUpdate(vm, job, asyncJob);
+job->synchronous = false;
 }
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 4527ee2a93..9dad47f732 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -95,9 +95,9 @@ qemuBlockJobIsRunning(qemuBlockJobDataPtr job)
 void
 qemuBlockJobStartupFinalize(qemuBlockJobDataPtr job);

-int qemuBlockJobUpdateDisk(virDomainObjPtr vm,
-   int asyncJob,
-   virDomainDiskDefPtr disk);
+int qemuBlockJobUpdate(virDomainObjPtr vm,
+   qemuBlockJobDataPtr job,
+   int asyncJob);

 void qemuBlockJobSyncBegin(qemuBlockJobDataPtr job);
 void qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 2e47ec021a..4ffa5b573d 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4739,7 +4739,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,

 job->newstate = status;

-qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk);
+qemuBlockJobUpdate(vm, job, QEMU_ASYNC_JOB_NONE);

  endjob:
 qemuBlockJobStartupFinalize(job);
@@ -17397,13 +17397,13 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
  * do the waiting while still holding the VM job, to prevent newly
  * scheduled block jobs from confusing us. */
 if (!async) {
-qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk);
+qemuBlockJobUpdate(vm, job, QEMU_ASYNC_JOB_NONE);
 while (qemuBlockJobIsRunning(job)) {
 if (virDomainObjWait(vm) < 0) {
 ret = -1;
 goto endjob;
 }
-qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk);
+qemuBlockJobUpdate(vm, job, QEMU_ASYNC_JOB_NONE);
 }
 }

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index ac3c609067..92fcfa6278 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -464,17 +464,16 @@ qemuMigrationDstStopNBDServer(virQEMUDriverPtr driver,


 static void
-qemuMigrationNBDReportMirrorError(virDomainDiskDefPtr disk)
+qemuMigrationNBDReportMirrorError(qemuBlockJobDataPtr job,
+  const char *diskdst)
 {
-qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
-
 if (job->errmsg) {
 virReportError(VIR_ERR_OPERATION_FAILED,
_("migration of disk %s failed: %s"),
-   disk->dst, job->errmsg);
+   diskdst, job->errmsg);
 } else {
 virReportError(VIR_ERR_OPERATION_FAILED,
-   _("migration of disk %s failed"), disk->dst);
+   _("migration of disk %s failed"), diskdst);
 }
 }

@@ -501,16 +500,26 @@ qemuMigrationSr

[libvirt] [PATCH RFC 09/51] qemu: blockjob: Rename qemuBlockJobEventProcess to qemuBlockJobEventProcessLegacy

2018-12-12 Thread Peter Krempa
This will handle blockjob finalizing for the old approach so rename it
accordingly.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index b1a30b1edb..5934d58480 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -81,7 +81,7 @@ qemuBlockJobEmitEvents(virQEMUDriverPtr driver,


 /**
- * qemuBlockJobEventProcess:
+ * qemuBlockJobEventProcessLegacy:
  * @driver: qemu driver
  * @vm: domain
  * @disk: domain disk
@@ -93,12 +93,12 @@ qemuBlockJobEmitEvents(virQEMUDriverPtr driver,
  * restart, also update the domain's status XML.
  */
 static void
-qemuBlockJobEventProcess(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
- virDomainDiskDefPtr disk,
- int asyncJob,
- int type,
- int status)
+qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
+   virDomainObjPtr vm,
+   virDomainDiskDefPtr disk,
+   int asyncJob,
+   int type,
+   int status)
 {
 virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
 virDomainDiskDefPtr persistDisk = NULL;
@@ -232,8 +232,8 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,
 *error = NULL;

 if (status != -1) {
-qemuBlockJobEventProcess(priv->driver, vm, disk, asyncJob,
- job->type, status);
+qemuBlockJobEventProcessLegacy(priv->driver, vm, disk, asyncJob,
+   job->type, status);
 job->status = -1;
 if (error)
 VIR_STEAL_PTR(*error, job->errmsg);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 25/51] qemu: migration: Extract reporting of disk migration error

2018-12-12 Thread Peter Krempa
The same message is reported in 3 distinct places. Move it out into a
single function.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_migration.c | 43 ---
 1 file changed, 18 insertions(+), 25 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index bde8697ede..1ce7863460 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -463,6 +463,21 @@ qemuMigrationDstStopNBDServer(virQEMUDriverPtr driver,
 }


+static void
+qemuMigrationNBDReportMirrorError(virDomainDiskDefPtr disk,
+  const char *errmsg)
+{
+if (errmsg) {
+virReportError(VIR_ERR_OPERATION_FAILED,
+   _("migration of disk %s failed: %s"),
+   disk->dst, errmsg);
+} else {
+virReportError(VIR_ERR_OPERATION_FAILED,
+   _("migration of disk %s failed"), disk->dst);
+}
+}
+
+
 /**
  * qemuMigrationSrcNBDStorageCopyReady:
  * @vm: domain
@@ -492,15 +507,7 @@ qemuMigrationSrcNBDStorageCopyReady(virDomainObjPtr vm,

 status = qemuBlockJobUpdateDisk(vm, asyncJob, disk, &error);
 if (status == VIR_DOMAIN_BLOCK_JOB_FAILED) {
-if (error) {
-virReportError(VIR_ERR_OPERATION_FAILED,
-   _("migration of disk %s failed: %s"),
-   disk->dst, error);
-VIR_FREE(error);
-} else {
-virReportError(VIR_ERR_OPERATION_FAILED,
-   _("migration of disk %s failed"), disk->dst);
-}
+qemuMigrationNBDReportMirrorError(disk, error);
 return -1;
 }
 VIR_FREE(error);
@@ -553,14 +560,7 @@ qemuMigrationSrcNBDCopyCancelled(virDomainObjPtr vm,
 switch (status) {
 case VIR_DOMAIN_BLOCK_JOB_FAILED:
 if (check) {
-if (error) {
-virReportError(VIR_ERR_OPERATION_FAILED,
-   _("migration of disk %s failed: %s"),
-   disk->dst, error);
-} else {
-virReportError(VIR_ERR_OPERATION_FAILED,
-   _("migration of disk %s failed"), 
disk->dst);
-}
+qemuMigrationNBDReportMirrorError(disk, error);
 failed = true;
 }
 ATTRIBUTE_FALLTHROUGH;
@@ -635,14 +635,7 @@ qemuMigrationSrcNBDCopyCancelOne(virQEMUDriverPtr driver,
 case VIR_DOMAIN_BLOCK_JOB_FAILED:
 case VIR_DOMAIN_BLOCK_JOB_CANCELED:
 if (failNoJob) {
-if (error) {
-virReportError(VIR_ERR_OPERATION_FAILED,
-   _("migration of disk %s failed: %s"),
-   disk->dst, error);
-} else {
-virReportError(VIR_ERR_OPERATION_FAILED,
-   _("migration of disk %s failed"), disk->dst);
-}
+qemuMigrationNBDReportMirrorError(disk, error);
 goto cleanup;
 }
 ATTRIBUTE_FALLTHROUGH;
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 29/51] qemu: Allocate diskPriv->blockjob only when there's a blockjob

2018-12-12 Thread Peter Krempa
Rather than storing the presence of the blockjob in a flag we can bind
together the lifecycle of the job with the lifecycle of the object which
is tracking the data for it.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 76 +---
 src/qemu/qemu_blockjob.h |  1 -
 src/qemu/qemu_domain.c   |  5 ---
 3 files changed, 55 insertions(+), 27 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index c1826baa3c..87dc520f2c 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -66,23 +66,22 @@ qemuBlockJobDataOnceInit(void)

 VIR_ONCE_GLOBAL_INIT(qemuBlockJobData)

-qemuBlockJobDataPtr
-qemuBlockJobDataNew(void)
+static qemuBlockJobDataPtr
+qemuBlockJobDataNew(qemuBlockjobType type)
 {
+qemuBlockJobDataPtr job = NULL;
+
 if (qemuBlockJobDataInitialize() < 0)
 return NULL;

-return virObjectNew(qemuBlockJobDataClass);
-}
-
+if (!(job = virObjectNew(qemuBlockJobDataClass)))
+return NULL;

-static void
-qemuBlockJobDataReset(qemuBlockJobDataPtr job)
-{
-job->type = -1;
+job->state = QEMU_BLOCKJOB_STATE_NEW;
 job->newstate = -1;
-VIR_FREE(job->errmsg);
-job->synchronous = false;
+job->type = type;
+
+return job;
 }


@@ -98,15 +97,16 @@ qemuBlockJobDataPtr
 qemuBlockJobDiskNew(virDomainDiskDefPtr disk,
 qemuBlockjobType type)
 {
-qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
-job->disk = disk;
+qemuBlockJobDataPtr job = NULL;

-qemuBlockJobDataReset(job);
+if (!(job = qemuBlockJobDataNew(type)))
+return NULL;

-job->state = QEMU_BLOCKJOB_STATE_NEW;
-job->type = type;
+job->disk = disk;
+if (disk)
+QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob = virObjectRef(job);

-return virObjectRef(job);
+return job;
 }


@@ -141,6 +141,22 @@ qemuBlockJobStarted(qemuBlockJobDataPtr job)
 }


+static void
+qemuBlockJobTerminate(qemuBlockJobDataPtr job)
+{
+qemuDomainDiskPrivatePtr diskPriv;
+
+if (job->disk) {
+diskPriv = QEMU_DOMAIN_DISK_PRIVATE(job->disk);
+
+if (job == diskPriv->blockjob) {
+virObjectUnref(diskPriv->blockjob);
+diskPriv->blockjob = NULL;
+}
+}
+}
+
+
 /**
  * qemuBlockJobStartupFinalize:
  * @job: job being started
@@ -156,7 +172,7 @@ qemuBlockJobStartupFinalize(qemuBlockJobDataPtr job)
 return;

 if (job->state == QEMU_BLOCKJOB_STATE_NEW)
-qemuBlockJobDataReset(job);
+qemuBlockJobTerminate(job);

 virObjectUnref(job);
 }
@@ -200,11 +216,15 @@ qemuBlockJobEmitEvents(virQEMUDriverPtr driver,
 static void
 qemuBlockJobEventProcessLegacyCompleted(virQEMUDriverPtr driver,
 virDomainObjPtr vm,
-virDomainDiskDefPtr disk,
+qemuBlockJobDataPtr job,
 int asyncJob)
 {
+virDomainDiskDefPtr disk = job->disk;
 virDomainDiskDefPtr persistDisk = NULL;

+if (!disk)
+return;
+
 if (disk->mirrorState == VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT) {
 if (vm->newDef) {
 virStorageSourcePtr copy = NULL;
@@ -256,6 +276,7 @@ qemuBlockJobEventProcessLegacyCompleted(virQEMUDriverPtr 
driver,
 virStorageSourceBackingStoreClear(disk->src);
 ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk, true));
 ignore_value(qemuBlockNodeNamesDetect(driver, vm, asyncJob));
+qemuBlockJobTerminate(job);
 }


@@ -294,7 +315,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
  * to match.  */
 switch ((virConnectDomainEventBlockJobStatus) job->newstate) {
 case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
-qemuBlockJobEventProcessLegacyCompleted(driver, vm, disk, asyncJob);
+qemuBlockJobEventProcessLegacyCompleted(driver, vm, job, asyncJob);
 break;

 case VIR_DOMAIN_BLOCK_JOB_READY:
@@ -310,6 +331,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
 }
 disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
 disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
+qemuBlockJobTerminate(job);
 break;

 case VIR_DOMAIN_BLOCK_JOB_LAST:
@@ -333,7 +355,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,


 /**
- * qemuBlockJobUpdate:
+ * qemuBlockJobUpdateDisk:
  * @vm: domain
  * @disk: domain disk
  * @error: error (output parameter)
@@ -410,3 +432,15 @@ qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
 qemuBlockJobUpdate(vm, job, asyncJob);
 job->synchronous = false;
 }
+
+
+qemuBlockJobDataPtr
+qemuBlockJobGetByDisk(virDomainDiskDefPtr disk)
+{
+qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+
+if (!job)
+return NULL;
+
+return virObjectRef(job);
+}
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 9dad47f732..8c567ec886 100644
--- a/src/qemu/qemu_

[libvirt] [PATCH RFC 38/51] qemu: monitor: Add new fields for 'block-stream' command

2018-12-12 Thread Peter Krempa
Allow using the node name to specify the base of the 'stream' operation,
allow specifying explicit job name and add support for delayed dismiss
of the job so that we can reap the state even if libvirtd was not
running when qemu emitted the job completion event.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_driver.c   |  4 ++--
 src/qemu/qemu_monitor.c  | 18 +++---
 src/qemu/qemu_monitor.h  |  3 +++
 src/qemu/qemu_monitor_json.c | 14 ++
 src/qemu/qemu_monitor_json.h |  3 +++
 tests/qemumonitorjsontest.c  |  2 +-
 6 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1b31132807..133bfcfbf3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17276,8 +17276,8 @@ qemuDomainBlockPullCommon(virQEMUDriverPtr driver,
 basePath = qemuMonitorDiskNameLookup(priv->mon, device, disk->src,
  baseSource);
 if (!baseSource || basePath)
-ret = qemuMonitorBlockStream(priv->mon, device, basePath, backingPath,
- speed);
+ret = qemuMonitorBlockStream(priv->mon, device, NULL, false, basePath,
+ NULL, backingPath, speed);
 if (qemuDomainObjExitMonitor(driver, vm) < 0)
 ret = -1;

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 1d40aef127..d6cad63863 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3388,16 +3388,28 @@ qemuMonitorScreendump(qemuMonitorPtr mon,
 int
 qemuMonitorBlockStream(qemuMonitorPtr mon,
const char *device,
+   const char *jobname,
+   bool persistjob,
const char *base,
+   const char *baseNode,
const char *backingName,
unsigned long long bandwidth)
 {
-VIR_DEBUG("device=%s, base=%s, backingName=%s, bandwidth=%lluB",
-  device, NULLSTR(base), NULLSTR(backingName), bandwidth);
+VIR_DEBUG("device=%s, jobname=%s, persistjob=%d, base=%s, baseNode=%s, "
+  "backingName=%s, bandwidth=%lluB",
+  device, NULLSTR(jobname), persistjob, NULLSTR(base),
+  NULLSTR(baseNode), NULLSTR(backingName), bandwidth);

 QEMU_CHECK_MONITOR(mon);

-return qemuMonitorJSONBlockStream(mon, device, base, backingName, 
bandwidth);
+if (base && baseNode) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("'base' and 'baseNode' can't be used together"));
+return -1;
+}
+
+return qemuMonitorJSONBlockStream(mon, device, jobname, persistjob, base,
+  baseNode, backingName, bandwidth);
 }


diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 66bfdb0e5c..bbdf88ae60 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -908,7 +908,10 @@ int qemuMonitorSendKey(qemuMonitorPtr mon,

 int qemuMonitorBlockStream(qemuMonitorPtr mon,
const char *device,
+   const char *jobname,
+   bool persistjob,
const char *base,
+   const char *baseNode,
const char *backingName,
unsigned long long bandwidth)
 ATTRIBUTE_NONNULL(2);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index dfcc6d88b5..fe16a3d13c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -4797,19 +4797,33 @@ qemuMonitorJSONBlockJobError(virJSONValuePtr cmd,
 int
 qemuMonitorJSONBlockStream(qemuMonitorPtr mon,
const char *device,
+   const char *jobname,
+   bool persistjob,
const char *base,
+   const char *baseNode,
const char *backingName,
unsigned long long speed)
 {
 int ret = -1;
 virJSONValuePtr cmd = NULL;
 virJSONValuePtr reply = NULL;
+virTristateBool autofinalize = VIR_TRISTATE_BOOL_ABSENT;
+virTristateBool autodismiss = VIR_TRISTATE_BOOL_ABSENT;
+
+if (persistjob) {
+autofinalize = VIR_TRISTATE_BOOL_YES;
+autodismiss = VIR_TRISTATE_BOOL_NO;
+}

 if (!(cmd = qemuMonitorJSONMakeCommand("block-stream",
"s:device", device,
+   "S:job-id", jobname,
"Y:speed", speed,
"S:base", base,
+   "S:base-node", baseNode,
"S:backing-file", backingName,
+   "T:auto-finalize", autofinalize,
+  

[libvirt] [PATCH RFC 36/51] qemu: domain: Store blockjob data in the status XML

2018-12-12 Thread Peter Krempa
We need to store the block job state in the status XML so that we can
properly recover any data when reconnecting after startup and also in
the end to be able to do any transition of the backing chain that
happened while libvirt was not connected to the monitor.

First step is to note the name, type, state and corresponding disk into
the status XML.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_domain.c | 105 +++--
 1 file changed, 101 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 7a9a94efcf..7845889dec 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -35,6 +35,7 @@
 #include "qemu_migration_params.h"
 #include "qemu_security.h"
 #include "qemu_extdevice.h"
+#include "qemu_blockjob.h"
 #include "viralloc.h"
 #include "virlog.h"
 #include "virerror.h"
@@ -2235,17 +2236,47 @@ 
qemuDomainObjPrivateXMLFormatAutomaticPlacement(virBufferPtr buf,
 }


+static int
+qemuDomainObjPrivateXMLFormatBlockjobIterator(void *payload,
+  const void *name 
ATTRIBUTE_UNUSED,
+  void *data)
+{
+virBuffer attrBuf = VIR_BUFFER_INITIALIZER;
+virBuffer childBuf = VIR_BUFFER_INITIALIZER;
+qemuBlockJobDataPtr job = payload;
+virBufferPtr buf = data;
+
+virBufferSetChildIndent(&childBuf, buf);
+
+virBufferAsprintf(&attrBuf, " name='%s'", job->name);
+virBufferAsprintf(&attrBuf, " type='%s'", 
qemuBlockjobTypeToString(job->type));
+virBufferAsprintf(&attrBuf, " state='%s'", 
qemuBlockjobStateTypeToString(job->state));
+
+if (job->disk)
+virBufferAsprintf(&childBuf, "\n", job->disk->dst);
+
+return virXMLFormatElement(buf, "blockjob", &attrBuf, &childBuf);
+}
+
+
 static int
 qemuDomainObjPrivateXMLFormatBlockjobs(virBufferPtr buf,
virDomainObjPtr vm)
 {
+qemuDomainObjPrivatePtr priv = vm->privateData;
 virBuffer attrBuf = VIR_BUFFER_INITIALIZER;
+virBuffer childBuf = VIR_BUFFER_INITIALIZER;
 bool bj = qemuDomainHasBlockjob(vm, false);

 virBufferAsprintf(&attrBuf, " active='%s'",
   
virTristateBoolTypeToString(virTristateBoolFromBool(bj)));

-return virXMLFormatElement(buf, "blockjobs", &attrBuf, NULL);
+virBufferSetChildIndent(&childBuf, buf);
+
+virHashForEach(priv->blockjobs,
+   qemuDomainObjPrivateXMLFormatBlockjobIterator, &childBuf);
+
+return virXMLFormatElement(buf, "blockjobs", &attrBuf, &childBuf);
 }


@@ -2599,18 +2630,84 @@ 
qemuDomainObjPrivateXMLParseAutomaticPlacement(xmlXPathContextPtr ctxt,


 static int
-qemuDomainObjPrivateXMLParseBlockjobs(qemuDomainObjPrivatePtr priv,
+qemuDomainObjPrivateXMLParseBlockjobData(virDomainObjPtr vm,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
+{
+xmlNodePtr save_node = ctxt->node;
+virDomainDiskDefPtr disk = NULL;
+qemuBlockJobDataPtr job = NULL;
+char *name = NULL;
+char *typestr = NULL;
+int type;
+char *statestr = NULL;
+int state;
+char *diskdst = NULL;
+int ret = -1;
+
+ctxt->node = node;
+
+if (!(name = virXPathString("string(./@name)", ctxt)) ||
+!(typestr = virXPathString("string(./@type)", ctxt)) ||
+!(statestr = virXPathString("string(./@state)", ctxt)) ||
+(type = qemuBlockjobTypeFromString(typestr)) < 0 ||
+(state = qemuBlockjobStateTypeFromString(statestr)) < 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+   _("malformed block job data"));
+goto cleanup;
+}
+
+if ((diskdst = virXPathString("string(./disk/@dst)", ctxt)))
+disk = virDomainDiskByName(vm->def, diskdst, false);
+
+if (!(job = qemuBlockJobDiskNew(vm, disk, type, name)))
+goto cleanup;
+
+job->state = state;
+
+ret = 0;
+
+ cleanup:
+virObjectUnref(job);
+VIR_FREE(name);
+VIR_FREE(typestr);
+VIR_FREE(statestr);
+VIR_FREE(diskdst);
+ctxt->node = save_node;
+return ret;
+}
+
+
+static int
+qemuDomainObjPrivateXMLParseBlockjobs(virDomainObjPtr vm,
+  qemuDomainObjPrivatePtr priv,
   xmlXPathContextPtr ctxt)
 {
+xmlNodePtr *nodes = NULL;
+ssize_t nnodes = 0;
 char *active;
 int tmp;
+size_t i;
+int ret = -1;

 if ((active = virXPathString("string(./blockjobs/@active)", ctxt)) &&
 (tmp = virTristateBoolTypeFromString(active)) > 0)
 priv->reconnectBlockjobs = tmp;

+if ((nnodes = virXPathNodeSet("./blockjobs/blockjob", ctxt, &nodes)) < 0)
+goto cleanup;
+
+for (i = 0; i < nnodes; i++) {
+if (qemuDomainObjPrivateXMLParseBlockjobData(vm, nodes[i], ctxt) < 0)
+goto cleanup;
+}
+
+ret = 0;
+
+ cleanup:
 VIR_FREE(active);
-return 0;
+VIR_

[libvirt] [PATCH RFC 37/51] tests: qemustatusxml2xml: Add test case for block job tracking

2018-12-12 Thread Peter Krempa
Signed-off-by: Peter Krempa 
---
 .../blockjob-blockdev-in.xml  | 364 ++
 .../blockjob-blockdev-out.xml |   1 +
 tests/qemuxml2xmltest.c   |   2 +
 3 files changed, 367 insertions(+)
 create mode 100644 tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml
 create mode 12 tests/qemustatusxml2xmldata/blockjob-blockdev-out.xml

diff --git a/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml 
b/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml
new file mode 100644
index 00..23d2a209f3
--- /dev/null
+++ b/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml
@@ -0,0 +1,364 @@
+
+  
+  
+  
+
+  
+  
+
+
+  
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  
+  
+
+
+
+
+
+
+
+
+
+
+  
+  
+  
+  
+  
+  
+  
+
+  
+
+  
+  
+copy
+0439a4a8-db56-4933-9183-d8681d7b0746
+1024000
+1024000
+8
+
+  
+
+
+  /machine
+
+
+  hvm
+  
+  
+
+
+  
+  
+  
+
+
+  
+
+
+  
+
+
+  
+  
+  
+
+destroy
+restart
+restart
+
+  
+  
+
+
+  
/home/pipo/git/qemu.git/x86_64-softmmu/qemu-system-x86_64
+  
+
+
+
+
+  
+  
+
+
+
+
+  
+  
+
+
+  
+  
+
+  
+  
+
+
+  
+  
+
+
+  
+
+
+  
+  
+
+
+
+  
+  
+
+
+
+
+  
+  
+
+
+
+  
+  
+
+  
+  
+
+  
+  
+
+
+  
+  
+
+
+  
+  
+
+
+
+  
+  
+  
+/dev/random
+
+
+  
+
+
+  unconfined_u:unconfined_r:svirt_t:s0:c550,c786
+  unconfined_u:object_r:svirt_image_t:s0:c550,c786
+
+
+  +0:+0
+  +0:+0
+
+  
+
diff --git a/tests/qemustatusxml2xmldata/blockjob-blockdev-out.xml 
b/tests/qemustatusxml2xmldata/blockjob-blockdev-out.xml
new file mode 12
index 00..cdca6e4a8b
--- /dev/null
+++ b/tests/qemustatusxml2xmldata/blockjob-blockdev-out.xml
@@ -0,0 +1 @@
+blockjob-blockdev-in.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 1062deee37..da9469b263 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1252,6 +1252,8 @@ mymain(void)
 DO_TEST_STATUS("migration-out-nbd-tls");
 DO_TEST_STATUS("disk-secinfo-upgrade");

+DO_TEST_STATUS("blockjob-blockdev");
+
 DO_TEST("vhost-vsock", QEMU_CAPS_DEVICE_VHOST_VSOCK);
 DO_TEST("vhost-vsock-auto", QEMU_CAPS_DEVICE_VHOST_VSOCK);
 DO_TEST("vhost-vsock-ccw", QEMU_CAPS_DEVICE_VHOST_VSOCK,
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 17/51] qemu: migration: Separate startup of disk mirror from migration logic

2018-12-12 Thread Peter Krempa
Extract the disk mirroring startup code from the loop into a separate
function to allow cleaner cleanup paths.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_migration.c | 85 +--
 1 file changed, 55 insertions(+), 30 deletions(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 5f4fcb4bad..9d165e27aa 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -890,6 +890,58 @@ qemuMigrationSrcNBDStorageCopyDriveMirror(virQEMUDriverPtr 
driver,
 }


+static int
+qemuMigrationSrcNBDStorageCopyOne(virQEMUDriverPtr driver,
+  virDomainObjPtr vm,
+  virDomainDiskDefPtr disk,
+  const char *host,
+  int port,
+  unsigned long long mirror_speed,
+  unsigned int mirror_flags,
+  const char *tlsAlias,
+  unsigned int flags)
+{
+qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+char *diskAlias = NULL;
+int rc;
+int ret = -1;
+
+if (!(diskAlias = qemuAliasDiskDriveFromDisk(disk)))
+goto cleanup;
+
+qemuBlockJobSyncBeginDisk(disk);
+
+if (flags & VIR_MIGRATE_TLS) {
+rc = qemuMigrationSrcNBDStorageCopyBlockdev(driver, vm,
+disk, diskAlias,
+host, port,
+mirror_speed,
+mirror_flags,
+tlsAlias);
+} else {
+rc = qemuMigrationSrcNBDStorageCopyDriveMirror(driver, vm, diskAlias,
+   host, port,
+   mirror_speed,
+   mirror_flags);
+}
+
+if (rc < 0) {
+qemuBlockJobSyncEndDisk(vm, QEMU_ASYNC_JOB_MIGRATION_OUT, disk);
+goto cleanup;
+}
+
+VIR_FREE(diskAlias);
+diskPriv->migrating = true;
+diskPriv->blockjob->started = true;
+
+ret = 0;
+
+ cleanup:
+VIR_FREE(diskAlias);
+return ret;
+}
+
+
 /**
  * qemuMigrationSrcNBDStorageCopy:
  * @driver: qemu driver
@@ -926,7 +978,6 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver,
 int ret = -1;
 int port;
 size_t i;
-char *diskAlias = NULL;
 unsigned long long mirror_speed = speed;
 unsigned int mirror_flags = VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT;
 int rv;
@@ -951,40 +1002,15 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver,

 for (i = 0; i < vm->def->ndisks; i++) {
 virDomainDiskDefPtr disk = vm->def->disks[i];
-qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
-int rc;

 /* check whether disk should be migrated */
 if (!qemuMigrationAnyCopyDisk(disk, nmigrate_disks, migrate_disks))
 continue;

-if (!(diskAlias = qemuAliasDiskDriveFromDisk(disk)))
-goto cleanup;
-
-qemuBlockJobSyncBeginDisk(disk);
-
-if (flags & VIR_MIGRATE_TLS) {
-rc = qemuMigrationSrcNBDStorageCopyBlockdev(driver, vm,
-disk, diskAlias,
-host, port,
-mirror_speed,
-mirror_flags,
-tlsAlias);
-} else {
-rc = qemuMigrationSrcNBDStorageCopyDriveMirror(driver, vm, 
diskAlias,
-   host, port,
-   mirror_speed,
-   mirror_flags);
-}
-
-if (rc < 0) {
-qemuBlockJobSyncEndDisk(vm, QEMU_ASYNC_JOB_MIGRATION_OUT, disk);
+if (qemuMigrationSrcNBDStorageCopyOne(driver, vm, disk, host, port,
+  mirror_speed, mirror_flags,
+  tlsAlias, flags) < 0)
 goto cleanup;
-}
-
-VIR_FREE(diskAlias);
-diskPriv->migrating = true;
-diskPriv->blockjob->started = true;

 if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, 
driver->caps) < 0) {
 VIR_WARN("Failed to save status on vm %s", vm->def->name);
@@ -1024,7 +1050,6 @@ qemuMigrationSrcNBDStorageCopy(virQEMUDriverPtr driver,

  cleanup:
 virObjectUnref(cfg);
-VIR_FREE(diskAlias);
 return ret;
 }

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 21/51] qemu: blockjob: Record job type when starting the job

2018-12-12 Thread Peter Krempa
We can properly track the job type when starting the job so that we
don't have to infer it later.

This patch also adds an enum of block job types specific to qemu
(qemuBlockjobType) which mirrors the public block job types
(virDomainBlockJobType) but allows for other types to be added later
which will not be public.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 10 +-
 src/qemu/qemu_blockjob.h  | 20 ++--
 src/qemu/qemu_driver.c| 11 ++-
 src/qemu/qemu_migration.c |  2 +-
 src/qemu/qemu_process.c   |  8 ++--
 5 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 7bbe582722..531de035af 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -96,12 +96,16 @@ qemuBlockJobDataReset(qemuBlockJobDataPtr job)
  * Returns 0 on success and -1 on failure.
  */
 qemuBlockJobDataPtr
-qemuBlockJobDiskNew(virDomainDiskDefPtr disk)
+qemuBlockJobDiskNew(virDomainDiskDefPtr disk,
+qemuBlockjobType type)
 {
 qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
 job->disk = disk;

 qemuBlockJobDataReset(job);
+
+job->type = type;
+
 return virObjectRef(job);
 }

@@ -278,10 +282,6 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
   type,
   status);

-if (type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT &&
-disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)
-type = disk->mirrorJob;
-
 qemuBlockJobEmitEvents(driver, vm, disk, type, status);

 /* If we completed a block pull or commit, then update the XML
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index feaee4dee3..6f6d0aa691 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -25,6 +25,21 @@
 # include "internal.h"
 # include "qemu_conf.h"

+/**
+ * This enum has to map all known block job types from enum 
virDomainBlockJobType
+ * to the same values. All internal blockjobs can be mapped after and don't
+ * need to have stable values.
+ */
+typedef enum {
+QEMU_BLOCKJOB_TYPE_NONE = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN,
+QEMU_BLOCKJOB_TYPE_PULL = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL,
+QEMU_BLOCKJOB_TYPE_COPY = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY,
+QEMU_BLOCKJOB_TYPE_COMMIT = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT,
+QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT,
+QEMU_BLOCKJOB_TYPE_INTERNAL,
+QEMU_BLOCKJOB_TYPE_LAST
+} qemuBlockjobType;
+verify((int)QEMU_BLOCKJOB_TYPE_INTERNAL == VIR_DOMAIN_BLOCK_JOB_TYPE_LAST);

 typedef struct _qemuBlockJobData qemuBlockJobData;
 typedef qemuBlockJobData *qemuBlockJobDataPtr;
@@ -35,7 +50,7 @@ struct _qemuBlockJobData {
 virDomainDiskDefPtr disk; /* may be NULL, if blockjob does not corrspond 
to any disk */

 bool started;
-int type;
+int type; /* qemuBlockjobType */
 char *errmsg;
 bool synchronous; /* API call is waiting for this job */

@@ -45,7 +60,8 @@ struct _qemuBlockJobData {
 qemuBlockJobDataPtr qemuBlockJobDataNew(void);

 qemuBlockJobDataPtr
-qemuBlockJobDiskNew(virDomainDiskDefPtr disk)
+qemuBlockJobDiskNew(virDomainDiskDefPtr disk,
+qemuBlockjobType type)
 ATTRIBUTE_NONNULL(1);

 qemuBlockJobDataPtr
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9e5171744e..5eace06099 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4732,12 +4732,11 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 }

 if (!(job = qemuBlockJobDiskGetJob(disk))) {
-if (!(job = qemuBlockJobDiskNew(disk)))
+if (!(job = qemuBlockJobDiskNew(disk, type)))
 goto endjob;
 qemuBlockJobStarted(job);
 }

-job->type = type;
 job->newstate = status;

 qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk, NULL);
@@ -17269,7 +17268,7 @@ qemuDomainBlockPullCommon(virQEMUDriverPtr driver,
 speed <<= 20;
 }

-if (!(job = qemuBlockJobDiskNew(disk)))
+if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_PULL)))
 goto endjob;

 qemuDomainObjEnterMonitor(driver, vm);
@@ -17797,7 +17796,7 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
 goto endjob;
 }

-if (!(job = qemuBlockJobDiskNew(disk)))
+if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_COPY)))
 goto endjob;

 /* Actually start the mirroring */
@@ -18048,6 +18047,7 @@ qemuDomainBlockCommit(virDomainPtr dom,
 virStorageSourcePtr mirror = NULL;
 unsigned long long speed = bandwidth;
 qemuBlockJobDataPtr job = NULL;
+qemuBlockjobType jobtype = QEMU_BLOCKJOB_TYPE_COMMIT;

 /* XXX Add support for COMMIT_DELETE */
 virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW |
@@ -18207,9 +18207,10 @@ qemuDomainBlockCommit(virDomainPtr dom,
 disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
 disk->mirror = mirror;
 disk->mirrorJob = VIR_DOMAIN_BLO

[libvirt] [PATCH RFC 26/51] qemu: blockjob: Remove error propagation from qemuBlockJobUpdateDisk

2018-12-12 Thread Peter Krempa
The job error can be safely accessed in the job structure, so we don't
need to propagate it through qemuBlockJobUpdateDisk.

Drop the propagation and refactor any caller that pased non-NULL error.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 12 ++--
 src/qemu/qemu_blockjob.h  |  3 +--
 src/qemu/qemu_driver.c|  6 +++---
 src/qemu/qemu_migration.c | 28 +++-
 4 files changed, 17 insertions(+), 32 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index e778e5b7ce..7aaa439791 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -342,23 +342,15 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
 int
 qemuBlockJobUpdateDisk(virDomainObjPtr vm,
int asyncJob,
-   virDomainDiskDefPtr disk,
-   char **error)
+   virDomainDiskDefPtr disk)
 {
 qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
 qemuDomainObjPrivatePtr priv = vm->privateData;
 int state = job->newstate;

-if (error)
-*error = NULL;
-
 if (state != -1) {
 qemuBlockJobEventProcessLegacy(priv->driver, vm, job, asyncJob);
 job->newstate = -1;
-if (error)
-VIR_STEAL_PTR(*error, job->errmsg);
-else
-VIR_FREE(job->errmsg);
 }

 return state;
@@ -408,6 +400,6 @@ qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
 virDomainDiskDefPtr disk)
 {
 VIR_DEBUG("disk=%s", disk->dst);
-qemuBlockJobUpdateDisk(vm, asyncJob, disk, NULL);
+qemuBlockJobUpdateDisk(vm, asyncJob, disk);
 QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob->synchronous = false;
 }
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 67b9c94b64..4527ee2a93 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -97,8 +97,7 @@ qemuBlockJobStartupFinalize(qemuBlockJobDataPtr job);

 int qemuBlockJobUpdateDisk(virDomainObjPtr vm,
int asyncJob,
-   virDomainDiskDefPtr disk,
-   char **error);
+   virDomainDiskDefPtr disk);

 void qemuBlockJobSyncBegin(qemuBlockJobDataPtr job);
 void qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f203f89521..2e47ec021a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4739,7 +4739,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,

 job->newstate = status;

-qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk, NULL);
+qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk);

  endjob:
 qemuBlockJobStartupFinalize(job);
@@ -17397,13 +17397,13 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
  * do the waiting while still holding the VM job, to prevent newly
  * scheduled block jobs from confusing us. */
 if (!async) {
-qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk, NULL);
+qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk);
 while (qemuBlockJobIsRunning(job)) {
 if (virDomainObjWait(vm) < 0) {
 ret = -1;
 goto endjob;
 }
-qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk, NULL);
+qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk);
 }
 }

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 1ce7863460..ac3c609067 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -464,13 +464,14 @@ qemuMigrationDstStopNBDServer(virQEMUDriverPtr driver,


 static void
-qemuMigrationNBDReportMirrorError(virDomainDiskDefPtr disk,
-  const char *errmsg)
+qemuMigrationNBDReportMirrorError(virDomainDiskDefPtr disk)
 {
-if (errmsg) {
+qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+
+if (job->errmsg) {
 virReportError(VIR_ERR_OPERATION_FAILED,
_("migration of disk %s failed: %s"),
-   disk->dst, errmsg);
+   disk->dst, job->errmsg);
 } else {
 virReportError(VIR_ERR_OPERATION_FAILED,
_("migration of disk %s failed"), disk->dst);
@@ -500,17 +501,15 @@ qemuMigrationSrcNBDStorageCopyReady(virDomainObjPtr vm,
 for (i = 0; i < vm->def->ndisks; i++) {
 virDomainDiskDefPtr disk = vm->def->disks[i];
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
-char *error = NULL;

 if (!diskPriv->migrating)
 continue;

-status = qemuBlockJobUpdateDisk(vm, asyncJob, disk, &error);
+status = qemuBlockJobUpdateDisk(vm, asyncJob, disk);
 if (status == VIR_DOMAIN_BLOCK_JOB_FAILED) {
-qemuMigrationNBDReportMirrorError(disk, error);
+qemuMigrationNBDReportMirrorError(disk);
 return -1;
 }
-  

[libvirt] [PATCH RFC 24/51] qemu: blockjob: Track current state of blockjob

2018-12-12 Thread Peter Krempa
Add a field tracking the current state of job so that it can be queried
later. Until now the job state e.g. that the job is _READY for
finalizing was tracked only for mirror jobs. Add tracking of state for
all jobs.

Similarly to 'qemuBlockJobType' this maps the existing states of the
blockjob from virConnectDomainEventBlockJobStatus to
'qemuBlockJobState' so that we can track some internal states as well.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 23 +++
 src/qemu/qemu_blockjob.h  | 22 +-
 src/qemu/qemu_domain.c|  5 +++--
 src/qemu/qemu_driver.c|  3 +--
 src/qemu/qemu_migration.c |  8 ++--
 src/qemu/qemu_process.c   |  4 +++-
 6 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 0b2c667dae..e778e5b7ce 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -79,7 +79,6 @@ qemuBlockJobDataNew(void)
 static void
 qemuBlockJobDataReset(qemuBlockJobDataPtr job)
 {
-job->started = false;
 job->type = -1;
 job->newstate = -1;
 VIR_FREE(job->errmsg);
@@ -104,6 +103,7 @@ qemuBlockJobDiskNew(virDomainDiskDefPtr disk,

 qemuBlockJobDataReset(job);

+job->state = QEMU_BLOCKJOB_STATE_NEW;
 job->type = type;

 return virObjectRef(job);
@@ -137,7 +137,7 @@ qemuBlockJobDiskGetJob(virDomainDiskDefPtr disk)
 void
 qemuBlockJobStarted(qemuBlockJobDataPtr job)
 {
-job->started = true;
+job->state = QEMU_BLOCKJOB_STATE_RUNNING;
 }


@@ -155,13 +155,21 @@ qemuBlockJobStartupFinalize(qemuBlockJobDataPtr job)
 if (!job)
 return;

-if (!job->started)
+if (job->state == QEMU_BLOCKJOB_STATE_NEW)
 qemuBlockJobDataReset(job);

 virObjectUnref(job);
 }


+bool
+qemuBlockJobIsRunning(qemuBlockJobDataPtr job)
+{
+return job->state == QEMU_BLOCKJOB_STATE_RUNNING ||
+   job->state == QEMU_BLOCKJOB_STATE_READY;
+}
+
+
 /**
  * qemuBlockJobEmitEvents:
  *
@@ -195,7 +203,6 @@ qemuBlockJobEventProcessLegacyCompleted(virQEMUDriverPtr 
driver,
 virDomainDiskDefPtr disk,
 int asyncJob)
 {
-qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
 virDomainDiskDefPtr persistDisk = NULL;

 if (disk->mirrorState == VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT) {
@@ -249,7 +256,6 @@ qemuBlockJobEventProcessLegacyCompleted(virQEMUDriverPtr 
driver,
 virStorageSourceBackingStoreClear(disk->src);
 ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk, true));
 ignore_value(qemuBlockNodeNamesDetect(driver, vm, asyncJob));
-diskPriv->blockjob->started = false;
 }


@@ -271,12 +277,12 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
 {
 virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
 virDomainDiskDefPtr disk = job->disk;
-qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);

-VIR_DEBUG("disk=%s, mirrorState=%s, type=%d, newstate=%d",
+VIR_DEBUG("disk=%s, mirrorState=%s, type=%d, state=%d, newstate=%d",
   disk->dst,
   NULLSTR(virDomainDiskMirrorStateTypeToString(disk->mirrorState)),
   job->type,
+  job->state,
   job->newstate);

 qemuBlockJobEmitEvents(driver, vm, disk, job->type, job->newstate);
@@ -301,13 +307,14 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
 }
 disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
 disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
-diskPriv->blockjob->started = false;
 break;

 case VIR_DOMAIN_BLOCK_JOB_LAST:
 break;
 }

+job->state = job->newstate;
+
 if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 
0)
 VIR_WARN("Unable to save status on vm %s after block job", 
vm->def->name);

diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 0c2ce46986..67b9c94b64 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -25,6 +25,22 @@
 # include "internal.h"
 # include "qemu_conf.h"

+/**
+ * This enum has to map all known block job states from enum 
virDomainBlockJobType
+ * to the same values. All internal blockjobs can be mapped after and don't
+ * need to have stable values.
+ */
+typedef enum {
+QEMU_BLOCKJOB_STATE_COMPLETED = VIR_DOMAIN_BLOCK_JOB_COMPLETED,
+QEMU_BLOCKJOB_STATE_FAILED = VIR_DOMAIN_BLOCK_JOB_FAILED,
+QEMU_BLOCKJOB_STATE_CANCELLED = VIR_DOMAIN_BLOCK_JOB_CANCELED,
+QEMU_BLOCKJOB_STATE_READY = VIR_DOMAIN_BLOCK_JOB_READY,
+QEMU_BLOCKJOB_STATE_NEW = VIR_DOMAIN_BLOCK_JOB_LAST,
+QEMU_BLOCKJOB_STATE_RUNNING,
+QEMU_BLOCKJOB_STATE_LAST
+} qemuBlockjobState;
+verify((int)QEMU_BLOCKJOB_STATE_NEW == VIR_DOMAIN_BLOCK_JOB_LAST);
+
 /**
  * This enum has to map all known block job types from enum 
virDomainBlockJobType
  * to the same values. All internal blockjobs can be map

[libvirt] [PATCH RFC 30/51] qemu: migration: Don't call qemuBlockJobSyncEndDisk when block job has terminated

2018-12-12 Thread Peter Krempa
Now that the data is per-job, we don't really need to bother with
finishing the synchronous job handling if the job is already terminated.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_migration.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 92fcfa6278..bed8eed563 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -577,7 +577,6 @@ qemuMigrationSrcNBDCopyCancelled(virDomainObjPtr vm,
 ATTRIBUTE_FALLTHROUGH;
 case VIR_DOMAIN_BLOCK_JOB_CANCELED:
 case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
-qemuBlockJobSyncEndDisk(vm, asyncJob, disk);
 diskPriv->migrating = false;
 break;

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 31/51] qemu: blockjob: Convert qemuBlockJobSyncEndDisk to take job instead of disk

2018-12-12 Thread Peter Krempa
And rename it in accordance with the change.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 20 ++--
 src/qemu/qemu_blockjob.h  |  6 +++---
 src/qemu/qemu_driver.c|  4 ++--
 src/qemu/qemu_migration.c |  2 +-
 4 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 87dc520f2c..c98d393f4b 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -386,12 +386,12 @@ qemuBlockJobUpdate(virDomainObjPtr vm,
  * @disk: domain disk
  *
  * Begin a new synchronous block job for @disk. The synchronous
- * block job is ended by a call to qemuBlockJobSyncEndDisk, or by
+ * block job is ended by a call to qemuBlockJobSyncEnd, or by
  * the guest quitting.
  *
  * During a synchronous block job, a block job event for @disk
  * will not be processed asynchronously. Instead, it will be
- * processed only when qemuBlockJobUpdate or qemuBlockJobSyncEndDisk
+ * processed only when qemuBlockJobUpdate or qemuBlockJobSyncEnd
  * is called.
  */
 void
@@ -409,7 +409,7 @@ qemuBlockJobSyncBegin(qemuBlockJobDataPtr job)


 /**
- * qemuBlockJobSyncEndDisk:
+ * qemuBlockJobSyncEnd:
  * @vm: domain
  * @disk: domain disk
  *
@@ -419,16 +419,16 @@ qemuBlockJobSyncBegin(qemuBlockJobDataPtr job)
  * qemuBlockJobStartupFinalize will be called.
  */
 void
-qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
-int asyncJob,
-virDomainDiskDefPtr disk)
+qemuBlockJobSyncEnd(virDomainObjPtr vm,
+qemuBlockJobDataPtr job,
+int asyncJob)
 {
-qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+const char *diskdst = NULL;

-if (!job)
-return;
+if (job->disk)
+diskdst = job->disk->dst;

-VIR_DEBUG("disk=%s", disk->dst);
+VIR_DEBUG("disk=%s", NULLSTR(diskdst));
 qemuBlockJobUpdate(vm, job, asyncJob);
 job->synchronous = false;
 }
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 8c567ec886..0ec9fd17b7 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -99,9 +99,9 @@ int qemuBlockJobUpdate(virDomainObjPtr vm,
int asyncJob);

 void qemuBlockJobSyncBegin(qemuBlockJobDataPtr job);
-void qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
- int asyncJob,
- virDomainDiskDefPtr disk);
+void qemuBlockJobSyncEnd(virDomainObjPtr vm,
+ qemuBlockJobDataPtr job,
+ int asyncJob);

 qemuBlockJobDataPtr
 qemuBlockJobGetByDisk(virDomainDiskDefPtr disk)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 4ffa5b573d..ff113ae57b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17408,8 +17408,8 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
 }

  endjob:
-if (disk)
-qemuBlockJobSyncEndDisk(vm, QEMU_ASYNC_JOB_NONE, disk);
+if (job && !async)
+qemuBlockJobSyncEnd(vm, job, QEMU_ASYNC_JOB_NONE);
 qemuDomainObjEndJob(driver, vm);

  cleanup:
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index bed8eed563..4a6f631689 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -721,7 +721,7 @@ qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver,
 err = virSaveLastError();
 failed = true;
 }
-qemuBlockJobSyncEndDisk(vm, asyncJob, disk);
+qemuBlockJobSyncEnd(vm, job, asyncJob);
 diskPriv->migrating = false;
 }

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 23/51] qemu: blockjob: Convert qemuBlockJobSyncBeginDisk to work with the job

2018-12-12 Thread Peter Krempa
Modify qemuBlockJobSyncBeginDisk to operate on qemuBlockt sJobDataPtr and
rename it accordingly.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 11 +++
 src/qemu/qemu_blockjob.h  |  2 +-
 src/qemu/qemu_driver.c| 10 +-
 src/qemu/qemu_migration.c | 11 +++
 4 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index c6b70c5388..0b2c667dae 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -359,7 +359,7 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,


 /**
- * qemuBlockJobSyncBeginDisk:
+ * qemuBlockJobSyncBegin:
  * @disk: domain disk
  *
  * Begin a new synchronous block job for @disk. The synchronous
@@ -372,11 +372,14 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,
  * is called.
  */
 void
-qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk)
+qemuBlockJobSyncBegin(qemuBlockJobDataPtr job)
 {
-qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+const char *diskdst = NULL;

-VIR_DEBUG("disk=%s", disk->dst);
+if (job->disk)
+diskdst = job->disk->dst;
+
+VIR_DEBUG("disk=%s", NULLSTR(diskdst));
 job->synchronous = true;
 job->newstate = -1;
 }
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 6f6d0aa691..0c2ce46986 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -80,7 +80,7 @@ int qemuBlockJobUpdateDisk(virDomainObjPtr vm,
virDomainDiskDefPtr disk,
char **error);

-void qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk);
+void qemuBlockJobSyncBegin(qemuBlockJobDataPtr job);
 void qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
  int asyncJob,
  virDomainDiskDefPtr disk);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5eace06099..5fd92ca0c1 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -17316,6 +17316,7 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
 bool save = false;
 bool pivot = !!(flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT);
 bool async = !!(flags & VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC);
+qemuBlockJobDataPtr job = NULL;
 virDomainObjPtr vm;
 int ret = -1;

@@ -17343,6 +17344,12 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
 if (!(device = qemuAliasDiskDriveFromDisk(disk)))
 goto endjob;

+if (!(job = qemuBlockJobDiskGetJob(disk))) {
+virReportError(VIR_ERR_INVALID_ARG,
+   _("disk %s does not have an active block job"), 
disk->dst);
+goto endjob;
+}
+
 if (disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_NONE &&
 disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_READY) {
 virReportError(VIR_ERR_OPERATION_INVALID,
@@ -17352,7 +17359,7 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
 }

 if (!async)
-qemuBlockJobSyncBeginDisk(disk);
+qemuBlockJobSyncBegin(job);

 if (pivot) {
 if ((ret = qemuDomainBlockPivot(driver, vm, device, disk)) < 0)
@@ -17407,6 +17414,7 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
 qemuDomainObjEndJob(driver, vm);

  cleanup:
+virObjectUnref(job);
 virObjectUnref(cfg);
 VIR_FREE(device);
 virDomainObjEndAPI(&vm);
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 837ed39efe..b9119c5b89 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -911,7 +911,7 @@ qemuMigrationSrcNBDStorageCopyOne(virQEMUDriverPtr driver,
 if (!(job = qemuBlockJobDiskNew(disk, QEMU_BLOCKJOB_TYPE_COPY)))
 goto cleanup;

-qemuBlockJobSyncBeginDisk(disk);
+qemuBlockJobSyncBegin(job);

 if (flags & VIR_MIGRATE_TLS) {
 rc = qemuMigrationSrcNBDStorageCopyBlockdev(driver, vm,
@@ -5393,16 +5393,19 @@ qemuMigrationSrcCancel(virQEMUDriverPtr driver,
 for (i = 0; i < vm->def->ndisks; i++) {
 virDomainDiskDefPtr disk = vm->def->disks[i];
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+qemuBlockJobDataPtr job;

-if (!diskPriv->blockjob->started)
+if (!(job = qemuBlockJobDiskGetJob(disk)) ||
+!job->started)
 diskPriv->migrating = false;

 if (diskPriv->migrating) {
-qemuBlockJobSyncBeginDisk(disk);
+qemuBlockJobSyncBegin(job);
 storage = true;
 }
-}

+virObjectUnref(job);
+}

 if (storage &&
 qemuMigrationSrcNBDCopyCancel(driver, vm, false,
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 19/51] qemu: blockjob: Drop unnecessary calls to qemuBlockJobSyncEndDisk

2018-12-12 Thread Peter Krempa
If the job wasn't started, we don't need to end the synchronous job. Add
a note and drop the unnecessary calls.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 4 +++-
 src/qemu/qemu_migration.c | 8 ++--
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index a3dc231b32..17657a9d9b 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -391,7 +391,9 @@ qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk)
  * @disk: domain disk
  *
  * End a synchronous block job for @disk. Any pending block job event
- * for the disk is processed.
+ * for the disk is processed. Note that it's not necessary to call this 
function
+ * in case the block job was not started successfully if
+ * qemuBlockJobStartupFinalize will be called.
  */
 void
 qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 79ad2efe75..dbf35b0829 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -703,10 +703,8 @@ qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver,
 virDomainDiskDefPtr disk = vm->def->disks[i];
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);

-if (!diskPriv->blockjob->started) {
-qemuBlockJobSyncEndDisk(vm, asyncJob, disk);
+if (!diskPriv->blockjob->started)
 diskPriv->migrating = false;
-}

 if (!diskPriv->migrating)
 continue;
@@ -929,10 +927,8 @@ qemuMigrationSrcNBDStorageCopyOne(virQEMUDriverPtr driver,
mirror_flags);
 }

-if (rc < 0) {
-qemuBlockJobSyncEndDisk(vm, QEMU_ASYNC_JOB_MIGRATION_OUT, disk);
+if (rc < 0)
 goto cleanup;
-}

 VIR_FREE(diskAlias);
 diskPriv->migrating = true;
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 20/51] qemu: blockjob: Add reference to disk into struct qemuBlockJobData

2018-12-12 Thread Peter Krempa
Block jobs can also happen on objects which are not a disk at a given
point (e.g. the frontend was not hotplugged yet) and thus will be
eventually kept separately. Add a reference back to the disk for
blockjobs which do correspond to a disk.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 1 +
 src/qemu/qemu_blockjob.h | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 17657a9d9b..7bbe582722 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -99,6 +99,7 @@ qemuBlockJobDataPtr
 qemuBlockJobDiskNew(virDomainDiskDefPtr disk)
 {
 qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+job->disk = disk;

 qemuBlockJobDataReset(job);
 return virObjectRef(job);
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 3d1b389dec..feaee4dee3 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -32,6 +32,8 @@ typedef qemuBlockJobData *qemuBlockJobDataPtr;
 struct _qemuBlockJobData {
 virObject parent;

+virDomainDiskDefPtr disk; /* may be NULL, if blockjob does not corrspond 
to any disk */
+
 bool started;
 int type;
 char *errmsg;
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 22/51] qemu: blockjob: Pass in job to qemuBlockJobEventProcessLegacy

2018-12-12 Thread Peter Krempa
Don't split out individual fields, just pass in the job.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 26 +++---
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 531de035af..c6b70c5388 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -257,9 +257,7 @@ qemuBlockJobEventProcessLegacyCompleted(virQEMUDriverPtr 
driver,
  * qemuBlockJobEventProcessLegacy:
  * @driver: qemu driver
  * @vm: domain
- * @disk: domain disk
- * @type: block job type
- * @status: block job status
+ * @job: job to process events for
  *
  * Update disk's mirror state in response to a block job event
  * from QEMU. For mirror state's that must survive libvirt
@@ -268,25 +266,24 @@ qemuBlockJobEventProcessLegacyCompleted(virQEMUDriverPtr 
driver,
 static void
 qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
virDomainObjPtr vm,
-   virDomainDiskDefPtr disk,
-   int asyncJob,
-   int type,
-   int status)
+   qemuBlockJobDataPtr job,
+   int asyncJob)
 {
 virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+virDomainDiskDefPtr disk = job->disk;
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);

-VIR_DEBUG("disk=%s, mirrorState=%s, type=%d, status=%d",
+VIR_DEBUG("disk=%s, mirrorState=%s, type=%d, newstate=%d",
   disk->dst,
   NULLSTR(virDomainDiskMirrorStateTypeToString(disk->mirrorState)),
-  type,
-  status);
+  job->type,
+  job->newstate);

-qemuBlockJobEmitEvents(driver, vm, disk, type, status);
+qemuBlockJobEmitEvents(driver, vm, disk, job->type, job->newstate);

 /* If we completed a block pull or commit, then update the XML
  * to match.  */
-switch ((virConnectDomainEventBlockJobStatus) status) {
+switch ((virConnectDomainEventBlockJobStatus) job->newstate) {
 case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
 qemuBlockJobEventProcessLegacyCompleted(driver, vm, disk, asyncJob);
 break;
@@ -314,7 +311,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
 if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 
0)
 VIR_WARN("Unable to save status on vm %s after block job", 
vm->def->name);

-if (status == VIR_DOMAIN_BLOCK_JOB_COMPLETED && vm->newDef) {
+if (job->newstate == VIR_DOMAIN_BLOCK_JOB_COMPLETED && vm->newDef) {
 if (virDomainSaveConfig(cfg->configDir, driver->caps, vm->newDef) < 0)
 VIR_WARN("Unable to update persistent definition on vm %s "
  "after block job", vm->def->name);
@@ -349,8 +346,7 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,
 *error = NULL;

 if (state != -1) {
-qemuBlockJobEventProcessLegacy(priv->driver, vm, disk, asyncJob,
-   job->type, state);
+qemuBlockJobEventProcessLegacy(priv->driver, vm, job, asyncJob);
 job->newstate = -1;
 if (error)
 VIR_STEAL_PTR(*error, job->errmsg);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 15/51] qemu: blockjob: Turn struct qemuBlockJobData into a virObject

2018-12-12 Thread Peter Krempa
Reference counting will simplify semantics of the lifecycle of the
object.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 33 -
 src/qemu/qemu_blockjob.h |  5 +++--
 src/qemu/qemu_domain.c   |  4 ++--
 3 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index a7cdc3c068..cf1710a0e8 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -42,14 +42,37 @@
 VIR_LOG_INIT("qemu.qemu_blockjob");


-void
-qemuBlockJobDataFree(qemuBlockJobDataPtr job)
+static virClassPtr qemuBlockJobDataClass;
+
+
+static void
+qemuBlockJobDataDispose(void *obj)
 {
-if (!job)
-return;
+qemuBlockJobDataPtr job = obj;

 VIR_FREE(job->errmsg);
-VIR_FREE(job);
+}
+
+
+static int
+qemuBlockJobDataOnceInit(void)
+{
+if (!VIR_CLASS_NEW(qemuBlockJobData, virClassForObject()))
+return -1;
+
+return 0;
+}
+
+
+VIR_ONCE_GLOBAL_INIT(qemuBlockJobData)
+
+qemuBlockJobDataPtr
+qemuBlockJobDataNew(void)
+{
+if (qemuBlockJobDataInitialize() < 0)
+return NULL;
+
+return virObjectNew(qemuBlockJobDataClass);
 }


diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 1479c6f720..de1ad7039d 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -30,6 +30,8 @@ typedef struct _qemuBlockJobData qemuBlockJobData;
 typedef qemuBlockJobData *qemuBlockJobDataPtr;

 struct _qemuBlockJobData {
+virObject parent;
+
 bool started;
 int type;
 int status;
@@ -37,8 +39,7 @@ struct _qemuBlockJobData {
 bool synchronous; /* API call is waiting for this job */
 };

-void
-qemuBlockJobDataFree(qemuBlockJobDataPtr job);
+qemuBlockJobDataPtr qemuBlockJobDataNew(void);

 int qemuBlockJobUpdateDisk(virDomainObjPtr vm,
int asyncJob,
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 5a64231f95..9c3ab426bd 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1062,7 +1062,7 @@ qemuDomainDiskPrivateNew(void)
 if (!(priv = virObjectNew(qemuDomainDiskPrivateClass)))
 return NULL;

-if (VIR_ALLOC(priv->blockjob) < 0) {
+if (!(priv->blockjob = qemuBlockJobDataNew())) {
 virObjectUnref(priv);
 priv = NULL;
 }
@@ -1078,7 +1078,7 @@ qemuDomainDiskPrivateDispose(void *obj)
 virStorageSourceFree(priv->migrSource);
 VIR_FREE(priv->qomName);
 VIR_FREE(priv->nodeCopyOnRead);
-qemuBlockJobDataFree(priv->blockjob);
+virObjectUnref(priv->blockjob);
 }

 static virClassPtr qemuDomainStorageSourcePrivateClass;
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 27/51] qemu: blockjob: Consume new block job state in the processing function

2018-12-12 Thread Peter Krempa
The processing function modifies the job state so it should make sure
that the variable holding the new state is cleared properly and not the
caller. The caller should only deal with the job state and not the
transition that happened.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 15 +--
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 7aaa439791..49e747ebbb 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -285,6 +285,9 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
   job->state,
   job->newstate);

+if (job->newstate == -1)
+return;
+
 qemuBlockJobEmitEvents(driver, vm, disk, job->type, job->newstate);

 /* If we completed a block pull or commit, then update the XML
@@ -314,6 +317,7 @@ qemuBlockJobEventProcessLegacy(virQEMUDriverPtr driver,
 }

 job->state = job->newstate;
+job->newstate = -1;

 if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 
0)
 VIR_WARN("Unable to save status on vm %s after block job", 
vm->def->name);
@@ -346,14 +350,13 @@ qemuBlockJobUpdateDisk(virDomainObjPtr vm,
 {
 qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
 qemuDomainObjPrivatePtr priv = vm->privateData;
-int state = job->newstate;

-if (state != -1) {
-qemuBlockJobEventProcessLegacy(priv->driver, vm, job, asyncJob);
-job->newstate = -1;
-}
+if (job->newstate == -1)
+return -1;
+
+qemuBlockJobEventProcessLegacy(priv->driver, vm, job, asyncJob);

-return state;
+return job->state;
 }


-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 18/51] qemu: blockjob: Add functions for block job state control

2018-12-12 Thread Peter Krempa
Rather than direclty modifying fields in the qemuBlockJobDataPtr
structure add a bunch of fields which allow to do the transitions.

This will help later when adding more complexity to the job handing.

APIs introduced in this patch are:

qemuBlockJobDiskNew - prepare for starting a new blockjob on a disk
qemuBlockJobDiskGetJob - get the block job data structure for a disk

For individual job state manipulation the following APIs are added:
qemuBlockJobStarted - Sets the job as started with qemu. Until that
  the job can be cancelled without asking qemu.

qemuBlockJobStartupFinalize - finalize job startup. If the job was
  started in qemu already, just releases
  reference to the job object. Otherwise
  clears everything as if the job was never
  started.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 81 +++
 src/qemu/qemu_blockjob.h  | 19 +
 src/qemu/qemu_driver.c| 31 ---
 src/qemu/qemu_migration.c |  7 +++-
 src/qemu/qemu_process.c   | 17 
 5 files changed, 141 insertions(+), 14 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 252f1640b2..a3dc231b32 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -76,6 +76,87 @@ qemuBlockJobDataNew(void)
 }


+static void
+qemuBlockJobDataReset(qemuBlockJobDataPtr job)
+{
+job->started = false;
+job->type = -1;
+job->newstate = -1;
+VIR_FREE(job->errmsg);
+job->synchronous = false;
+}
+
+
+/**
+ * qemuBlockJobDiskNew:
+ * @disk: disk definition
+ *
+ * Start/associate a new blockjob with @disk.
+ *
+ * Returns 0 on success and -1 on failure.
+ */
+qemuBlockJobDataPtr
+qemuBlockJobDiskNew(virDomainDiskDefPtr disk)
+{
+qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+
+qemuBlockJobDataReset(job);
+return virObjectRef(job);
+}
+
+
+/**
+ * qemuBlockJobDiskGetJob:
+ * @disk: disk definition
+ *
+ * Get a reference to the block job data object associated with @disk.
+ */
+qemuBlockJobDataPtr
+qemuBlockJobDiskGetJob(virDomainDiskDefPtr disk)
+{
+qemuBlockJobDataPtr job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+
+if (!job)
+return NULL;
+
+return virObjectRef(job);
+}
+
+
+/**
+ * qemuBlockJobStarted:
+ * @job: job data
+ *
+ * Mark @job as started in qemu.
+ */
+void
+qemuBlockJobStarted(qemuBlockJobDataPtr job)
+{
+job->started = true;
+}
+
+
+/**
+ * qemuBlockJobStartupFinalize:
+ * @job: job being started
+ *
+ * Cancels and clears the job private data if the job was not started with
+ * qemu (see qemuBlockJobStarted) or just clears up the local reference
+ * to @job if it was started.
+ */
+void
+qemuBlockJobStartupFinalize(qemuBlockJobDataPtr job)
+{
+if (!job)
+return;
+
+if (!job->started)
+qemuBlockJobDataReset(job);
+
+virObjectUnref(job);
+}
+
+
 /**
  * qemuBlockJobEmitEvents:
  *
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 7761eee6ae..3d1b389dec 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -42,6 +42,21 @@ struct _qemuBlockJobData {

 qemuBlockJobDataPtr qemuBlockJobDataNew(void);

+qemuBlockJobDataPtr
+qemuBlockJobDiskNew(virDomainDiskDefPtr disk)
+ATTRIBUTE_NONNULL(1);
+
+qemuBlockJobDataPtr
+qemuBlockJobDiskGetJob(virDomainDiskDefPtr disk)
+ATTRIBUTE_NONNULL(1);
+
+void
+qemuBlockJobStarted(qemuBlockJobDataPtr job)
+ATTRIBUTE_NONNULL(1);
+
+void
+qemuBlockJobStartupFinalize(qemuBlockJobDataPtr job);
+
 int qemuBlockJobUpdateDisk(virDomainObjPtr vm,
int asyncJob,
virDomainDiskDefPtr disk,
@@ -52,4 +67,8 @@ void qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
  int asyncJob,
  virDomainDiskDefPtr disk);

+qemuBlockJobDataPtr
+qemuBlockJobGetByDisk(virDomainDiskDefPtr disk)
+ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
 #endif /* __QEMU_BLOCKJOB_H__ */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 637307806b..9e5171744e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4716,7 +4716,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
  int status)
 {
 virDomainDiskDefPtr disk;
-qemuBlockJobDataPtr job;
+qemuBlockJobDataPtr job = NULL;

 if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
 return;
@@ -4731,7 +4731,11 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 goto endjob;
 }

-job = QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob;
+if (!(job = qemuBlockJobDiskGetJob(disk))) {
+if (!(job = qemuBlockJobDiskNew(disk)))
+goto endjob;
+qemuBlockJobStarted(job);
+}

 job->type = type;
 job->newstate = status;
@@ -4739,6 +4743,7 @@ processBlockJobEvent(virQEMUDriverPtr drive

[libvirt] [PATCH RFC 05/51] qemu: blockjob: Rename public APIs

2018-12-12 Thread Peter Krempa
All the public APIs of the qemu_blockjob module operate on a 'disk'.
Since I'll be adding APIs which operate on a job later let's rename the
existing ones.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c  | 28 ++--
 src/qemu/qemu_blockjob.h  | 16 
 src/qemu/qemu_driver.c| 10 +-
 src/qemu/qemu_migration.c | 20 ++--
 4 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 32fa9876b5..8b51235795 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -197,7 +197,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,


 /**
- * qemuBlockJobUpdate:
+ * qemuBlockJobUpdateDisk:
  * @vm: domain
  * @disk: domain disk
  * @error: error (output parameter)
@@ -208,10 +208,10 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
  * Returns the block job event processed or -1 if there was no pending event.
  */
 int
-qemuBlockJobUpdate(virDomainObjPtr vm,
-   qemuDomainAsyncJob asyncJob,
-   virDomainDiskDefPtr disk,
-   char **error)
+qemuBlockJobUpdateDisk(virDomainObjPtr vm,
+   qemuDomainAsyncJob asyncJob,
+   virDomainDiskDefPtr disk,
+   char **error)
 {
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
 qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -236,20 +236,20 @@ qemuBlockJobUpdate(virDomainObjPtr vm,


 /**
- * qemuBlockJobSyncBegin:
+ * qemuBlockJobSyncBeginDisk:
  * @disk: domain disk
  *
  * Begin a new synchronous block job for @disk. The synchronous
- * block job is ended by a call to qemuBlockJobSyncEnd, or by
+ * block job is ended by a call to qemuBlockJobSyncEndDisk, or by
  * the guest quitting.
  *
  * During a synchronous block job, a block job event for @disk
  * will not be processed asynchronously. Instead, it will be
- * processed only when qemuBlockJobUpdate or qemuBlockJobSyncEnd
+ * processed only when qemuBlockJobUpdateDisk or qemuBlockJobSyncEndDisk
  * is called.
  */
 void
-qemuBlockJobSyncBegin(virDomainDiskDefPtr disk)
+qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk)
 {
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);

@@ -260,7 +260,7 @@ qemuBlockJobSyncBegin(virDomainDiskDefPtr disk)


 /**
- * qemuBlockJobSyncEnd:
+ * qemuBlockJobSyncEndDisk:
  * @vm: domain
  * @disk: domain disk
  *
@@ -268,11 +268,11 @@ qemuBlockJobSyncBegin(virDomainDiskDefPtr disk)
  * for the disk is processed.
  */
 void
-qemuBlockJobSyncEnd(virDomainObjPtr vm,
-qemuDomainAsyncJob asyncJob,
-virDomainDiskDefPtr disk)
+qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
+qemuDomainAsyncJob asyncJob,
+virDomainDiskDefPtr disk)
 {
 VIR_DEBUG("disk=%s", disk->dst);
-qemuBlockJobUpdate(vm, asyncJob, disk, NULL);
+qemuBlockJobUpdateDisk(vm, asyncJob, disk, NULL);
 QEMU_DOMAIN_DISK_PRIVATE(disk)->blockJobSync = false;
 }
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index c14d26a6a1..9f7677dc1e 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -26,14 +26,14 @@
 # include "qemu_conf.h"
 # include "qemu_domain.h"

-int qemuBlockJobUpdate(virDomainObjPtr vm,
-   qemuDomainAsyncJob asyncJob,
-   virDomainDiskDefPtr disk,
-   char **error);
+int qemuBlockJobUpdateDisk(virDomainObjPtr vm,
+   qemuDomainAsyncJob asyncJob,
+   virDomainDiskDefPtr disk,
+   char **error);

-void qemuBlockJobSyncBegin(virDomainDiskDefPtr disk);
-void qemuBlockJobSyncEnd(virDomainObjPtr vm,
- qemuDomainAsyncJob asyncJob,
- virDomainDiskDefPtr disk);
+void qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk);
+void qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
+ qemuDomainAsyncJob asyncJob,
+ virDomainDiskDefPtr disk);

 #endif /* __QEMU_BLOCKJOB_H__ */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c582e255a2..1b2a2d70ec 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4736,7 +4736,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 diskPriv->blockJobType = type;
 diskPriv->blockJobStatus = status;

-qemuBlockJobUpdate(vm, QEMU_ASYNC_JOB_NONE, disk, NULL);
+qemuBlockJobUpdateDisk(vm, QEMU_ASYNC_JOB_NONE, disk, NULL);

  endjob:
 qemuDomainObjEndJob(driver, vm);
@@ -17361,7 +17361,7 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
 }

 if (!async)
-qemuBlockJobSyncBegin(disk);
+qemuBlockJobSyncBeginDisk(disk);

 if (pivot) {
 if ((ret = qemuDomainBlockPivot(driver, vm, device, disk)) < 0)
@@ -17400,19 +17400,19 @@ qemuDomainBlockJobAbort(virDomainPtr dom,
  * 

[libvirt] [PATCH RFC 04/51] qemu: blockjob: Unexport qemuBlockJobEventProcess

2018-12-12 Thread Peter Krempa
The function is now only called locally. Some code movement was
necessary to avoid forward declarations.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 80 
 src/qemu/qemu_blockjob.h |  6 ---
 2 files changed, 40 insertions(+), 46 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index d38674a9d0..32fa9876b5 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -69,45 +69,6 @@ qemuBlockJobEmitEvents(virQEMUDriverPtr driver,
 }


-/**
- * qemuBlockJobUpdate:
- * @vm: domain
- * @disk: domain disk
- * @error: error (output parameter)
- *
- * Update disk's mirror state in response to a block job event stored in
- * blockJobStatus by qemuProcessHandleBlockJob event handler.
- *
- * Returns the block job event processed or -1 if there was no pending event.
- */
-int
-qemuBlockJobUpdate(virDomainObjPtr vm,
-   qemuDomainAsyncJob asyncJob,
-   virDomainDiskDefPtr disk,
-   char **error)
-{
-qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
-qemuDomainObjPrivatePtr priv = vm->privateData;
-int status = diskPriv->blockJobStatus;
-
-if (error)
-*error = NULL;
-
-if (status != -1) {
-qemuBlockJobEventProcess(priv->driver, vm, disk, asyncJob,
- diskPriv->blockJobType,
- diskPriv->blockJobStatus);
-diskPriv->blockJobStatus = -1;
-if (error)
-VIR_STEAL_PTR(*error, diskPriv->blockJobError);
-else
-VIR_FREE(diskPriv->blockJobError);
-}
-
-return status;
-}
-
-
 /**
  * qemuBlockJobEventProcess:
  * @driver: qemu driver
@@ -120,7 +81,7 @@ qemuBlockJobUpdate(virDomainObjPtr vm,
  * from QEMU. For mirror state's that must survive libvirt
  * restart, also update the domain's status XML.
  */
-void
+static void
 qemuBlockJobEventProcess(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  virDomainDiskDefPtr disk,
@@ -235,6 +196,45 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
 }


+/**
+ * qemuBlockJobUpdate:
+ * @vm: domain
+ * @disk: domain disk
+ * @error: error (output parameter)
+ *
+ * Update disk's mirror state in response to a block job event stored in
+ * blockJobStatus by qemuProcessHandleBlockJob event handler.
+ *
+ * Returns the block job event processed or -1 if there was no pending event.
+ */
+int
+qemuBlockJobUpdate(virDomainObjPtr vm,
+   qemuDomainAsyncJob asyncJob,
+   virDomainDiskDefPtr disk,
+   char **error)
+{
+qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+qemuDomainObjPrivatePtr priv = vm->privateData;
+int status = diskPriv->blockJobStatus;
+
+if (error)
+*error = NULL;
+
+if (status != -1) {
+qemuBlockJobEventProcess(priv->driver, vm, disk, asyncJob,
+ diskPriv->blockJobType,
+ diskPriv->blockJobStatus);
+diskPriv->blockJobStatus = -1;
+if (error)
+VIR_STEAL_PTR(*error, diskPriv->blockJobError);
+else
+VIR_FREE(diskPriv->blockJobError);
+}
+
+return status;
+}
+
+
 /**
  * qemuBlockJobSyncBegin:
  * @disk: domain disk
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index cee3ee21c4..c14d26a6a1 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -30,12 +30,6 @@ int qemuBlockJobUpdate(virDomainObjPtr vm,
qemuDomainAsyncJob asyncJob,
virDomainDiskDefPtr disk,
char **error);
-void qemuBlockJobEventProcess(virQEMUDriverPtr driver,
-  virDomainObjPtr vm,
-  virDomainDiskDefPtr disk,
-  qemuDomainAsyncJob asyncJob,
-  int type,
-  int status);

 void qemuBlockJobSyncBegin(virDomainDiskDefPtr disk);
 void qemuBlockJobSyncEnd(virDomainObjPtr vm,
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 06/51] qemu: blockjob: Remove header dependency on qemu_domain.h

2018-12-12 Thread Peter Krempa
The blockjob module uses 'qemuDomainAsyncJob' in it's public headers.
As I plan adding a new structure containing job data which will need to
be included in "qemu_domain.h" it's necessary to break the circular
dependency.

Convert 'qemuDomainAsyncJob' type to 'int' as it's an enum.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 6 +++---
 src/qemu/qemu_blockjob.h | 5 ++---
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 8b51235795..1b6d16cbb9 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -85,7 +85,7 @@ static void
 qemuBlockJobEventProcess(virQEMUDriverPtr driver,
  virDomainObjPtr vm,
  virDomainDiskDefPtr disk,
- qemuDomainAsyncJob asyncJob,
+ int asyncJob,
  int type,
  int status)
 {
@@ -209,7 +209,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
  */
 int
 qemuBlockJobUpdateDisk(virDomainObjPtr vm,
-   qemuDomainAsyncJob asyncJob,
+   int asyncJob,
virDomainDiskDefPtr disk,
char **error)
 {
@@ -269,7 +269,7 @@ qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk)
  */
 void
 qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
-qemuDomainAsyncJob asyncJob,
+int asyncJob,
 virDomainDiskDefPtr disk)
 {
 VIR_DEBUG("disk=%s", disk->dst);
diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h
index 9f7677dc1e..0c440757f2 100644
--- a/src/qemu/qemu_blockjob.h
+++ b/src/qemu/qemu_blockjob.h
@@ -24,16 +24,15 @@

 # include "internal.h"
 # include "qemu_conf.h"
-# include "qemu_domain.h"

 int qemuBlockJobUpdateDisk(virDomainObjPtr vm,
-   qemuDomainAsyncJob asyncJob,
+   int asyncJob,
virDomainDiskDefPtr disk,
char **error);

 void qemuBlockJobSyncBeginDisk(virDomainDiskDefPtr disk);
 void qemuBlockJobSyncEndDisk(virDomainObjPtr vm,
- qemuDomainAsyncJob asyncJob,
+ int asyncJob,
  virDomainDiskDefPtr disk);

 #endif /* __QEMU_BLOCKJOB_H__ */
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 02/51] qemu: blockjob: Emit VIR_DOMAIN_EVENT_ID_BLOCK_JOB only for local disks

2018-12-12 Thread Peter Krempa
The event reports the disk path to identify the disk which makes sense
only for local disks. Additionally network backed disks like NBD don't
need to have a path so the callback would return NULL.

Report VIR_DOMAIN_EVENT_ID_BLOCK_JOB only for non-empty local disks.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index ea327b83fe..d38674a9d0 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -46,7 +46,7 @@ VIR_LOG_INIT("qemu.qemu_blockjob");
  * qemuBlockJobEmitEvents:
  *
  * Emits the VIR_DOMAIN_EVENT_ID_BLOCK_JOB and VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2
- * for a block job.
+ * for a block job. The former event is emitted only for local disks.
  */
 static void
 qemuBlockJobEmitEvents(virQEMUDriverPtr driver,
@@ -58,8 +58,11 @@ qemuBlockJobEmitEvents(virQEMUDriverPtr driver,
 virObjectEventPtr event = NULL;
 virObjectEventPtr event2 = NULL;

-event = virDomainEventBlockJobNewFromObj(vm, disk->src->path, type, 
status);
-virObjectEventStateQueue(driver->domainEventState, event);
+if (virStorageSourceIsLocalStorage(disk->src) &&
+!virStorageSourceIsEmpty(disk->src)) {
+event = virDomainEventBlockJobNewFromObj(vm, disk->src->path, type, 
status);
+virObjectEventStateQueue(driver->domainEventState, event);
+}

 event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type, status);
 virObjectEventStateQueue(driver->domainEventState, event2);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 03/51] qemu: processBlockJobEvent: Use qemuBlockJobUpdate to process block job events

2018-12-12 Thread Peter Krempa
Replace use of qemuBlockJobEventProcess with the general helper. A small
tweak is required to pass in the 'type' and 'status' of the job via the
appropriate private data variables.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_driver.c | 14 --
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d0cf2c115a..c582e255a2 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4716,6 +4716,7 @@ processBlockJobEvent(virQEMUDriverPtr driver,
  int status)
 {
 virDomainDiskDefPtr disk;
+qemuDomainDiskPrivatePtr diskPriv;

 if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
 return;
@@ -4725,8 +4726,17 @@ processBlockJobEvent(virQEMUDriverPtr driver,
 goto endjob;
 }

-if ((disk = qemuProcessFindDomainDiskByAliasOrQOM(vm, diskAlias, NULL)))
-qemuBlockJobEventProcess(driver, vm, disk, QEMU_ASYNC_JOB_NONE, type, 
status);
+if (!(disk = qemuProcessFindDomainDiskByAliasOrQOM(vm, diskAlias, NULL))) {
+VIR_DEBUG("disk %s not found", diskAlias);
+goto endjob;
+}
+
+diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+
+diskPriv->blockJobType = type;
+diskPriv->blockJobStatus = status;
+
+qemuBlockJobUpdate(vm, QEMU_ASYNC_JOB_NONE, disk, NULL);

  endjob:
 qemuDomainObjEndJob(driver, vm);
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 01/51] qemu: blockjob: Extract emitting of libvirt events

2018-12-12 Thread Peter Krempa
Put the emitting of VIR_DOMAIN_EVENT_ID_BLOCK_JOB and
VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2 into a separate function.

Signed-off-by: Peter Krempa 
---
 src/qemu/qemu_blockjob.c | 37 ++---
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 0f52996ade..ea327b83fe 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -42,6 +42,30 @@
 VIR_LOG_INIT("qemu.qemu_blockjob");


+/**
+ * qemuBlockJobEmitEvents:
+ *
+ * Emits the VIR_DOMAIN_EVENT_ID_BLOCK_JOB and VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2
+ * for a block job.
+ */
+static void
+qemuBlockJobEmitEvents(virQEMUDriverPtr driver,
+   virDomainObjPtr vm,
+   virDomainDiskDefPtr disk,
+   virDomainBlockJobType type,
+   virConnectDomainEventBlockJobStatus status)
+{
+virObjectEventPtr event = NULL;
+virObjectEventPtr event2 = NULL;
+
+event = virDomainEventBlockJobNewFromObj(vm, disk->src->path, type, 
status);
+virObjectEventStateQueue(driver->domainEventState, event);
+
+event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type, status);
+virObjectEventStateQueue(driver->domainEventState, event2);
+}
+
+
 /**
  * qemuBlockJobUpdate:
  * @vm: domain
@@ -101,9 +125,6 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
  int type,
  int status)
 {
-virObjectEventPtr event = NULL;
-virObjectEventPtr event2 = NULL;
-const char *path;
 virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
 virDomainDiskDefPtr persistDisk = NULL;
 qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
@@ -114,14 +135,11 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
   type,
   status);

-/* Have to generate two variants of the event for old vs. new
- * client callbacks */
 if (type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT &&
 disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)
 type = disk->mirrorJob;
-path = virDomainDiskGetSource(disk);
-event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
-event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type, status);
+
+qemuBlockJobEmitEvents(driver, vm, disk, type, status);

 /* If we completed a block pull or commit, then update the XML
  * to match.  */
@@ -210,9 +228,6 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
  "after block job", vm->def->name);
 }

-virObjectEventStateQueue(driver->domainEventState, event);
-virObjectEventStateQueue(driver->domainEventState, event2);
-
 virObjectUnref(cfg);
 }

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH RFC 00/51] refactor block job handling and add support for new event/commands (blockdev-add saga)

2018-12-12 Thread Peter Krempa
This series refactors how libvirt stores block job data and handles
block job events in general. This is done in preparation for -blockdev
support where we'll need to add support for the 'blockdev-create' job
which is not associated to any frontend 'disk' in some cases.

This series introduces a new structure and table of blockjobs currently
running and implements handlers for the new even "JOB_STATUS_CHANGE".

RFC status excuses:
- the series needs much more testing than I did
- the last few patches are true RFC
- I didn't port/refactor the rest of the blockjob finishing code that
  I have for the individual job types after the big refactor so there
  aren't any examples for the -blockdev case yet.

I'll post the link to a repo containing the patches some time later.

Peter Krempa (51):
  qemu: blockjob: Extract emitting of libvirt events
  qemu: blockjob: Emit VIR_DOMAIN_EVENT_ID_BLOCK_JOB only for local
disks
  qemu: processBlockJobEvent: Use qemuBlockJobUpdate to process block
job events
  qemu: blockjob: Unexport qemuBlockJobEventProcess
  qemu: blockjob: Rename public APIs
  qemu: blockjob: Remove header dependency on qemu_domain.h
  qemu: Consolidate disk blockjob variables into a structure
  qemu: process: Consolidate error paths in qemuProcessHandleBlockJob
  qemu: blockjob: Rename qemuBlockJobEventProcess to
qemuBlockJobEventProcessLegacy
  qemu: blockjob: Split out handling of comlpleted jobs
  qemu: migration: Properly note that non-shared-storage migration uses
a blockjob
  qemu: process: refresh block jobs on reconnect
  qemu: driver: Remove block job status reprobing from
qemuDomainBlockPivot
  qemu: migration: Simplify cancellation of migration blockjobs
  qemu: blockjob: Turn struct qemuBlockJobData into a virObject
  qemu: blockjob: Clarify that job 'status' field contains new state
  qemu: migration: Separate startup of disk mirror from migration logic
  qemu: blockjob: Add functions for block job state control
  qemu: blockjob: Drop unnecessary calls to qemuBlockJobSyncEndDisk
  qemu: blockjob: Add reference to disk into struct qemuBlockJobData
  qemu: blockjob: Record job type when starting the job
  qemu: blockjob: Pass in job to qemuBlockJobEventProcessLegacy
  qemu: blockjob: Convert qemuBlockJobSyncBeginDisk to work with the job
  qemu: blockjob: Track current state of blockjob
  qemu: migration: Extract reporting of disk migration error
  qemu: blockjob: Remove error propagation from qemuBlockJobUpdateDisk
  qemu: blockjob: Consume new block job state in the processing function
  qemu: blockjob: Pass job into qemuBlockJobUpdateDisk and rename it
  qemu: Allocate diskPriv->blockjob only when there's a blockjob
  qemu: migration: Don't call qemuBlockJobSyncEndDisk when block job has
terminated
  qemu: blockjob: Convert qemuBlockJobSyncEndDisk to take job instead of
disk
  qemu: blockjob: Add job name into the data
  qemu: domain: Add global table of blockjobs
  qemu: blockjob: Register new and running blockjobs in the global table
  qemu: blockjob: Add string convertors for blockjob type and state
enums
  qemu: domain: Store blockjob data in the status XML
  tests: qemustatusxml2xml: Add test case for block job tracking
  qemu: monitor: Add new fields for 'block-stream' command
  qemu: monitor: Add new fields for 'block-commit' command
  qemu: monitor: Add new fields for 'blockdev-mirror' command
  qemu: monitor: Add support for 'job-dismiss' command
  qemu: monitor: Add support for 'job-cancel' command
  qemu: monitor: Add support for 'job-complete' command
  qemu: monitor: Add infrastructure for 'query-jobs'
  qemu: blockjob: Add 'concluded' state for a block job
  qemu: monitor: Implement support for 'JOB_STATUS_CHANGE' event
  qemu: process: Don't trigger BLOCK_JOB* events with -blockdev
  qemu: blockjob: Add helper to convert monitor job status to internal
state
  qemu: Add handler for job state change event
  qemu: blockjob: Add modern block job event handler
  qemu: process: Refresh -blockdev based blockjobs on reconnect to qemu

 src/qemu/qemu_blockjob.c  | 687 ++
 src/qemu/qemu_blockjob.h  | 111 ++-
 src/qemu/qemu_domain.c| 123 +++-
 src/qemu/qemu_domain.h|  13 +-
 src/qemu/qemu_driver.c| 114 ++-
 src/qemu/qemu_migration.c | 233 +++---
 src/qemu/qemu_monitor.c   | 120 ++-
 src/qemu/qemu_monitor.h   |  82 ++-
 src/qemu/qemu_monitor_json.c  | 239 +-
 src/qemu/qemu_monitor_json.h  |  28 +-
 src/qemu/qemu_process.c   | 179 -
 .../query-jobs-create.json|  20 +
 .../query-jobs-create.result  |  11 +
 .../qemumonitorjsondata/query-jobs-empty.json |   1 +
 .../query-jobs-empty.result   |   0
 tests/qemumonitorjsontest.c   | 101 ++-
 ...

Re: [libvirt] [PATCH v2 2/4] qemu: caps: add QEMU_CAPS_QCOW2_L2_CACHE_SIZE

2018-12-12 Thread Nikolay Shirokovskiy



On 12.12.2018 17:28, John Ferlan wrote:
> 
> 
> On 12/12/18 5:59 AM, Nikolay Shirokovskiy wrote:
>>
>>
>> On 11.12.2018 19:41, John Ferlan wrote:
>>>
>>>
>>> On 12/11/18 6:04 AM, Nikolay Shirokovskiy wrote:


 On 10.12.2018 19:58, John Ferlan wrote:
>
>
> On 11/8/18 8:02 AM, Nikolay Shirokovskiy wrote:
>> For qemu capable of setting l2-cache-size for qcow2 images
>> to INT64_MAX and semantics of upper limit on l2 cache
>> size. We can only check this by qemu version (3.1.0) now.
>>
>> Signed-off-by: Nikolay Shirokovskiy 
>> ---
>>  src/qemu/qemu_capabilities.c | 5 +
>>  src/qemu/qemu_capabilities.h | 1 +
>>  2 files changed, 6 insertions(+)
>>
>
> This patch needs to be updated to top of tree.
>
>> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
>> index 2ca5af3..49a3b60 100644
>> --- a/src/qemu/qemu_capabilities.c
>> +++ b/src/qemu/qemu_capabilities.c
>> @@ -509,6 +509,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
>>"vfio-pci.display",
>>"blockdev",
>>"vfio-ap",
>> +  "qcow2.l2-cache-size",
>
> When you do update, you will need to fix the comma-less entry for
> "egl-headless.rendernode" as well, unless someone else gets to it first.
>
>>  );
>>  
>>  
>> @@ -4117,6 +4118,10 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps,
>>  virQEMUCapsSet(qemuCaps, 
>> QEMU_CAPS_MACHINE_PSERIES_MAX_CPU_COMPAT);
>>  }
>>  
>> +/* l2-cache-size before 3001000 does not accept INT64_MAX */
>> +if (qemuCaps->version >= 3001000)
>> +virQEMUCapsSet(qemuCaps, QEMU_CAPS_QCOW2_L2_CACHE_SIZE);
>> +
>
> Not a fan of this.
>
> The 'l2-cache-size' was supported since QEMU 2.2. A "newer" algorithm
> for cache adjustment has been supported since QEMU 2.12 (and there's
> l2-cache-entry-size that "could be used" to know that). Then there's
> some unreferenced commit indicating usage of INT64_MAX. Tracking that
> down, I find qemu.git commit 6c1c8d5d from Max which enforces MAX_INT.

 This is a failure rather than enforcement. And AFAIU code that limit cache
 to appropriate maximum when INT64_MAX is given in read_cache_sizes:

 *l2_cache_size = MIN(max_l2_cache, l2_cache_max_setting);

 only appeared after release of 3.0 in 

 commit b749562d9822d14ef69c9eaa5f85903010b86c30
 Author: Leonid Bloch 
 Date:   Wed Sep 26 19:04:43 2018 +0300

 qcow2: Assign the L2 cache relatively to the image size


 ie setting cache size to INT64_MAX before 3.1 will fail. In
 other words in earlier versions there were no value to specify that
 cache size need to be set to maximum. You can calculate this value
 yourself knowing disk size and disk cluster size and set it but
 this is not convinient.

>>>
>>> So prior to this patch the max could be 32 MB? And now it's calculate-able?
>>
>> 32 MB is default value on Linux in 3.1 (the patch set it it to 1 MB but later
>> patch 80668d0f increases to 32 MB). 
>>
>> Before the patch one can set greater values but can not set INT64_MAX.
>> The exact value that can be set depends on cluster size due to the check
>> againts INT_MAX you already mentioned. So one can set up to INT_MAX * 
>> cluster_size,
>> but cluster_size is unknown to us (?). Given minium cluster size is 512 
>> bytes, we
>> can set INT_MAX * 512 (1 TB) always. This will cover 64 TB disks for cluster
>> size 512 bytes and 8192 PB for default cluster size. So we should refuse 
>> to start with policy 'maximum' and disk size greater then 64 TB. 
>> Or may be we can just check cluster size at start up. How do you think?
> 
> I'm not sure I'd go through the trouble of determining the size. If
> we're not changing the default cluster_size, then using 512 "seems"
> reasonable (whether others feel the same way who knows yet). I'm not
> even sure if we already get that information - feel free to research and
> add though.
> 
> I'm not sure I would "refuse" to start - think in terms of what is the
> downside to not being able to have a large enough value - well that
> seems to be I/O performance.  If we can get "better" I/O performance by
> providing "something" more than "default" for those environments, then I
> would think that's better than doing nothing or failing to start.
> 
> I'm not sure how much "effort" you want to put into the window of
> support prior to 3.1 where "maximum" is true maximum.  It could be
> simple enough to document that for prior to 3.1 the maximum value is
> limited to XXX. After 3.1 it's essentially unlimited since libvirt can
> provide the maximum integer value to QEMU and QEMU then decides the
> maximum up to that value.  There's ways to wordsmith it - I'm pretty
> sure it's been done before, but I don't have 

Re: [libvirt] [PATCH 0/8] Add tests for Storage Pool startup command line generation

2018-12-12 Thread John Ferlan



On 12/12/18 9:04 AM, Michal Privoznik wrote:
> On 12/4/18 5:47 PM, John Ferlan wrote:
>> Similar to qemuxml2argv and storagevolxml2argv, add storagepoolxml2argvtest
>> in order to check the command line creation for the pool 'Start' commands.
>>
>> Only applicable for pool types with a "@startPool" function - that is disk,
>> fs, iscsi, logical, scsi, and vstorage and further restricted if the pool
>> doesn't use virCommandPtr type processing.
>>
>> This initial series only addresses fs and logical so that it's not "too
>> many patches to review".
>>
>> The iscsi and vstorage pools could have their own tests, with the iscsi
>> ones being more challenging to write.
>>
>> The disk pool does not have the normal command line processing to start
>> something - rather the command line processing is used to validate that
>> the pool about to be started is of a valid type based on the label seen
>> at startup compared to the pool XML. This processing is not easily mocked.
>>
>> The scsi (for NPIV) doesn't use the virCommandPtr style interfaces, but at
>> least that processing is tested in other ways using testCreateVport from
>> test_driver.c.
>>
>> John Ferlan (8):
>>   storage: Extract out mount command creation for FS Backend
>>   storage: Move FS backend mount creation command helper
>>   storage: Move virStorageBackendFileSystemGetPoolSource
>>   tests: Introduce tests for storage pool xml to argv checks
>>   tests: Add storagepool xml test for netfs-auto
>>   storage: Rework virStorageBackendFileSystemMountCmd
>>   logical: Fix @on argument type
>>   storage: Add tests for logical backend startup
>>
>>  src/storage/storage_backend_fs.c  |  77 +---
>>  src/storage/storage_backend_logical.c |  12 +-
>>  src/storage/storage_util.c| 122 
>>  src/storage/storage_util.h|  11 ++
>>  tests/Makefile.am |  12 ++
>>  tests/storagepoolxml2argvdata/pool-fs.argv|   1 +
>>  .../pool-logical-create.argv  |   1 +
>>  .../pool-logical-noname.argv  |   1 +
>>  .../pool-logical-nopath.argv  |   1 +
>>  .../storagepoolxml2argvdata/pool-logical.argv |   1 +
>>  .../pool-netfs-auto.argv  |  
>>  .../pool-netfs-cifs.argv  |   1 +
>>  .../pool-netfs-gluster.argv   |   1 +
>>  tests/storagepoolxml2argvdata/pool-netfs.argv |   1 +
>>  tests/storagepoolxml2argvtest.c   | 175 ++
>>  .../storagepoolxml2xmlin/pool-netfs-auto.xml  |  19 ++
>>  .../storagepoolxml2xmlout/pool-netfs-auto.xml |  20 ++
>>  tests/storagepoolxml2xmltest.c|   1 +
>>  18 files changed, 375 insertions(+), 83 deletions(-)
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-fs.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-create.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-noname.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-nopath.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-auto.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-cifs.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-gluster.argv
>>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs.argv
>>  create mode 100644 tests/storagepoolxml2argvtest.c
>>  create mode 100644 tests/storagepoolxml2xmlin/pool-netfs-auto.xml
>>  create mode 100644 tests/storagepoolxml2xmlout/pool-netfs-auto.xml
>>
> 
> The patches look good from logical POV. However, there is an issue with
> mount/vgchange location on different systems.
> 
> Michal
> 

Hmm... good to know... Maybe I can strip the path to mount/vgchange from
the output... That shouldn't be hard to do (hah!).

I'll see if I can come up with something...

Tks -

John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 4/4] conf: domain: gfx: Iterate over graphics devices when doing validation

2018-12-12 Thread Erik Skultety
On Tue, Dec 11, 2018 at 06:54:31PM -0500, John Ferlan wrote:
>
>
> On 12/7/18 9:47 AM, Erik Skultety wrote:
> > The validation code for graphics has been in place for a while, but
> > because it is only executed from the device iterator, that validation
> > code was never truly run. The unfortunate side effect of this whole mess
>
> dang confusing postparse and validation processing...  when you say
> "device iterator" you meant the hypervisor specific device iterator,
> right?  That is, what's called by deviceValidateCallback or the call
> into qemuDomainDeviceDefValidateGraphics. I'm just trying to follow the
> wording, nothing more, nothing less.
>
> > was that a few capabilities were missing from the test suite, which in
> > turn meant that a few graphics test which expected a failure happily
>
> graphics tests (the s on test)
>
> > accepted whatever failure the parser returned which made them succeed
> > even though in reality we allowed to start a domain with multiple
> > OpenGL-enabled graphics devices.
>
> add blank line between paragraphs
>
> > This patch enables iteration over graphics devices. Unsurprisingly,
> > a few tests started failing as a result, so fix those too.
> >
> > Signed-off-by: Erik Skultety 
> > ---
> >  src/conf/domain_conf.c   | 13 -
> >  tests/qemuxml2argvtest.c |  7 ++-
> >  tests/qemuxml2xmltest.c  | 10 +++---
> >  3 files changed, 21 insertions(+), 9 deletions(-)
> >
> > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> > index 11552bff5b..a4c762a210 100644
> > --- a/src/conf/domain_conf.c
> > +++ b/src/conf/domain_conf.c
> > @@ -3705,6 +3705,7 @@ virDomainSkipBackcompatConsole(virDomainDefPtr def,
> >
> >  typedef enum {
> >  DEVICE_INFO_ITERATE_ALL_CONSOLES = 1 << 0, /* Iterate console[0] */
> > +DEVICE_INFO_ITERATE_GRAPHICS = 1 << 1 /* Iterate graphics */
> >  } virDomainDeviceInfoIterateFlags;
> >
> >  /*
> > @@ -3870,6 +3871,15 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr 
> > def,
> >  return rc;
> >  }
> >
> > +if (iteratorFlags & DEVICE_INFO_ITERATE_GRAPHICS) {
> > +device.type = VIR_DOMAIN_DEVICE_GRAPHICS;
> > +for (i = 0; i < def->ngraphics; i++) {
> > +device.data.graphics = def->graphics[i];
> > +if ((rc = cb(def, &device, NULL, opaque)) != 0)
>
> So the only caller to this passes cb=virDomainDefValidateDeviceIterator
> which ironically doesn't use @info (e.g. the 3rd param):
>
> virDomainDefValidateDeviceIterator(virDomainDefPtr def,
>virDomainDeviceDefPtr dev,
>virDomainDeviceInfoPtr info
> ATTRIBUTE_UNUSED,
>void *opaque)
>
> I know these are generic functions, but some day if someone changes that
> helper to "use" @info can I assume that some test would fail in a most
> spectacular way?
>
> Not a problem here, just looking to confirm my own feeling on this with
> what you'd expect.  You may want to even add a comment noting that for a
> graphics device the @info isn't used (remember my patch2 comment), so
> one has to be careful which callers can set the iterate flag that dumps
> you here.  Say nothing for the called function - if it expects something
> and gets NULL, all bets are off. I can assume it wouldn't be picked up
> by the compiler's ATTRIBUTE_NONNULL too unless the prototype for the @cb
> was set to have that.
>
> > +return rc;
> > +}
> > +}
> > +
> >  /* Coverity is not very happy with this - all dead_error_condition */
> >  #if !STATIC_ANALYSIS
> >  /* This switch statement is here to trigger compiler warning when 
> > adding
> > @@ -6348,7 +6358,8 @@ virDomainDefValidate(virDomainDefPtr def,
> >  /* iterate the devices */
> >  if (virDomainDeviceInfoIterateInternal(def,
> > 
> > virDomainDefValidateDeviceIterator,
> > -   
> > DEVICE_INFO_ITERATE_ALL_CONSOLES,
> > +   
> > (DEVICE_INFO_ITERATE_ALL_CONSOLES |
> > +DEVICE_INFO_ITERATE_GRAPHICS),
> > &data) < 0)
> >  return -1;
> >
> > diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
> > index 528139654c..05451863ad 100644
> > --- a/tests/qemuxml2argvtest.c
> > +++ b/tests/qemuxml2argvtest.c
> > @@ -1299,7 +1299,7 @@ mymain(void)
> >
> >  DO_TEST("graphics-sdl",
> >  QEMU_CAPS_DEVICE_VGA);
> > -DO_TEST_FAILURE("graphics-sdl-egl-headless", NONE);
> > +DO_TEST_PARSE_ERROR_CAPS_LATEST("graphics-sdl-egl-headless");
>
> We're changing from a general execution failure to a parse failure, so
> theoretically we could not have started a guest like this, right?  If we
> could have then I'd be concerned with the guest disappearance factor on
> libvirtd restart, but I don't think that's the case h

Re: [libvirt] [PATCH 1/2] qemu: don't log error for missing optional sources on stats

2018-12-12 Thread John Ferlan



On 12/12/18 9:32 AM, Nikolay Shirokovskiy wrote:
> 
> 
> On 12.12.2018 16:28, John Ferlan wrote:
>>
>>
>> On 12/12/18 3:04 AM, Nikolay Shirokovskiy wrote:
>>>
>>>
>>> On 11.12.2018 17:33, John Ferlan wrote:


 On 12/11/18 2:34 AM, Nikolay Shirokovskiy wrote:
>
>
> On 11.12.2018 01:05, John Ferlan wrote:
>>
>> $SUBJ:
>>
>> 'storage sources'
>>
>> On 11/12/18 7:58 AM, Nikolay Shirokovskiy wrote:
>>> Every time we call all domain stats for inactive domain with
>>> unavailable source we get error message in logs. It's a bit noisy.
>>
>> Are there ones in particular?
>
> Like this one:
>
> qemuOpenFileAs:3324 : Failed to open file '/path/to/optinal/disk': No 
> such file or directory
>

 So this is the one that perhaps is bothersome to the degree of we're
 ignoring that it doesn't exist, but then again the domain is not active,
 so does it really matter.

>>>
>>> I would prefer not to see false positive messages in logs if it is possible.
>>>
>>
>>> While it's arguable whether we need such message or not for mandatory
>>> disks we would like not to see messages for optional disks. Let's
>>
>> Filtering for the 'startupPolicy = optional' for domain stats (with
>> empty/unavailable local source) would seem to be a "new use" perhaps not
>> totally in line with the original intention.
>
> But I was not going to change behaviour only to stop polluting
> logs with messages like above.
>

 Your solution requires that someone has modified their definition to
 include that startupPolicy='optional' attribute. I can be persuaded that
 this is desirable; however, it would be nice to get Peter's opinion on
 this especially since he knows the code and "rules" for backing stores
 better than I do. IOW: From a storage backing chain perspective does it
 make sense to use that.
>>>
>>> Not presicely, rather if someone already has optional disk then why logging
>>> this kind of errors.
>
>>
>>> filter at least for cases of local files. Fixing other cases would
>>> require passing flag down the stack to .backendInit of storage
>>> which is ugly.
>>
>> Yeah, I remember chasing down into backendInit (virStorageFileInitAs)
>> from qemuDomainStorageOpenStat for
>>
>>virStorageFileBackendForType:145 : internal error: missing storage
>> backend for 'none' storage
>>virStorageFileBackendForType:141 : internal error: missing storage
>> backend for network files using iscsi protocol
>>
>> where the 'none' comes from a volume using a storage pool of iSCSI
>> disks. I chased for a bit, but yes it got messy fast.
>>
>>>
>>> Stats for active domain are fine because we either drop disks
>>> with unavailable sources or clean source which is handled
>>> by virStorageSourceIsEmpty in qemuDomainGetStatsOneBlockFallback.
>>>
>>> We have these logs for successful stats since 25aa7035d which
>>> in turn fixes 596a13713 which added substantial stats for offline
>>> disks.
>>>
>>> Signed-off-by: Nikolay Shirokovskiy 
>>> ---
>>>  src/qemu/qemu_driver.c  | 5 +
>>>  src/qemu/qemu_process.c | 9 +
>>>  src/qemu/qemu_process.h | 2 ++
>>>  3 files changed, 16 insertions(+)
>>>
>>> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
>>> index a52e249..72e4cfe 100644
>>> --- a/src/qemu/qemu_driver.c
>>> +++ b/src/qemu/qemu_driver.c
>>> @@ -20290,6 +20290,11 @@ 
>>> qemuDomainGetStatsBlockExportDisk(virDomainDiskDefPtr disk,
>>>  const char *backendstoragealias;
>>>  int ret = -1;
>>>  
>>> +if (!virDomainObjIsActive(dom) &&
>>> +qemuProcessMissingLocalOptionalDisk(disk))
>>> +return qemuDomainGetStatsBlockExportHeader(disk, disk->src, 
>>> *recordnr,
>>> +   records, nrecords);
>>> +
>>
>> From my quick read this part would seem reasonable since the *Frontend
>> and *Backend wouldn't have valid data and *GetStatsOneBlock is fetching
>> source sizing data which for an empty source would be unobtainable.
>>
>>>  for (n = disk->src; virStorageSourceIsBacking(n); n = 
>>> n->backingStore) {
>>>  if (blockdev) {
>>>  frontendalias = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
>>> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
>>> index 9cf9718..802274e 100644
>>> --- a/src/qemu/qemu_process.c
>>> +++ b/src/qemu/qemu_process.c
>>> @@ -6070,6 +6070,15 @@ qemuProcessPrepareSEVGuestInput(virDomainObjPtr 
>>> vm)
>>>  }
>>>  
>>>  
>>> +bool
>>> +qemuProcessMissingLocalOptionalDisk(virDomainDiskDefPtr disk)
>>
>> Curious why you chose qemu_process and not qemu_domain or even
>>

Re: [libvirt] [PATCH] secret: Add check/validation for correct usage when LookupByUUID

2018-12-12 Thread John Ferlan



On 12/12/18 9:29 AM, Michal Privoznik wrote:
> On 12/4/18 9:32 PM, John Ferlan wrote:
>> If virSecretGetSecretString is using by secretLookupByUUID,
>> then it's possible the found sec->usageType doesn't match the
>> desired @secretUsageType. If this occurs for the encrypted
>> volume creation processing and a subsequent pool refresh is
>> executed, then the secret used to create the volume will not
>> be found by the storageBackendLoadDefaultSecrets which expects
>> to find secrets by VIR_SECRET_USAGE_TYPE_VOLUME.
>>
>> Add a check to virSecretGetSecretString to avoid the possibility
>> along with an error indicating the incorrect matched types.
>>
>> Signed-off-by: John Ferlan 
>> ---
>>
>>  If someone has an idea regarding how the usage could be filled
>>  in "properly" for the qemuxml2argvtest, I'm willing to give it
>>  a shot. However, fair warning trying to "mock" for tls, volume,
>>  iscsi, and ceph could be rather painful. Thus the NONE was the
>>  well, easiest way to go since the stored secret (ahem) shouldn't
>>  be of usageType "none" (famous last words).
>>
>>  src/secret/secret_util.c | 17 +
>>  tests/qemuxml2argvtest.c |  4 +++-
>>  2 files changed, 20 insertions(+), 1 deletion(-)
>>
>> diff --git a/src/secret/secret_util.c b/src/secret/secret_util.c
>> index 16e43ab2cc..27e164a425 100644
>> --- a/src/secret/secret_util.c
>> +++ b/src/secret/secret_util.c
>> @@ -71,6 +71,23 @@ virSecretGetSecretString(virConnectPtr conn,
>>  if (!sec)
>>  goto cleanup;
>>  
>> +/* NB: NONE is a byproduct of the qemuxml2argvtest test mocking
>> + * for UUID lookups. Normal secret XML processing would fail if
>> + * the usage type was NONE and since we have no way to set the
>> + * expected usage in that environment, let's just accept NONE */
>> +if (sec->usageType != VIR_SECRET_USAGE_TYPE_NONE &&
>> +sec->usageType != secretUsageType) {
>> +char uuidstr[VIR_UUID_STRING_BUFLEN];
>> +
>> +virUUIDFormat(seclookupdef->u.uuid, uuidstr);
>> +virReportError(VIR_ERR_INVALID_ARG,
>> +   _("secret with uuid %s is of type '%s' not "
>> + "expected '%s' type"),
>> +   uuidstr, virSecretUsageTypeToString(sec->usageType),
>> +   virSecretUsageTypeToString(secretUsageType));
>> +goto cleanup;
>> +}
> 
> I don't quite understand why this is needed. I mean, if
> seclookupdef->type == VIR_SECRET_LOOKUP_TYPE_USAGE then this check is
> done while looking the secret up. If seclookupdef->type ==
> VIR_SECRET_LOOKUP_TYPE_UUID then this check feels odd; the caller wants
> the secret by UUID and they don't care about the usage type.
> 
> Is there an actual error you're seeing?
> 
> Michal
> 

Someone used an "iscsi" usage type secret by to create their luks
encrypted volume. When using vol-dumpxml after creation the secret by
usage existed. Then a pool-refresh caused the secret to disappear
because on pool refresh the secret for a volume is refreshed by "volume"
secret usage type.  When I posted this patch, the bz didn't exist, but
it does now, see: https://bugzilla.redhat.com/show_bug.cgi?id=1656255

John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 1/2] qemu: don't log error for missing optional sources on stats

2018-12-12 Thread Nikolay Shirokovskiy



On 12.12.2018 16:28, John Ferlan wrote:
> 
> 
> On 12/12/18 3:04 AM, Nikolay Shirokovskiy wrote:
>>
>>
>> On 11.12.2018 17:33, John Ferlan wrote:
>>>
>>>
>>> On 12/11/18 2:34 AM, Nikolay Shirokovskiy wrote:


 On 11.12.2018 01:05, John Ferlan wrote:
>
> $SUBJ:
>
> 'storage sources'
>
> On 11/12/18 7:58 AM, Nikolay Shirokovskiy wrote:
>> Every time we call all domain stats for inactive domain with
>> unavailable source we get error message in logs. It's a bit noisy.
>
> Are there ones in particular?

 Like this one:

 qemuOpenFileAs:3324 : Failed to open file '/path/to/optinal/disk': No such 
 file or directory

>>>
>>> So this is the one that perhaps is bothersome to the degree of we're
>>> ignoring that it doesn't exist, but then again the domain is not active,
>>> so does it really matter.
>>>
>>
>> I would prefer not to see false positive messages in logs if it is possible.
>>
>
>> While it's arguable whether we need such message or not for mandatory
>> disks we would like not to see messages for optional disks. Let's
>
> Filtering for the 'startupPolicy = optional' for domain stats (with
> empty/unavailable local source) would seem to be a "new use" perhaps not
> totally in line with the original intention.

 But I was not going to change behaviour only to stop polluting
 logs with messages like above.

>>>
>>> Your solution requires that someone has modified their definition to
>>> include that startupPolicy='optional' attribute. I can be persuaded that
>>> this is desirable; however, it would be nice to get Peter's opinion on
>>> this especially since he knows the code and "rules" for backing stores
>>> better than I do. IOW: From a storage backing chain perspective does it
>>> make sense to use that.
>>
>> Not presicely, rather if someone already has optional disk then why logging
>> this kind of errors.

>
>> filter at least for cases of local files. Fixing other cases would
>> require passing flag down the stack to .backendInit of storage
>> which is ugly.
>
> Yeah, I remember chasing down into backendInit (virStorageFileInitAs)
> from qemuDomainStorageOpenStat for
>
>virStorageFileBackendForType:145 : internal error: missing storage
> backend for 'none' storage
>virStorageFileBackendForType:141 : internal error: missing storage
> backend for network files using iscsi protocol
>
> where the 'none' comes from a volume using a storage pool of iSCSI
> disks. I chased for a bit, but yes it got messy fast.
>
>>
>> Stats for active domain are fine because we either drop disks
>> with unavailable sources or clean source which is handled
>> by virStorageSourceIsEmpty in qemuDomainGetStatsOneBlockFallback.
>>
>> We have these logs for successful stats since 25aa7035d which
>> in turn fixes 596a13713 which added substantial stats for offline
>> disks.
>>
>> Signed-off-by: Nikolay Shirokovskiy 
>> ---
>>  src/qemu/qemu_driver.c  | 5 +
>>  src/qemu/qemu_process.c | 9 +
>>  src/qemu/qemu_process.h | 2 ++
>>  3 files changed, 16 insertions(+)
>>
>> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
>> index a52e249..72e4cfe 100644
>> --- a/src/qemu/qemu_driver.c
>> +++ b/src/qemu/qemu_driver.c
>> @@ -20290,6 +20290,11 @@ 
>> qemuDomainGetStatsBlockExportDisk(virDomainDiskDefPtr disk,
>>  const char *backendstoragealias;
>>  int ret = -1;
>>  
>> +if (!virDomainObjIsActive(dom) &&
>> +qemuProcessMissingLocalOptionalDisk(disk))
>> +return qemuDomainGetStatsBlockExportHeader(disk, disk->src, 
>> *recordnr,
>> +   records, nrecords);
>> +
>
> From my quick read this part would seem reasonable since the *Frontend
> and *Backend wouldn't have valid data and *GetStatsOneBlock is fetching
> source sizing data which for an empty source would be unobtainable.
>
>>  for (n = disk->src; virStorageSourceIsBacking(n); n = 
>> n->backingStore) {
>>  if (blockdev) {
>>  frontendalias = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
>> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
>> index 9cf9718..802274e 100644
>> --- a/src/qemu/qemu_process.c
>> +++ b/src/qemu/qemu_process.c
>> @@ -6070,6 +6070,15 @@ qemuProcessPrepareSEVGuestInput(virDomainObjPtr 
>> vm)
>>  }
>>  
>>  
>> +bool
>> +qemuProcessMissingLocalOptionalDisk(virDomainDiskDefPtr disk)
>
> Curious why you chose qemu_process and not qemu_domain or even
> virstoragefile?  This has nothing to do with whether the qemu process is
> running or not.

 Yeah, we have nothing qemu specific here. Just not sure is this useful
>>

Re: [libvirt] [PATCH] secret: Add check/validation for correct usage when LookupByUUID

2018-12-12 Thread Michal Privoznik
On 12/4/18 9:32 PM, John Ferlan wrote:
> If virSecretGetSecretString is using by secretLookupByUUID,
> then it's possible the found sec->usageType doesn't match the
> desired @secretUsageType. If this occurs for the encrypted
> volume creation processing and a subsequent pool refresh is
> executed, then the secret used to create the volume will not
> be found by the storageBackendLoadDefaultSecrets which expects
> to find secrets by VIR_SECRET_USAGE_TYPE_VOLUME.
> 
> Add a check to virSecretGetSecretString to avoid the possibility
> along with an error indicating the incorrect matched types.
> 
> Signed-off-by: John Ferlan 
> ---
> 
>  If someone has an idea regarding how the usage could be filled
>  in "properly" for the qemuxml2argvtest, I'm willing to give it
>  a shot. However, fair warning trying to "mock" for tls, volume,
>  iscsi, and ceph could be rather painful. Thus the NONE was the
>  well, easiest way to go since the stored secret (ahem) shouldn't
>  be of usageType "none" (famous last words).
> 
>  src/secret/secret_util.c | 17 +
>  tests/qemuxml2argvtest.c |  4 +++-
>  2 files changed, 20 insertions(+), 1 deletion(-)
> 
> diff --git a/src/secret/secret_util.c b/src/secret/secret_util.c
> index 16e43ab2cc..27e164a425 100644
> --- a/src/secret/secret_util.c
> +++ b/src/secret/secret_util.c
> @@ -71,6 +71,23 @@ virSecretGetSecretString(virConnectPtr conn,
>  if (!sec)
>  goto cleanup;
>  
> +/* NB: NONE is a byproduct of the qemuxml2argvtest test mocking
> + * for UUID lookups. Normal secret XML processing would fail if
> + * the usage type was NONE and since we have no way to set the
> + * expected usage in that environment, let's just accept NONE */
> +if (sec->usageType != VIR_SECRET_USAGE_TYPE_NONE &&
> +sec->usageType != secretUsageType) {
> +char uuidstr[VIR_UUID_STRING_BUFLEN];
> +
> +virUUIDFormat(seclookupdef->u.uuid, uuidstr);
> +virReportError(VIR_ERR_INVALID_ARG,
> +   _("secret with uuid %s is of type '%s' not "
> + "expected '%s' type"),
> +   uuidstr, virSecretUsageTypeToString(sec->usageType),
> +   virSecretUsageTypeToString(secretUsageType));
> +goto cleanup;
> +}

I don't quite understand why this is needed. I mean, if
seclookupdef->type == VIR_SECRET_LOOKUP_TYPE_USAGE then this check is
done while looking the secret up. If seclookupdef->type ==
VIR_SECRET_LOOKUP_TYPE_UUID then this check feels odd; the caller wants
the secret by UUID and they don't care about the usage type.

Is there an actual error you're seeing?

Michal

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH v2 2/4] qemu: caps: add QEMU_CAPS_QCOW2_L2_CACHE_SIZE

2018-12-12 Thread John Ferlan



On 12/12/18 5:59 AM, Nikolay Shirokovskiy wrote:
> 
> 
> On 11.12.2018 19:41, John Ferlan wrote:
>>
>>
>> On 12/11/18 6:04 AM, Nikolay Shirokovskiy wrote:
>>>
>>>
>>> On 10.12.2018 19:58, John Ferlan wrote:


 On 11/8/18 8:02 AM, Nikolay Shirokovskiy wrote:
> For qemu capable of setting l2-cache-size for qcow2 images
> to INT64_MAX and semantics of upper limit on l2 cache
> size. We can only check this by qemu version (3.1.0) now.
>
> Signed-off-by: Nikolay Shirokovskiy 
> ---
>  src/qemu/qemu_capabilities.c | 5 +
>  src/qemu/qemu_capabilities.h | 1 +
>  2 files changed, 6 insertions(+)
>

 This patch needs to be updated to top of tree.

> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
> index 2ca5af3..49a3b60 100644
> --- a/src/qemu/qemu_capabilities.c
> +++ b/src/qemu/qemu_capabilities.c
> @@ -509,6 +509,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
>"vfio-pci.display",
>"blockdev",
>"vfio-ap",
> +  "qcow2.l2-cache-size",

 When you do update, you will need to fix the comma-less entry for
 "egl-headless.rendernode" as well, unless someone else gets to it first.

>  );
>  
>  
> @@ -4117,6 +4118,10 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps,
>  virQEMUCapsSet(qemuCaps, 
> QEMU_CAPS_MACHINE_PSERIES_MAX_CPU_COMPAT);
>  }
>  
> +/* l2-cache-size before 3001000 does not accept INT64_MAX */
> +if (qemuCaps->version >= 3001000)
> +virQEMUCapsSet(qemuCaps, QEMU_CAPS_QCOW2_L2_CACHE_SIZE);
> +

 Not a fan of this.

 The 'l2-cache-size' was supported since QEMU 2.2. A "newer" algorithm
 for cache adjustment has been supported since QEMU 2.12 (and there's
 l2-cache-entry-size that "could be used" to know that). Then there's
 some unreferenced commit indicating usage of INT64_MAX. Tracking that
 down, I find qemu.git commit 6c1c8d5d from Max which enforces MAX_INT.
>>>
>>> This is a failure rather than enforcement. And AFAIU code that limit cache
>>> to appropriate maximum when INT64_MAX is given in read_cache_sizes:
>>>
>>> *l2_cache_size = MIN(max_l2_cache, l2_cache_max_setting);
>>>
>>> only appeared after release of 3.0 in 
>>>
>>> commit b749562d9822d14ef69c9eaa5f85903010b86c30
>>> Author: Leonid Bloch 
>>> Date:   Wed Sep 26 19:04:43 2018 +0300
>>>
>>> qcow2: Assign the L2 cache relatively to the image size
>>>
>>>
>>> ie setting cache size to INT64_MAX before 3.1 will fail. In
>>> other words in earlier versions there were no value to specify that
>>> cache size need to be set to maximum. You can calculate this value
>>> yourself knowing disk size and disk cluster size and set it but
>>> this is not convinient.
>>>
>>
>> So prior to this patch the max could be 32 MB? And now it's calculate-able?
> 
> 32 MB is default value on Linux in 3.1 (the patch set it it to 1 MB but later
> patch 80668d0f increases to 32 MB). 
> 
> Before the patch one can set greater values but can not set INT64_MAX.
> The exact value that can be set depends on cluster size due to the check
> againts INT_MAX you already mentioned. So one can set up to INT_MAX * 
> cluster_size,
> but cluster_size is unknown to us (?). Given minium cluster size is 512 
> bytes, we
> can set INT_MAX * 512 (1 TB) always. This will cover 64 TB disks for cluster
> size 512 bytes and 8192 PB for default cluster size. So we should refuse 
> to start with policy 'maximum' and disk size greater then 64 TB. 
> Or may be we can just check cluster size at start up. How do you think?

I'm not sure I'd go through the trouble of determining the size. If
we're not changing the default cluster_size, then using 512 "seems"
reasonable (whether others feel the same way who knows yet). I'm not
even sure if we already get that information - feel free to research and
add though.

I'm not sure I would "refuse" to start - think in terms of what is the
downside to not being able to have a large enough value - well that
seems to be I/O performance.  If we can get "better" I/O performance by
providing "something" more than "default" for those environments, then I
would think that's better than doing nothing or failing to start.

I'm not sure how much "effort" you want to put into the window of
support prior to 3.1 where "maximum" is true maximum.  It could be
simple enough to document that for prior to 3.1 the maximum value is
limited to XXX. After 3.1 it's essentially unlimited since libvirt can
provide the maximum integer value to QEMU and QEMU then decides the
maximum up to that value.  There's ways to wordsmith it - I'm pretty
sure it's been done before, but I don't have an example readily
available (search docs for size, maximum, or default)...

> 
> By the way the patch works only for -blockdev configuration which is
> available since QEMU 2.10 

Re: [libvirt] [PATCH 0/8] Add tests for Storage Pool startup command line generation

2018-12-12 Thread Michal Privoznik
On 12/4/18 5:47 PM, John Ferlan wrote:
> Similar to qemuxml2argv and storagevolxml2argv, add storagepoolxml2argvtest
> in order to check the command line creation for the pool 'Start' commands.
> 
> Only applicable for pool types with a "@startPool" function - that is disk,
> fs, iscsi, logical, scsi, and vstorage and further restricted if the pool
> doesn't use virCommandPtr type processing.
> 
> This initial series only addresses fs and logical so that it's not "too
> many patches to review".
> 
> The iscsi and vstorage pools could have their own tests, with the iscsi
> ones being more challenging to write.
> 
> The disk pool does not have the normal command line processing to start
> something - rather the command line processing is used to validate that
> the pool about to be started is of a valid type based on the label seen
> at startup compared to the pool XML. This processing is not easily mocked.
> 
> The scsi (for NPIV) doesn't use the virCommandPtr style interfaces, but at
> least that processing is tested in other ways using testCreateVport from
> test_driver.c.
> 
> John Ferlan (8):
>   storage: Extract out mount command creation for FS Backend
>   storage: Move FS backend mount creation command helper
>   storage: Move virStorageBackendFileSystemGetPoolSource
>   tests: Introduce tests for storage pool xml to argv checks
>   tests: Add storagepool xml test for netfs-auto
>   storage: Rework virStorageBackendFileSystemMountCmd
>   logical: Fix @on argument type
>   storage: Add tests for logical backend startup
> 
>  src/storage/storage_backend_fs.c  |  77 +---
>  src/storage/storage_backend_logical.c |  12 +-
>  src/storage/storage_util.c| 122 
>  src/storage/storage_util.h|  11 ++
>  tests/Makefile.am |  12 ++
>  tests/storagepoolxml2argvdata/pool-fs.argv|   1 +
>  .../pool-logical-create.argv  |   1 +
>  .../pool-logical-noname.argv  |   1 +
>  .../pool-logical-nopath.argv  |   1 +
>  .../storagepoolxml2argvdata/pool-logical.argv |   1 +
>  .../pool-netfs-auto.argv  |   1 +
>  .../pool-netfs-cifs.argv  |   1 +
>  .../pool-netfs-gluster.argv   |   1 +
>  tests/storagepoolxml2argvdata/pool-netfs.argv |   1 +
>  tests/storagepoolxml2argvtest.c   | 175 ++
>  .../storagepoolxml2xmlin/pool-netfs-auto.xml  |  19 ++
>  .../storagepoolxml2xmlout/pool-netfs-auto.xml |  20 ++
>  tests/storagepoolxml2xmltest.c|   1 +
>  18 files changed, 375 insertions(+), 83 deletions(-)
>  create mode 100644 tests/storagepoolxml2argvdata/pool-fs.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-create.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-noname.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-nopath.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-auto.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-cifs.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-gluster.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs.argv
>  create mode 100644 tests/storagepoolxml2argvtest.c
>  create mode 100644 tests/storagepoolxml2xmlin/pool-netfs-auto.xml
>  create mode 100644 tests/storagepoolxml2xmlout/pool-netfs-auto.xml
> 

The patches look good from logical POV. However, there is an issue with
mount/vgchange location on different systems.

Michal

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 4/8] tests: Introduce tests for storage pool xml to argv checks

2018-12-12 Thread Michal Privoznik
On 12/4/18 5:47 PM, John Ferlan wrote:
> Similar to qemuxml2argv and storagevolxml2argv, let's create some
> tests to ensure that the XML generates a consistent command line.
> 
> Using the same list of pools as storagepoolxml2xmltest, start with
> the file system tests (fs, netfs, netfs-cifs, netfs-gluster).
> 
> Signed-off-by: John Ferlan 
> ---
>  tests/Makefile.am |  12 ++
>  tests/storagepoolxml2argvdata/pool-fs.argv|   1 +
>  .../pool-netfs-cifs.argv  |   1 +
>  .../pool-netfs-gluster.argv   |   1 +
>  tests/storagepoolxml2argvdata/pool-netfs.argv |   1 +
>  tests/storagepoolxml2argvtest.c   | 171 ++
>  6 files changed, 187 insertions(+)
>  create mode 100644 tests/storagepoolxml2argvdata/pool-fs.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-cifs.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs-gluster.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-netfs.argv
>  create mode 100644 tests/storagepoolxml2argvtest.c
> 
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index d7ec7e3a6f..bec0930c11 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -140,6 +140,7 @@ EXTRA_DIST = \
>   storagepoolschemadata \
>   storagepoolxml2xmlin \
>   storagepoolxml2xmlout \
> + storagepoolxml2argvdata \
>   storagevolschemadata \
>   storagevolxml2argvdata \
>   storagevolxml2xmlin \
> @@ -363,6 +364,7 @@ endif WITH_NWFILTER
>  
>  if WITH_STORAGE
>  test_programs += storagevolxml2argvtest
> +test_programs += storagepoolxml2argvtest
>  test_programs += virstorageutiltest
>  endif WITH_STORAGE
>  
> @@ -901,6 +903,16 @@ storagevolxml2argvtest_LDADD = \
>   ../src/libvirt_util.la \
>   $(LDADDS)
>  
> +storagepoolxml2argvtest_SOURCES = \
> +storagepoolxml2argvtest.c \
> +testutils.c testutils.h
> +storagepoolxml2argvtest_LDADD = \
> + $(LIBXML_LIBS) \
> + ../src/libvirt_driver_storage_impl.la \
> + ../src/libvirt_conf.la \
> + ../src/libvirt_util.la \
> + $(LDADDS)
> +
>  else ! WITH_STORAGE
>  EXTRA_DIST += storagevolxml2argvtest.c
>  EXTRA_DIST += virstorageutiltest.c
> diff --git a/tests/storagepoolxml2argvdata/pool-fs.argv 
> b/tests/storagepoolxml2argvdata/pool-fs.argv
> new file mode 100644
> index 00..4a94148114
> --- /dev/null
> +++ b/tests/storagepoolxml2argvdata/pool-fs.argv
> @@ -0,0 +1 @@
> +/usr/bin/mount -t ext3 /dev/sda6 /mnt

Problem is, on my system (Gentoo), it is /usr/mount so this is failing
for me.

I wonder if we should have a placeholder here, say "MOUNT" and then
replace it with actual location of 'mount' (taken from config.h) at runtime.

Michal

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 8/8] storage: Add tests for logical backend startup

2018-12-12 Thread Michal Privoznik
On 12/4/18 5:47 PM, John Ferlan wrote:
> Add the logical storage pool startup validation (xml2argv) tests.
> 
> Signed-off-by: John Ferlan 
> ---
>  src/storage/storage_backend_logical.c   |  6 +-
>  src/storage/storage_util.c  | 11 +++
>  src/storage/storage_util.h  |  4 
>  .../pool-logical-create.argv|  1 +
>  .../pool-logical-noname.argv|  1 +
>  .../pool-logical-nopath.argv|  1 +
>  tests/storagepoolxml2argvdata/pool-logical.argv |  1 +
>  tests/storagepoolxml2argvtest.c | 13 -
>  8 files changed, 28 insertions(+), 10 deletions(-)
>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-create.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-noname.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical-nopath.argv
>  create mode 100644 tests/storagepoolxml2argvdata/pool-logical.argv
> 
> diff --git a/src/storage/storage_backend_logical.c 
> b/src/storage/storage_backend_logical.c
> index 44cff61af7..12fff651e8 100644
> --- a/src/storage/storage_backend_logical.c
> +++ b/src/storage/storage_backend_logical.c
> @@ -52,11 +52,7 @@ virStorageBackendLogicalSetActive(virStoragePoolObjPtr 
> pool,
>  {
>  int ret;
>  virStoragePoolDefPtr def = virStoragePoolObjGetDef(pool);
> -virCommandPtr cmd =
> -virCommandNewArgList(VGCHANGE,
> - on ? "-aly" : "-aln",
> - def->source.name,
> - NULL);
> +virCommandPtr cmd = virStorageBackendLogicalChangeCmd(def, on);
>  
>  ret = virCommandRun(cmd, NULL);
>  virCommandFree(cmd);
> diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c
> index 789f270f2a..01f3c93008 100644
> --- a/src/storage/storage_util.c
> +++ b/src/storage/storage_util.c
> @@ -4337,3 +4337,14 @@ 
> virStorageBackendFileSystemMountCmd(virStoragePoolDefPtr def,
>  virStorageBackendFileSystemMountDefaultArgs(cmd, src, def);
>  return cmd;
>  }
> +
> +
> +virCommandPtr
> +virStorageBackendLogicalChangeCmd(virStoragePoolDefPtr def,
> +  bool on)
> +{
> +return virCommandNewArgList(VGCHANGE,
> +on ? "-aly" : "-aln",
> +def->source.name,
> +NULL);
> +}
> diff --git a/src/storage/storage_util.h b/src/storage/storage_util.h
> index 28b3e0b9c9..a2ef2ac07d 100644
> --- a/src/storage/storage_util.h
> +++ b/src/storage/storage_util.h
> @@ -184,4 +184,8 @@ virCommandPtr
>  virStorageBackendFileSystemMountCmd(virStoragePoolDefPtr def,
>  const char *src);
>  
> +virCommandPtr
> +virStorageBackendLogicalChangeCmd(virStoragePoolDefPtr def,
> +  bool on);
> +
>  #endif /* __VIR_STORAGE_UTIL_H__ */
> diff --git a/tests/storagepoolxml2argvdata/pool-logical-create.argv 
> b/tests/storagepoolxml2argvdata/pool-logical-create.argv
> new file mode 100644
> index 00..203da86e48
> --- /dev/null
> +++ b/tests/storagepoolxml2argvdata/pool-logical-create.argv
> @@ -0,0 +1 @@
> +/usr/sbin/vgchange -aly HostVG

The same point here. On my system it is /sbin/vgchange.

Michal

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH v2 1/4] xml: add disk driver metadata_cache_size option

2018-12-12 Thread John Ferlan



On 12/12/18 3:39 AM, Nikolay Shirokovskiy wrote:
> 
> 
> On 11.12.2018 19:34, John Ferlan wrote:
>>
>>
>> On 12/11/18 5:22 AM, Nikolay Shirokovskiy wrote:
>>>
>>>
>>> On 10.12.2018 19:56, John Ferlan wrote:

 On 11/8/18 8:02 AM, Nikolay Shirokovskiy wrote:
> Signed-off-by: Nikolay Shirokovskiy 
> ---
>  docs/formatdomain.html.in  |  8 
>  docs/schemas/domaincommon.rng  | 11 +
>  src/conf/domain_conf.c | 17 
>  src/conf/domain_conf.h |  9 
>  .../qemuxml2argvdata/disk-metadata_cache_size.xml  | 42 
> +++
>  .../disk-metadata_cache_size.xml   | 48 
> ++
>  tests/qemuxml2xmltest.c|  2 +
>  7 files changed, 137 insertions(+)
>  create mode 100644 tests/qemuxml2argvdata/disk-metadata_cache_size.xml
>  create mode 100644 tests/qemuxml2xmloutdata/disk-metadata_cache_size.xml
>

  looks like a forgotten thread...  It seems reviewer bandwidth is
 limited and won't get much better during the last couple weeks of the
 month when many if not most Red Hat employees are out to due company
 shutdown period.

 You need to add a few words to the commit message to describe what's
 being changed.  Oh and you'll also need a "last" patch to docs/news.xml
 to describe the new feature.

> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
> index 269741a..1d186ab 100644
> --- a/docs/formatdomain.html.in
> +++ b/docs/formatdomain.html.in
> @@ -3556,6 +3556,14 @@
>  virt queues for virtio-blk. (Since 
> 3.9.0)
>
>
> +The optional metadata_cache_size attribute 
> specifies
> +metadata cache size policy, possible values are "default" 
> and "maximum".

 s/policy, possible/policy. Possible/

> +"default" leaves setting cache size to hypervisor, "maximum" 
> makes

 s/"default"/Using "default"/

 s/to hypervisor,/to the hypervisor./

 s/"maximum"/Using "maximum"

> +cache size large enough to keep all metadata, this will help 
> if workload


 "Using maximum assigns the largest value possible for the cache size.
 This ensures the entire disk cache remains in memory for faster I/O at
 the expense of utilizing more memory."

 [Editorial comment: it's really not 100% clear what all the tradeoffs
 someone is making here. The phrase "large enough" just sticks out, but
 since you use INT64_MAX in patch 3, I suppose that *is* the maximum.
 Still in some way indicating that this allows QEMU to grow the cache and
 keep everything in memory, but has the side effect that disks configured
 this way will cause guest memory requirements to grow albeit limited by
 the QEMU algorithms. It seems from my read the max is 32MB, so perhaps
 not a huge deal, but could be useful to note. Whether QEMU shrinks the
 cache when not in use wasn't 100% clear to me.]

 It's too bad it's not possible to utilize some dynamic value via
 qcow2_update_options_prepare. If dynamic adjustment were possible, then
 saving the value in the XML wouldn't be necessary - we could just allow
 dynamic adjustment similar to what I did for of a couple of IOThread
 params (see commit 11ceedcda and the patches before it).

> +needs access to whole disk all the time. ( class="since">Since
> +4.10.0, QEMU 3.1)

 This will be at least 5.0.0 now.

> +  
> +  
>For virtio disks,
>Virtio-specific options can also 
> be
>set. (Since 3.5.0)
> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
> index b9ac5df..3e406fc 100644
> --- a/docs/schemas/domaincommon.rng
> +++ b/docs/schemas/domaincommon.rng
> @@ -1990,6 +1990,9 @@
>  
>
>
> +
> +  
> +  
>  
>
>  
> @@ -2090,6 +2093,14 @@
>
>  
>
> +  
> +
> +  
> +default
> +maximum

 I didn't go back and read the previous reviews nor was I present for the
 KVM Forum discussion on this, but default really means "minimum" I
 think. Even that just doesn't feel "right". There's 3 QEMU knobs, but
 this changes 1 knob allowing one direction. And yes, changing 3 knobs is
 also confusing. I "assume" that it's been determined that this one knob
 has the greatest affect on I/O performance...

 Reading https://github.com/qemu/qemu/blob/master/docs/qcow2-cache.txt
 some phrases stick o

Re: [libvirt] [PATCH 1/2] qemu: don't log error for missing optional sources on stats

2018-12-12 Thread John Ferlan



On 12/12/18 3:04 AM, Nikolay Shirokovskiy wrote:
> 
> 
> On 11.12.2018 17:33, John Ferlan wrote:
>>
>>
>> On 12/11/18 2:34 AM, Nikolay Shirokovskiy wrote:
>>>
>>>
>>> On 11.12.2018 01:05, John Ferlan wrote:

 $SUBJ:

 'storage sources'

 On 11/12/18 7:58 AM, Nikolay Shirokovskiy wrote:
> Every time we call all domain stats for inactive domain with
> unavailable source we get error message in logs. It's a bit noisy.

 Are there ones in particular?
>>>
>>> Like this one:
>>>
>>> qemuOpenFileAs:3324 : Failed to open file '/path/to/optinal/disk': No such 
>>> file or directory
>>>
>>
>> So this is the one that perhaps is bothersome to the degree of we're
>> ignoring that it doesn't exist, but then again the domain is not active,
>> so does it really matter.
>>
> 
> I would prefer not to see false positive messages in logs if it is possible.
> 

> While it's arguable whether we need such message or not for mandatory
> disks we would like not to see messages for optional disks. Let's

 Filtering for the 'startupPolicy = optional' for domain stats (with
 empty/unavailable local source) would seem to be a "new use" perhaps not
 totally in line with the original intention.
>>>
>>> But I was not going to change behaviour only to stop polluting
>>> logs with messages like above.
>>>
>>
>> Your solution requires that someone has modified their definition to
>> include that startupPolicy='optional' attribute. I can be persuaded that
>> this is desirable; however, it would be nice to get Peter's opinion on
>> this especially since he knows the code and "rules" for backing stores
>> better than I do. IOW: From a storage backing chain perspective does it
>> make sense to use that.
> 
> Not presicely, rather if someone already has optional disk then why logging
> this kind of errors.
> >>

> filter at least for cases of local files. Fixing other cases would
> require passing flag down the stack to .backendInit of storage
> which is ugly.

 Yeah, I remember chasing down into backendInit (virStorageFileInitAs)
 from qemuDomainStorageOpenStat for

virStorageFileBackendForType:145 : internal error: missing storage
 backend for 'none' storage
virStorageFileBackendForType:141 : internal error: missing storage
 backend for network files using iscsi protocol

 where the 'none' comes from a volume using a storage pool of iSCSI
 disks. I chased for a bit, but yes it got messy fast.

>
> Stats for active domain are fine because we either drop disks
> with unavailable sources or clean source which is handled
> by virStorageSourceIsEmpty in qemuDomainGetStatsOneBlockFallback.
>
> We have these logs for successful stats since 25aa7035d which
> in turn fixes 596a13713 which added substantial stats for offline
> disks.
>
> Signed-off-by: Nikolay Shirokovskiy 
> ---
>  src/qemu/qemu_driver.c  | 5 +
>  src/qemu/qemu_process.c | 9 +
>  src/qemu/qemu_process.h | 2 ++
>  3 files changed, 16 insertions(+)
>
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index a52e249..72e4cfe 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -20290,6 +20290,11 @@ 
> qemuDomainGetStatsBlockExportDisk(virDomainDiskDefPtr disk,
>  const char *backendstoragealias;
>  int ret = -1;
>  
> +if (!virDomainObjIsActive(dom) &&
> +qemuProcessMissingLocalOptionalDisk(disk))
> +return qemuDomainGetStatsBlockExportHeader(disk, disk->src, 
> *recordnr,
> +   records, nrecords);
> +

 From my quick read this part would seem reasonable since the *Frontend
 and *Backend wouldn't have valid data and *GetStatsOneBlock is fetching
 source sizing data which for an empty source would be unobtainable.

>  for (n = disk->src; virStorageSourceIsBacking(n); n = 
> n->backingStore) {
>  if (blockdev) {
>  frontendalias = QEMU_DOMAIN_DISK_PRIVATE(disk)->qomName;
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 9cf9718..802274e 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -6070,6 +6070,15 @@ qemuProcessPrepareSEVGuestInput(virDomainObjPtr vm)
>  }
>  
>  
> +bool
> +qemuProcessMissingLocalOptionalDisk(virDomainDiskDefPtr disk)

 Curious why you chose qemu_process and not qemu_domain or even
 virstoragefile?  This has nothing to do with whether the qemu process is
 running or not.
>>>
>>> Yeah, we have nothing qemu specific here. Just not sure is this useful
>>> for other purpuses or not.
>>>
>>
>> Since your chosen filter is "domain startup policy", I think qemu_domain
>> is where it belongs.
>>

> +{
> +return disk->

Re: [libvirt] [PATCH 0/2] Add mem cold/hot plug supported check to virDomainDefCompatibleDevice

2018-12-12 Thread Michal Privoznik
On 12/7/18 6:27 PM, John Ferlan wrote:
> https://bugzilla.redhat.com/show_bug.cgi?id=1624336
> 
> Details are in patch2, but essentially the issue is the check
> for whether cold/hot plug of memory is supported occurs during 
> qemuDomainDefValidateMemoryHotplug; however, that is called
> after virDomainDefCompatibleDevice, but is not called during
> the qemuDomainAttachDeviceConfig processing.
> 
> Another solution would be to modify virDomainDefCompatibleDevice
> to add a "if (def->mem.max_memory > 0 &&" check before the check
> for whether the size fits and virDomainDefHasMemoryHotplug could
> be called from qemuDomainAttachDeviceConfig, but that seems a bit
> strange. The additional call is to avoid the equally strange message
> that would appear "no free memory device slot available" because
> nmems == mem.memory_slots == 0. If this solution is preferred I'm
> fine with that, but figured I needed to start somewhere.
> 
> John Ferlan (2):
>   conf: Add the size of failed max_memory in error
>   conf: Add check/error for domain supports cold/hotplug
> 
>  src/conf/domain_conf.c | 10 +-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 

ACK

Michal

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH v2 1/2] qemuBuildMemoryBackendProps: Pass @priv instead of its individual members

2018-12-12 Thread Michal Privoznik
So far we have two arguments that we are passing to
qemuBuildMemoryBackendProps() and that are taken from domain
private data: @qemuCaps and @autoNodeset. In the next commit I
will use one more item from there. Therefore, instead of having
it as yet another argument to the function, pass pointer to the
private data object.

There is one change in qemuDomainAttachMemory() where previously
@autoNodeset was NULL but now is priv->autoNodeset (which may be
set). This is safe to do as @autoNodeset is advisory only.

Signed-off-by: Michal Privoznik 
---
 src/qemu/qemu_command.c | 30 ++
 src/qemu/qemu_command.h |  3 +--
 src/qemu/qemu_hotplug.c |  2 +-
 3 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 32ed83f277..01a3141134 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3201,22 +3201,21 @@ qemuBuildMemoryBackendPropsShare(virJSONValuePtr props,
  * @backendProps: [out] constructed object
  * @alias: alias of the device
  * @cfg: qemu driver config object
- * @qemuCaps: qemu capabilities object
+ * @priv: pointer to domain private object
  * @def: domain definition object
  * @mem: memory definition object
- * @autoNodeset: fallback nodeset in case of automatic NUMA placement
  * @force: forcibly use one of the backends
  *
  * Creates a configuration object that represents memory backend of given guest
- * NUMA node (domain @def and @mem). Use @autoNodeset to fine tune the
+ * NUMA node (domain @def and @mem). Use @priv->autoNodeset to fine tune the
  * placement of the memory on the host NUMA nodes.
  *
  * By default, if no memory-backend-* object is necessary to fulfil the guest
  * configuration value of 1 is returned. This behaviour can be suppressed by
  * setting @force to true in which case 0 would be returned.
  *
- * Then, if one of the three memory-backend-* should be used, the @qemuCaps is
- * consulted to check if qemu does support it.
+ * Then, if one of the three memory-backend-* should be used, the 
@priv->qemuCaps
+ * is consulted to check if qemu does support it.
  *
  * Returns: 0 on success,
  *  1 on success and if there's no need to use memory-backend-*
@@ -3226,10 +3225,9 @@ int
 qemuBuildMemoryBackendProps(virJSONValuePtr *backendProps,
 const char *alias,
 virQEMUDriverConfigPtr cfg,
-virQEMUCapsPtr qemuCaps,
+qemuDomainObjPrivatePtr priv,
 virDomainDefPtr def,
 virDomainMemoryDefPtr mem,
-virBitmapPtr autoNodeset,
 bool force)
 {
 const char *backendType = "memory-backend-file";
@@ -3379,7 +3377,7 @@ qemuBuildMemoryBackendProps(virJSONValuePtr *backendProps,
 
 if (!mem->nvdimmPath &&
 discard == VIR_TRISTATE_BOOL_YES) {
-if (!virQEMUCapsGet(qemuCaps, 
QEMU_CAPS_OBJECT_MEMORY_FILE_DISCARD)) {
+if (!virQEMUCapsGet(priv->qemuCaps, 
QEMU_CAPS_OBJECT_MEMORY_FILE_DISCARD)) {
 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this QEMU doesn't support memory discard"));
 goto cleanup;
@@ -3403,7 +3401,7 @@ qemuBuildMemoryBackendProps(virJSONValuePtr *backendProps,
 if (mem->sourceNodes) {
 nodemask = mem->sourceNodes;
 } else {
-if (virDomainNumatuneMaybeGetNodeset(def->numa, autoNodeset,
+if (virDomainNumatuneMaybeGetNodeset(def->numa, priv->autoNodeset,
  &nodemask, mem->targetNode) < 0)
 goto cleanup;
 }
@@ -3431,19 +3429,19 @@ qemuBuildMemoryBackendProps(virJSONValuePtr 
*backendProps,
 } else {
 /* otherwise check the required capability */
 if (STREQ(backendType, "memory-backend-file") &&
-!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
+!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE)) {
 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this qemu doesn't support the "
  "memory-backend-file object"));
 goto cleanup;
 } else if (STREQ(backendType, "memory-backend-ram") &&
-   !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_RAM)) {
+   !virQEMUCapsGet(priv->qemuCaps, 
QEMU_CAPS_OBJECT_MEMORY_RAM)) {
 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this qemu doesn't support the "
  "memory-backend-ram object"));
 goto cleanup;
 } else if (STREQ(backendType, "memory-backend-memory") &&
-   !virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_MEMFD)) {
+   !virQEMUCapsGet(priv->qemuCaps, 
QEMU_CAPS_OBJECT_MEMORY_MEMFD)) {
   

[libvirt] [PATCH v2 2/2] qemu: Don't use -mem-prealloc among with .prealloc=yes

2018-12-12 Thread Michal Privoznik
https://bugzilla.redhat.com/show_bug.cgi?id=1624223

There are two ways to request memory preallocation on cmd line:
-mem-prealloc and .prealloc attribute for a memory-backend-file.
However, as it turns out it's not safe to use both at the same
time. If -mem-prealloc is used then qemu will fullly allocate the
memory (this is done by actually touching every page that has
been allocated). Then, if .prealloc=yes is specified,
mbind(flags = MPOL_MF_STRICT | MPOL_MF_MOVE) is called which:

a) has to (possibly) move the memory to a different NUMA node,
b) can have no effect when hugepages are in play (thus ignoring user
request to place memory on desired NUMA nodes).

Prefer -mem-prealloc as it is more backward compatible
compared to switching to "-numa node,memdev=  + -object
memory-backend-file".

Signed-off-by: Michal Privoznik 
---
 src/qemu/qemu_command.c   | 26 ---
 src/qemu/qemu_domain.c|  7 +
 src/qemu/qemu_domain.h|  3 +++
 .../hugepages-numa-default-dimm.args  |  2 +-
 4 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 01a3141134..1a1cb9cbbd 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3357,11 +3357,13 @@ qemuBuildMemoryBackendProps(virJSONValuePtr 
*backendProps,
 if (mem->nvdimmPath) {
 if (VIR_STRDUP(memPath, mem->nvdimmPath) < 0)
 goto cleanup;
-prealloc = true;
+if (!priv->memPrealloc)
+prealloc = true;
 } else if (useHugepage) {
 if (qemuGetDomainHupageMemPath(def, cfg, pagesize, &memPath) < 0)
 goto cleanup;
-prealloc = true;
+if (!priv->memPrealloc)
+prealloc = true;
 } else {
 /* We can have both pagesize and mem source. If that's the case,
  * prefer hugepages as those are more specific. */
@@ -7576,7 +7578,8 @@ qemuBuildSmpCommandLine(virCommandPtr cmd,
 static int
 qemuBuildMemPathStr(virQEMUDriverConfigPtr cfg,
 const virDomainDef *def,
-virCommandPtr cmd)
+virCommandPtr cmd,
+qemuDomainObjPrivatePtr priv)
 {
 const long system_page_size = virGetSystemPageSizeKB();
 char *mem_path = NULL;
@@ -7598,8 +7601,10 @@ qemuBuildMemPathStr(virQEMUDriverConfigPtr cfg,
 return 0;
 }
 
-if (def->mem.allocation != VIR_DOMAIN_MEMORY_ALLOCATION_IMMEDIATE)
+if (def->mem.allocation != VIR_DOMAIN_MEMORY_ALLOCATION_IMMEDIATE) {
 virCommandAddArgList(cmd, "-mem-prealloc", NULL);
+priv->memPrealloc = true;
+}
 
 virCommandAddArgList(cmd, "-mem-path", mem_path, NULL);
 VIR_FREE(mem_path);
@@ -7612,7 +7617,8 @@ static int
 qemuBuildMemCommandLine(virCommandPtr cmd,
 virQEMUDriverConfigPtr cfg,
 const virDomainDef *def,
-virQEMUCapsPtr qemuCaps)
+virQEMUCapsPtr qemuCaps,
+qemuDomainObjPrivatePtr priv)
 {
 if (qemuDomainDefValidateMemoryHotplug(def, qemuCaps, NULL) < 0)
 return -1;
@@ -7631,15 +7637,17 @@ qemuBuildMemCommandLine(virCommandPtr cmd,
   virDomainDefGetMemoryInitial(def) / 1024);
 }
 
-if (def->mem.allocation == VIR_DOMAIN_MEMORY_ALLOCATION_IMMEDIATE)
+if (def->mem.allocation == VIR_DOMAIN_MEMORY_ALLOCATION_IMMEDIATE) {
 virCommandAddArgList(cmd, "-mem-prealloc", NULL);
+priv->memPrealloc = true;
+}
 
 /*
  * Add '-mem-path' (and '-mem-prealloc') parameter here if
  * the hugepages and no numa node is specified.
  */
 if (!virDomainNumaGetNodeCount(def->numa) &&
-qemuBuildMemPathStr(cfg, def, cmd) < 0)
+qemuBuildMemPathStr(cfg, def, cmd, priv) < 0)
 return -1;
 
 if (def->mem.locked && !virQEMUCapsGet(qemuCaps, 
QEMU_CAPS_REALTIME_MLOCK)) {
@@ -7748,7 +7756,7 @@ qemuBuildNumaArgStr(virQEMUDriverConfigPtr cfg,
 }
 
 if (!needBackend &&
-qemuBuildMemPathStr(cfg, def, cmd) < 0)
+qemuBuildMemPathStr(cfg, def, cmd, priv) < 0)
 goto cleanup;
 
 for (i = 0; i < ncells; i++) {
@@ -10441,7 +10449,7 @@ qemuBuildCommandLine(virQEMUDriverPtr driver,
 if (!migrateURI && !snapshot && qemuDomainAlignMemorySizes(def) < 0)
 goto error;
 
-if (qemuBuildMemCommandLine(cmd, cfg, def, qemuCaps) < 0)
+if (qemuBuildMemCommandLine(cmd, cfg, def, qemuCaps, priv) < 0)
 goto error;
 
 if (qemuBuildSmpCommandLine(cmd, def) < 0)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 509da6bfea..039b887d8e 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1944,6 +1944,8 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivatePtr 
priv)
 VIR_FREE(priv->libDir);
 VIR_FREE(priv->channelTargetDi

[libvirt] [PATCH v2 0/2] qemu: Don't use -mem-prealloc among with .prealloc=yes

2018-12-12 Thread Michal Privoznik
v2 of:

https://www.redhat.com/archives/libvir-list/2018-November/msg00159.html

diff to v1:
- Patch 01/02 is completely new
- Patch 02/02 has reworded commit message

Michal Prívozník (2):
  qemuBuildMemoryBackendProps: Pass @priv instead of its individual
members
  qemu: Don't use -mem-prealloc among with .prealloc=yes

 src/qemu/qemu_command.c   | 56 ++-
 src/qemu/qemu_command.h   |  3 +-
 src/qemu/qemu_domain.c|  7 +++
 src/qemu/qemu_domain.h|  3 +
 src/qemu/qemu_hotplug.c   |  2 +-
 .../hugepages-numa-default-dimm.args  |  2 +-
 6 files changed, 44 insertions(+), 29 deletions(-)

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [RFC v3 3/4] nvdimm: update qemu command-line generating for NVDIMM memory

2018-12-12 Thread Luyao Zhong
According to the result parsing from xml, add corresponding properties
into QEMU command line, including 'align', 'pmem' and 'unarmed'.

Signed-off-by: Luyao Zhong 
---
 src/qemu/qemu_command.c| 32 ++
 .../memory-hotplug-nvdimm-align.args   | 31 +
 .../memory-hotplug-nvdimm-pmem.args| 31 +
 .../memory-hotplug-nvdimm-unarmed.args | 31 +
 tests/qemuxml2argvtest.c   | 11 
 5 files changed, 136 insertions(+)
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-align.args
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-pmem.args
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-unarmed.args

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 32ed83f..73600b7 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3400,6 +3400,34 @@ qemuBuildMemoryBackendProps(virJSONValuePtr 
*backendProps,
 if (virJSONValueObjectAdd(props, "U:size", mem->size * 1024, NULL) < 0)
 goto cleanup;
 
+if (mem->alignsize) {
+if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE_ALIGN)) {
+virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+   _("align property is not available "
+ "with this QEMU binary"));
+goto cleanup;
+}
+if (virJSONValueObjectAdd(props,
+  "U:align",
+  mem->alignsize * 1024,
+  NULL) < 0)
+goto cleanup;
+}
+
+if (mem->nvdimmPmem) {
+if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_MEMORY_FILE_PMEM)) {
+virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+   _("pmem property is not available "
+ "with this QEMU binary"));
+goto cleanup;
+}
+if (virJSONValueObjectAdd(props,
+  "s:pmem",
+  mem->nvdimmPmem ? "on" : "off",
+  NULL) < 0)
+goto cleanup;
+}
+
 if (mem->sourceNodes) {
 nodemask = mem->sourceNodes;
 } else {
@@ -3569,6 +3597,10 @@ qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
 if (mem->labelsize)
 virBufferAsprintf(&buf, "label-size=%llu,", mem->labelsize * 1024);
 
+if (mem->nvdimmUnarmed)
+virBufferAsprintf(&buf, "unarmed=%s,",
+  mem->nvdimmUnarmed ? "on" : "off");
+
 virBufferAsprintf(&buf, "memdev=mem%s,id=%s",
   mem->info.alias, mem->info.alias);
 
diff --git a/tests/qemuxml2argvdata/memory-hotplug-nvdimm-align.args 
b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-align.args
new file mode 100644
index 000..432f622
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-align.args
@@ -0,0 +1,31 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-i686 \
+-name QEMUGuest1 \
+-S \
+-machine pc,accel=tcg,usb=off,dump-guest-core=off,nvdimm=on \
+-m size=219136k,slots=16,maxmem=1099511627776k \
+-smp 2,sockets=2,cores=1,threads=1 \
+-numa node,nodeid=0,cpus=0-1,mem=214 \
+-object memory-backend-file,id=memnvdimm0,prealloc=yes,mem-path=/tmp/nvdimm,\
+share=no,size=536870912,align=2097152 \
+-device nvdimm,node=0,memdev=memnvdimm0,id=nvdimm0,slot=0 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev 
socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
+server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,\
+bootindex=1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/memory-hotplug-nvdimm-pmem.args 
b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-pmem.args
new file mode 100644
index 000..d34ac5b
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-pmem.args
@@ -0,0 +1,31 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-i686 \
+-name QEMUGuest1 \
+-S \
+-machine pc,accel=tcg,usb=off,dump-guest-core=off,nvdimm=on \
+-m size=219136k,slots=16,maxmem=1099511627776k \
+-smp 2,sockets=2,cores=1,threads=1 \
+-numa node,nodeid=0,cpus=0-1,mem=214 \
+-object memory-backend-file,id=memnvdimm0,prealloc=yes,mem-path=/tmp/nvdimm,\
+share=no,size=536870912,pmem=on \
+-device nvdimm,node=0,memdev=memnvdimm0,id=nvdimm0,slot=0 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \

[libvirt] [RFC v3 1/4] nvdimm: introduce more config elements into xml for NVDIMM memory

2018-12-12 Thread Luyao Zhong
1.alignsize
The 'alignsize' option allows users to specify the proper alignment.

2.pmem
The 'pmem' option allows users to specify whether the backend storage of
memory-backend-file is a real persistent memory.

3.unarmed
The 'unarmed' option allows users to mark vNVDIMM read-only.

These options can be configured respectively or simultaneously in domain
xml file, here is an example:

  ...
  
  
  /dev/dax0.0
  2
  
  
  
  4094
  0
  
  2
  
  
  
  
  ...


Signed-off-by: Luyao Zhong 
---
 docs/formatdomain.html.in  | 80 ++
 docs/schemas/domaincommon.rng  | 23 ++-
 src/conf/domain_conf.c | 61 +++--
 src/conf/domain_conf.h |  3 +
 .../memory-hotplug-nvdimm-align.xml| 58 
 .../memory-hotplug-nvdimm-pmem.xml | 58 
 .../memory-hotplug-nvdimm-unarmed.xml  | 58 
 .../memory-hotplug-nvdimm-align.xml|  1 +
 .../memory-hotplug-nvdimm-pmem.xml |  1 +
 .../memory-hotplug-nvdimm-unarmed.xml  |  1 +
 tests/qemuxml2xmltest.c|  3 +
 11 files changed, 322 insertions(+), 25 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-align.xml
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-pmem.xml
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-unarmed.xml
 create mode 12 tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-align.xml
 create mode 12 tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-pmem.xml
 create mode 12 tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-unarmed.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 428b0e8..3f813f2 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -8322,6 +8322,8 @@ qemu-kvm -net nic,model=? /dev/null
   
 
   /tmp/nvdimm
+  2048
+  
 
 
   524288
@@ -8329,6 +8331,7 @@ qemu-kvm -net nic,model=? /dev/null
   
+  
 
   
 
@@ -8403,10 +8406,37 @@ qemu-kvm -net nic,model=? /dev/null
 
 
 
-  For model nvdimm this element is mandatory and has a
-  single child element path that represents a path
-  in the host that backs the nvdimm module in the guest.
+  For model nvdimm this element is mandatory. The
+  mandatory child element path represents a path in
+  the host that backs the nvdimm module in the guest. If
+  nvdimm is provided, then the following optional
+  elements can be provided as well:
 
+
+
+  alignsize
+  
+
+  This element can be used to specify a proper alignment.
+  When mmap(2) the backend files, QEMU uses the host page
+  size by default as the alignment of mapping address. However,
+  some backends may require alignments different from the page.
+  For example, mmap a real NVDIMM device maybe 2M-aligned required.
+  Since 4.9.0
+
+  
+
+  pmem
+  
+
+  This element can be used to specify whether the backend storage
+  of memory-backend-file is a real persistent memory. If the 
backend
+  is a real persistence memory and pmem is set, QEMU
+  will guarantee the persistence of its own writes to the vNVDIMM
+  backend.Since 4.9.0
+
+  
+
   
 
   target
@@ -8425,19 +8455,39 @@ qemu-kvm -net nic,model=? /dev/null
   NUMA nodes configured.
 
 
-  For NVDIMM type devices one can optionally use
-  label and its subelement size
-  to configure the size of namespaces label storage
-  within the NVDIMM module. The size element
-  has usual meaning described
-  here.
-  For QEMU domains the following restrictions apply:
+  Besides, the following optional elements can be provided as well for
+  NVDIMM type devices:
 
-
-  the minimum label size is 128KiB,
-  the remaining size (total-size - label-size) has to be aligned to
-4KiB
-
+
+
+  label
+  
+
+  For NVDIMM type devices one can optionally use
+  label and its subelement size
+  to configure the size of namespaces label storage
+  within the NVDIMM module. The size element
+  has usual meaning des

[libvirt] [RFC v3 2/4] nvdimm: add nvdimm-related qemucapabilities check

2018-12-12 Thread Luyao Zhong
-object memory-backend-file[,align=][,pmem=]

Signed-off-by: Luyao Zhong 
---
 src/qemu/qemu_capabilities.c   | 8 +++-
 src/qemu/qemu_capabilities.h   | 4 
 tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml | 1 +
 tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml   | 1 +
 tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml   | 1 +
 tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml  | 1 +
 tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml| 1 +
 tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml  | 1 +
 tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml  | 1 +
 tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml| 1 +
 tests/qemucapabilitiesdata/caps_3.0.0.x86_64.xml   | 1 +
 tests/qemucapabilitiesdata/caps_3.1.0.ppc64.xml| 2 ++
 tests/qemucapabilitiesdata/caps_3.1.0.x86_64.xml   | 2 ++
 13 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 9258bf6..8b518b1 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -516,7 +516,11 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
   "memory-backend-memfd.hugetlb",
   "iothread.poll-max-ns",
   "machine.pseries.cap-nested-hv",
-  "egl-headless.rendernode"
+  "egl-headless.rendernode",
+  "memory-backend-file.align",
+
+  /* 325 */
+  "memory-backend-file.pmem",
 );
 
 
@@ -1366,6 +1370,8 @@ static virQEMUCapsObjectTypeProps 
virQEMUCapsDeviceProps[] = {
 
 static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsMemoryBackendFile[] 
= {
 { "discard-data", QEMU_CAPS_OBJECT_MEMORY_FILE_DISCARD },
+{ "align", QEMU_CAPS_OBJECT_MEMORY_FILE_ALIGN },
+{ "pmem", QEMU_CAPS_OBJECT_MEMORY_FILE_PMEM },
 };
 
 static struct virQEMUCapsStringFlags 
virQEMUCapsObjectPropsMemoryBackendMemfd[] = {
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index c109887..f10b9a9 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -501,6 +501,10 @@ typedef enum { /* virQEMUCapsFlags grouping marker for 
syntax-check */
 QEMU_CAPS_IOTHREAD_POLLING, /* -object iothread.poll-max-ns */
 QEMU_CAPS_MACHINE_PSERIES_CAP_NESTED_HV, /* -machine pseries.cap-nested-hv 
*/
 QEMU_CAPS_EGL_HEADLESS_RENDERNODE, /* -display egl-headless,rendernode= */
+QEMU_CAPS_OBJECT_MEMORY_FILE_ALIGN, /* -object memory-backend-file,align= 
*/
+
+/* 325 */
+QEMU_CAPS_OBJECT_MEMORY_FILE_PMEM, /* -object memory-backend-file,pmem= */
 
 QEMU_CAPS_LAST /* this must always be the last item */
 } virQEMUCapsFlags;
diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml 
b/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml
index 8dd90f5..186a6cc 100644
--- a/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml
@@ -165,6 +165,7 @@
   
   
   
+  
   2011090
   0
   345725
diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml 
b/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml
index e646103..c47ebd7 100644
--- a/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml
@@ -163,6 +163,7 @@
   
   
   
+  
   2011090
   0
   426509
diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml 
b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml
index b18bd74..49249f5 100644
--- a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml
+++ b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml
@@ -132,6 +132,7 @@
   
   
   
+  
   2012000
   0
   375102
diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml 
b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml
index ac97e16..54c4a65 100644
--- a/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml
@@ -206,6 +206,7 @@
   
   
   
+  
   2011090
   0
   414371
diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml 
b/tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml
index f11d860..24a3c2b 100644
--- a/tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml
+++ b/tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml
@@ -163,6 +163,7 @@
   
   
   
+  
   2012050
   0
   444946
diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml 
b/tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml
index 552b319..1b5d8e6 100644
--- a/tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml
+++ b/tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml
@@ -103,6 +103,7 @@
   
   
   
+  
   300
   0
   0
diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml 
b/tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml
index 4f9832d..3c76f63 100644
--- a/tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml
+++ b/tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml
@@ -103,6 +103,7 @@
   
   
   
+  
   300
   0
   0
diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml 
b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xm

[libvirt] [RFC v3 4/4] nvdimm: update news.xml

2018-12-12 Thread Luyao Zhong
add more configure options for NVDIMM

Signed-off-by: Luyao Zhong 
---
 docs/news.xml | 9 +
 1 file changed, 9 insertions(+)

diff --git a/docs/news.xml b/docs/news.xml
index 5bdbd34..0112c91 100644
--- a/docs/news.xml
+++ b/docs/news.xml
@@ -38,6 +38,15 @@
   would normally prevent QEMU from accessing such a device.
 
   
+  
+
+  NVDIMM: support more configurations
+
+
+  Introduce more configuration options supported by QEMU community,
+  including 'alignsize', 'pmem', 'unarmed' and 'persistence'.
+
+  
 
 
 
-- 
2.7.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [RFC v3 0/4] update NVDIMM support

2018-12-12 Thread Luyao Zhong
Hi libvirt experts,

This is the RFC v3 for updating NVDIMM support in libvirt.

There are some gaps between qemu and libvirt, libvirt has not
supported several config options about NVDIMM memory while
qemu is ready now, including 'align', 'pmem', 'unarmed'.

I reworded and recoded my patches according to some feedback
comments from community once more.

But I met some issues I can't handle. I list them as follows:

a. add qemu_capabilities check
I want to add some nvdimm-related qemu_capabilities check, just
like 'QEMU_CAPS_OBJECT_MEMORY_FILE_ALIGN' in patch 2/4, and
I try to add the relevant sections into *.replies files manually.
But the qemucapabilitiestest failed, I don't know why. It seems
something wrong with the *.replies file. I think the *.replies
doesn't depends on other code or file, right? Could you help me address
this issue? The test log doesn't give me any useful info.

b. DO_TEST & DO_TEST_CAPS_LATEST
In the previous patches, several experts suggest me using
DO_TEST_CAPS_LATEST, but the testcases will fail. I guess it may
be related to the qemu_capabilities check I mentioned above. I'm
not sure if this issue will disappeared when the first one is be
resolved.

Besides, the whole nvdimm stuff do not introduce enough qemu_capabilities
check and do not use DO_TEST_CAPS_LATEST. Maybe it is better to do these
modification in another patch set. Or we can rely on qemu errors, it's just
what libvirt do currently. What' your comments?

Thank you in advance.

Regards,
Luyao Zhong

Luyao Zhong (4):
  nvdimm: introduce more config elements into xml for NVDIMM memory
  nvdimm: add nvdimm-related qemucapabilities check
  nvdimm: update qemu command-line generating for NVDIMM memory
  nvdimm: update news.xml

 docs/formatdomain.html.in  | 80 ++
 docs/news.xml  |  9 +++
 docs/schemas/domaincommon.rng  | 23 ++-
 src/conf/domain_conf.c | 61 +++--
 src/conf/domain_conf.h |  3 +
 src/qemu/qemu_capabilities.c   |  8 ++-
 src/qemu/qemu_capabilities.h   |  4 ++
 src/qemu/qemu_command.c| 32 +
 tests/qemucapabilitiesdata/caps_2.12.0.aarch64.xml |  1 +
 tests/qemucapabilitiesdata/caps_2.12.0.ppc64.xml   |  1 +
 tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml   |  1 +
 tests/qemucapabilitiesdata/caps_2.12.0.x86_64.xml  |  1 +
 tests/qemucapabilitiesdata/caps_3.0.0.ppc64.xml|  1 +
 tests/qemucapabilitiesdata/caps_3.0.0.riscv32.xml  |  1 +
 tests/qemucapabilitiesdata/caps_3.0.0.riscv64.xml  |  1 +
 tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml|  1 +
 tests/qemucapabilitiesdata/caps_3.0.0.x86_64.xml   |  1 +
 tests/qemucapabilitiesdata/caps_3.1.0.ppc64.xml|  2 +
 tests/qemucapabilitiesdata/caps_3.1.0.x86_64.xml   |  2 +
 .../memory-hotplug-nvdimm-align.args   | 31 +
 .../memory-hotplug-nvdimm-align.xml| 58 
 .../memory-hotplug-nvdimm-pmem.args| 31 +
 .../memory-hotplug-nvdimm-pmem.xml | 58 
 .../memory-hotplug-nvdimm-unarmed.args | 31 +
 .../memory-hotplug-nvdimm-unarmed.xml  | 58 
 tests/qemuxml2argvtest.c   | 11 +++
 .../memory-hotplug-nvdimm-align.xml|  1 +
 .../memory-hotplug-nvdimm-pmem.xml |  1 +
 .../memory-hotplug-nvdimm-unarmed.xml  |  1 +
 tests/qemuxml2xmltest.c|  3 +
 30 files changed, 491 insertions(+), 26 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-align.args
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-align.xml
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-pmem.args
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-pmem.xml
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-unarmed.args
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-unarmed.xml
 create mode 12 tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-align.xml
 create mode 12 tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-pmem.xml
 create mode 12 tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-unarmed.xml

-- 
2.7.4

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH v3 17/18] tools: Provide a script to recover fubar'ed XATTRs setup

2018-12-12 Thread Michal Privoznik
Our code is not bug free. The refcounting I introduced will
almost certainly not work in some use cases. Provide a script
that will remove all the XATTRs set by libvirt so that it can
start cleanly.

Signed-off-by: Michal Privoznik 
---
 tools/Makefile.am   |  1 +
 tools/libvirt_recover_xattrs.sh | 96 +
 2 files changed, 97 insertions(+)
 create mode 100755 tools/libvirt_recover_xattrs.sh

diff --git a/tools/Makefile.am b/tools/Makefile.am
index f069167acc..1dc009c4fb 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -75,6 +75,7 @@ EXTRA_DIST = \
virt-login-shell.conf \
virsh-edit.c \
bash-completion/vsh \
+   libvirt_recover_xattrs.sh \
$(PODFILES) \
$(MANINFILES) \
$(NULL)
diff --git a/tools/libvirt_recover_xattrs.sh b/tools/libvirt_recover_xattrs.sh
new file mode 100755
index 00..69dfca0160
--- /dev/null
+++ b/tools/libvirt_recover_xattrs.sh
@@ -0,0 +1,96 @@
+#!/bin/bash
+
+function die {
+echo $@ >&2
+exit 1
+}
+
+function show_help {
+cat << EOF
+Usage: ${0##*/} -[hqn] [PATH]
+
+Clear out any XATTRs set by libvirt on all files that have them.
+The idea is to reset refcounting, should it break.
+
+  -hdisplay this help and exit
+  -qquiet (don't print which files are being fixed)
+  -ndry run; don't remove any XATTR just report the file name
+
+PATH can be specified to refine search to only to given path
+instead of whole root ('/'), which is the default.
+EOF
+}
+
+QUIET=0
+DRY_RUN=0
+P="/"
+
+# So far only qemu and lxc drivers use security driver.
+URI=("qemu:///system"
+ "qemu:///session"
+ "lxc:///system")
+
+LIBVIRT_XATTR_PREFIX="trusted.libvirt.security"
+
+if [ `whoami` != "root" ]; then
+die "Must be run as root"
+fi
+
+while getopts hqn opt; do
+case $opt in
+h)
+show_help
+exit 0
+;;
+q)
+QUIET=1
+;;
+n)
+DRY_RUN=1
+;;
+*)
+show_help >&2
+exit 1
+;;
+esac
+done
+
+shift $((OPTIND - 1))
+if [ $# -gt 0 ]; then
+P=$1
+fi
+
+if [ ${DRY_RUN} -eq 0 ]; then
+for u in ${URI[*]} ; do
+if [ -n "`virsh -q -c $u list 2>/dev/null`" ]; then
+die "There are still some domains running for $u"
+fi
+done
+fi
+
+
+# On Linux we use 'trusted' namespace, on FreeBSD we use 'system'
+# as there is no 'trusted'.
+XATTRS=("trusted.libvirt.security.dac"
+"trusted.libvirt.security.ref_dac"
+"trusted.libvirt.security.selinux"
+"trusted.libvirt.security.ref_selinux",
+"system.libvirt.security.dac"
+"system.libvirt.security.ref_dac"
+"system.libvirt.security.selinux"
+"system.libvirt.security.ref_selinux")
+
+for i in $(getfattr -R -d -m ${LIBVIRT_XATTR_PREFIX} --absolute-names ${P} 
2>/dev/null | grep "^# file:" | cut -d':' -f 2); do
+if [ ${DRY_RUN} -ne 0 ]; then
+echo $i
+getfattr -d -m ${LIBVIRT_XATTR_PREFIX} $i
+continue
+fi
+
+if [ ${QUIET} -eq 0 ]; then
+echo "Fixing $i";
+fi
+for x in ${XATTRS[*]}; do
+setfattr -x $x $i
+done
+done
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH v3 18/18] qemu.conf: Allow users to enable/disable label remembering

2018-12-12 Thread Michal Privoznik
Signed-off-by: Michal Privoznik 
---
 src/qemu/libvirtd_qemu.aug | 1 +
 src/qemu/qemu.conf | 4 
 src/qemu/qemu_conf.c   | 4 
 src/qemu/test_libvirtd_qemu.aug.in | 1 +
 4 files changed, 10 insertions(+)

diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
index ddc4bbfd1d..8a5b39e568 100644
--- a/src/qemu/libvirtd_qemu.aug
+++ b/src/qemu/libvirtd_qemu.aug
@@ -71,6 +71,7 @@ module Libvirtd_qemu =
  | str_entry "user"
  | str_entry "group"
  | bool_entry "dynamic_ownership"
+ | bool_entry "remember_owner"
  | str_array_entry "cgroup_controllers"
  | str_array_entry "cgroup_device_acl"
  | int_entry "seccomp_sandbox"
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index 8391332cb4..29093f6329 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -450,6 +450,10 @@
 # Set to 0 to disable file ownership changes.
 #dynamic_ownership = 1
 
+# Whether libvirt should remember and restore the original
+# ownership over files it is relabeling. Defaults to 1, set
+# to 0 to disable the feature.
+#remember_owner = 1
 
 # What cgroup controllers to make use of with QEMU guests
 #
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index a946b05d5d..89491a37b7 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -147,6 +147,7 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool 
privileged)
 cfg->group = (gid_t)-1;
 }
 cfg->dynamicOwnership = privileged;
+cfg->rememberOwner = true;
 
 cfg->cgroupControllers = -1; /* -1 == auto-detect */
 
@@ -730,6 +731,9 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
 if (virConfGetValueBool(conf, "dynamic_ownership", &cfg->dynamicOwnership) 
< 0)
 goto cleanup;
 
+if (virConfGetValueBool(conf, "remember_owner", &cfg->rememberOwner) < 0)
+goto cleanup;
+
 if (virConfGetValueStringList(conf,  "cgroup_controllers", false,
   &controllers) < 0)
 goto cleanup;
diff --git a/src/qemu/test_libvirtd_qemu.aug.in 
b/src/qemu/test_libvirtd_qemu.aug.in
index f1e8806ad2..92a8ae1192 100644
--- a/src/qemu/test_libvirtd_qemu.aug.in
+++ b/src/qemu/test_libvirtd_qemu.aug.in
@@ -43,6 +43,7 @@ module Test_libvirtd_qemu =
 { "user" = "root" }
 { "group" = "root" }
 { "dynamic_ownership" = "1" }
+{ "remember_owner" = "1" }
 { "cgroup_controllers"
 { "1" = "cpu" }
 { "2" = "devices" }
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH v3 14/18] virSecuritySELinuxRestoreAllLabel: Reorder device relabeling

2018-12-12 Thread Michal Privoznik
It helps whe trying to match calls with virSecuritySELinuxSetAllLabel
if the order in which devices are set/restored is the same in
both functions.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_selinux.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 4b68eb2717..4e30523e2c 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -2620,8 +2620,11 @@ virSecuritySELinuxRestoreAllLabel(virSecurityManagerPtr 
mgr,
 if (!secdef || !secdef->relabel || data->skipAllLabel)
 return 0;
 
-if (def->tpm) {
-if (virSecuritySELinuxRestoreTPMFileLabelInt(mgr, def, def->tpm) < 0)
+for (i = 0; i < def->ndisks; i++) {
+virDomainDiskDefPtr disk = def->disks[i];
+
+if (virSecuritySELinuxRestoreImageLabelInt(mgr, def, disk->src,
+   migrated) < 0)
 rc = -1;
 }
 
@@ -2643,11 +2646,8 @@ virSecuritySELinuxRestoreAllLabel(virSecurityManagerPtr 
mgr,
 return -1;
 }
 
-for (i = 0; i < def->ndisks; i++) {
-virDomainDiskDefPtr disk = def->disks[i];
-
-if (virSecuritySELinuxRestoreImageLabelInt(mgr, def, disk->src,
-   migrated) < 0)
+if (def->tpm) {
+if (virSecuritySELinuxRestoreTPMFileLabelInt(mgr, def, def->tpm) < 0)
 rc = -1;
 }
 
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 05/18] virSecurityDACRestoreAllLabel: Reorder device relabeling

2018-12-12 Thread Michal Privoznik
It helps whe trying to match calls with virSecurityDACSetAllLabel
if the order in which devices are set/restored is the same in
both functions.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_dac.c | 36 ++--
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 7be555903d..4935c962b9 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1664,24 +1664,6 @@ virSecurityDACRestoreAllLabel(virSecurityManagerPtr mgr,
 VIR_DEBUG("Restoring security label on %s migrated=%d",
   def->name, migrated);
 
-for (i = 0; i < def->nhostdevs; i++) {
-if (virSecurityDACRestoreHostdevLabel(mgr,
-  def,
-  def->hostdevs[i],
-  NULL) < 0)
-rc = -1;
-}
-
-for (i = 0; i < def->ngraphics; i++) {
-if (virSecurityDACRestoreGraphicsLabel(mgr, def, def->graphics[i]) < 0)
-return -1;
-}
-
-for (i = 0; i < def->ninputs; i++) {
-if (virSecurityDACRestoreInputLabel(mgr, def, def->inputs[i]) < 0)
-rc = -1;
-}
-
 for (i = 0; i < def->ndisks; i++) {
 if (virSecurityDACRestoreImageLabelInt(mgr,
def,
@@ -1690,6 +1672,24 @@ virSecurityDACRestoreAllLabel(virSecurityManagerPtr mgr,
 rc = -1;
 }
 
+for (i = 0; i < def->ngraphics; i++) {
+if (virSecurityDACRestoreGraphicsLabel(mgr, def, def->graphics[i]) < 0)
+return -1;
+}
+
+for (i = 0; i < def->ninputs; i++) {
+if (virSecurityDACRestoreInputLabel(mgr, def, def->inputs[i]) < 0)
+rc = -1;
+}
+
+for (i = 0; i < def->nhostdevs; i++) {
+if (virSecurityDACRestoreHostdevLabel(mgr,
+  def,
+  def->hostdevs[i],
+  NULL) < 0)
+rc = -1;
+}
+
 for (i = 0; i < def->nmems; i++) {
 if (virSecurityDACRestoreMemoryLabel(mgr,
  def,
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 10/18] security_selinux: Track if transaction is restore

2018-12-12 Thread Michal Privoznik
It is going to be important to know if the current transaction we
are running is a restore operation or set label operation so that
we know whether to call virSecurityGetRememberedLabel() or
virSecuritySetRememberedLabel(). That is, whether we are in a
restore and therefore have to fetch the remembered label, or we
are in set operation and therefore have to store the original
label.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_selinux.c | 36 +++--
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 95e9a1b0c7..715d9a428b 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -85,6 +85,7 @@ struct _virSecuritySELinuxContextItem {
 char *path;
 char *tcon;
 bool optional;
+bool restore;
 };
 
 typedef struct _virSecuritySELinuxContextList virSecuritySELinuxContextList;
@@ -123,7 +124,8 @@ static int
 virSecuritySELinuxContextListAppend(virSecuritySELinuxContextListPtr list,
 const char *path,
 const char *tcon,
-bool optional)
+bool optional,
+bool restore)
 {
 int ret = -1;
 virSecuritySELinuxContextItemPtr item = NULL;
@@ -135,6 +137,7 @@ 
virSecuritySELinuxContextListAppend(virSecuritySELinuxContextListPtr list,
 goto cleanup;
 
 item->optional = optional;
+item->restore = restore;
 
 if (VIR_APPEND_ELEMENT(list->items, list->nItems, item) < 0)
 goto cleanup;
@@ -178,7 +181,8 @@ virSecuritySELinuxContextListFree(void *opaque)
 static int
 virSecuritySELinuxTransactionAppend(const char *path,
 const char *tcon,
-bool optional)
+bool optional,
+bool restore)
 {
 virSecuritySELinuxContextListPtr list;
 
@@ -186,7 +190,7 @@ virSecuritySELinuxTransactionAppend(const char *path,
 if (!list)
 return 0;
 
-if (virSecuritySELinuxContextListAppend(list, path, tcon, optional) < 0)
+if (virSecuritySELinuxContextListAppend(list, path, tcon, optional, 
restore) < 0)
 return -1;
 
 return 1;
@@ -198,6 +202,11 @@ static int virSecuritySELinuxSetFileconHelper(const char 
*path,
   bool optional,
   bool privileged);
 
+
+static int virSecuritySELinuxRestoreFileLabel(virSecurityManagerPtr mgr,
+  const char *path);
+
+
 /**
  * virSecuritySELinuxTransactionRun:
  * @pid: process pid
@@ -242,13 +251,18 @@ virSecuritySELinuxTransactionRun(pid_t pid 
ATTRIBUTE_UNUSED,
 virSecuritySELinuxContextItemPtr item = list->items[i];
 
 /* TODO Implement rollback */
-if (virSecuritySELinuxSetFileconHelper(item->path,
-   item->tcon,
-   item->optional,
-   privileged) < 0) {
-rv = -1;
-break;
+if (!item->restore) {
+rv = virSecuritySELinuxSetFileconHelper(item->path,
+item->tcon,
+item->optional,
+privileged);
+} else {
+rv = virSecuritySELinuxRestoreFileLabel(list->manager,
+item->path);
 }
+
+if (rv < 0)
+break;
 }
 
 if (list->lock)
@@ -1265,7 +1279,7 @@ virSecuritySELinuxSetFileconHelper(const char *path, 
const char *tcon,
 {
 int rc;
 
-if ((rc = virSecuritySELinuxTransactionAppend(path, tcon, optional)) < 0)
+if ((rc = virSecuritySELinuxTransactionAppend(path, tcon, optional, 
false)) < 0)
 return -1;
 else if (rc > 0)
 return 0;
@@ -1387,7 +1401,7 @@ virSecuritySELinuxRestoreFileLabel(virSecurityManagerPtr 
mgr,
 goto cleanup;
 }
 
-if ((rc = virSecuritySELinuxTransactionAppend(path, fcon, false)) < 0)
+if ((rc = virSecuritySELinuxTransactionAppend(path, fcon, false, true)) < 
0)
 return -1;
 else if (rc > 0)
 return 0;
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 01/18] util: Introduce xattr getter/setter/remover

2018-12-12 Thread Michal Privoznik
Signed-off-by: Michal Privoznik 
---
 src/libvirt_private.syms |   3 +
 src/util/virfile.c   | 121 +++
 src/util/virfile.h   |  11 
 3 files changed, 135 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fd63c9ca61..9835e9a56c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1830,6 +1830,7 @@ virFileGetACLs;
 virFileGetHugepageSize;
 virFileGetMountReverseSubtree;
 virFileGetMountSubtree;
+virFileGetXAttr;
 virFileHasSuffix;
 virFileInData;
 virFileIsAbsPath;
@@ -1869,6 +1870,7 @@ virFileReadValueUint;
 virFileRelLinkPointsTo;
 virFileRemove;
 virFileRemoveLastComponent;
+virFileRemoveXAttr;
 virFileResolveAllLinks;
 virFileResolveLink;
 virFileRewrite;
@@ -1876,6 +1878,7 @@ virFileRewriteStr;
 virFileSanitizePath;
 virFileSetACLs;
 virFileSetupDev;
+virFileSetXAttr;
 virFileSkipRoot;
 virFileStripSuffix;
 virFileTouch;
diff --git a/src/util/virfile.c b/src/util/virfile.c
index f6f9e4ceda..263c92667c 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -64,6 +64,10 @@
 # include 
 #endif
 
+#if HAVE_LIBATTR
+# include 
+#endif
+
 #include "configmake.h"
 #include "intprops.h"
 #include "vircommand.h"
@@ -4354,3 +4358,120 @@ virFileWaitForExists(const char *path,
 
 return 0;
 }
+
+
+#if HAVE_LIBATTR
+/**
+ * virFileGetXAttr;
+ * @path: a filename
+ * @name: name of xattr
+ * @value: read value
+ *
+ * Reads xattr with @name for given @path and stores it into
+ * @value. Caller is responsible for freeing @value.
+ *
+ * Returns: 0 on success,
+ * -1 otherwise (with errno set).
+ */
+int
+virFileGetXAttr(const char *path,
+const char *name,
+char **value)
+{
+char *buf = NULL;
+int ret = -1;
+
+/* We might be racing with somebody who sets the same attribute. */
+while (1) {
+ssize_t need;
+ssize_t got;
+
+/* The first call determines how many bytes we need to allocate. */
+if ((need = getxattr(path, name, NULL, 0)) < 0)
+goto cleanup;
+
+if (VIR_REALLOC_N_QUIET(buf, need + 1) < 0)
+goto cleanup;
+
+if ((got = getxattr(path, name, buf, need)) < 0) {
+if (errno == ERANGE)
+continue;
+goto cleanup;
+}
+
+buf[got] = '\0';
+break;
+}
+
+VIR_STEAL_PTR(*value, buf);
+ret = 0;
+ cleanup:
+VIR_FREE(buf);
+return ret;
+}
+
+/**
+ * virFileSetXAttr:
+ * @path: a filename
+ * @name: name of xattr
+ * @value: value to set
+ *
+ * Sets xattr of @name and @value on @path.
+ *
+ * Returns: 0 on success,
+ * -1 otherwise (with errno set).
+ */
+int
+virFileSetXAttr(const char *path,
+const char *name,
+const char *value)
+{
+return setxattr(path, name, value, strlen(value), 0);
+}
+
+/**
+ * virFileRemoveXAttr:
+ * @path: a filename
+ * @name: name of xattr
+ *
+ * Remove xattr of @name on @path.
+ *
+ * Returns: 0 on success,
+ * -1 otherwise (with errno set).
+ */
+int
+virFileRemoveXAttr(const char *path,
+   const char *name)
+{
+return removexattr(path, name);
+}
+
+#else /* !HAVE_LIBATTR */
+
+int
+virFileGetXAttr(const char *path ATTRIBUTE_UNUSED,
+const char *name ATTRIBUTE_UNUSED,
+char **value ATTRIBUTE_UNUSED)
+{
+errno = ENOSYS;
+return -1;
+}
+
+int
+virFileSetXAttr(const char *path ATTRIBUTE_UNUSED,
+const char *name ATTRIBUTE_UNUSED,
+const char *value ATTRIBUTE_UNUSED)
+{
+errno = ENOSYS;
+return -1;
+}
+
+int
+virFileRemoveXAttr(const char *path ATTRIBUTE_UNUSED,
+   const char *name ATTRIBUTE_UNUSED)
+{
+errno = ENOSYS;
+return -1;
+}
+
+#endif /* HAVE_LIBATTR */
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 0f7dece958..aa4c29dc40 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -383,4 +383,15 @@ int virFileInData(int fd,
 
 VIR_DEFINE_AUTOPTR_FUNC(virFileWrapperFd, virFileWrapperFdFree)
 
+int virFileGetXAttr(const char *path,
+const char *name,
+char **value);
+
+int virFileSetXAttr(const char *path,
+const char *name,
+const char *value);
+
+int virFileRemoveXAttr(const char *path,
+   const char *name);
+
 #endif /* __VIR_FILE_H */
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH v3 16/18] tests: Introduce qemusecuritytest

2018-12-12 Thread Michal Privoznik
This test checks if security label remembering works correctly.
It uses qemuSecurity* APIs to do that. And some mocking (even
though it's not real mocking as we are used to from other tests
like virpcitest). So far, only DAC driver is tested.

Signed-off-by: Michal Privoznik 
---
 cfg.mk   |   4 +-
 src/util/virfile.h   |  15 +-
 tests/Makefile.am|  10 +
 tests/qemusecuritymock.c | 480 +++
 tests/qemusecuritytest.c | 173 ++
 tests/qemusecuritytest.h |  28 +++
 6 files changed, 703 insertions(+), 7 deletions(-)
 create mode 100644 tests/qemusecuritymock.c
 create mode 100644 tests/qemusecuritytest.c
 create mode 100644 tests/qemusecuritytest.h

diff --git a/cfg.mk b/cfg.mk
index c468d153eb..bd67cfd940 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -1178,7 +1178,7 @@ exclude_file_name_regexp--sc_copyright_usage = \
   ^COPYING(|\.LESSER)$$
 
 exclude_file_name_regexp--sc_flags_usage = \
-  
^(cfg\.mk|docs/|src/util/virnetdevtap\.c$$|tests/((vir(cgroup|pci|test|usb)|nss|qemuxml2argv)mock|virfilewrapper)\.c$$)
+  
^(cfg\.mk|docs/|src/util/virnetdevtap\.c$$|tests/((vir(cgroup|pci|test|usb)|nss|qemuxml2argv|qemusecurity)mock|virfilewrapper)\.c$$)
 
 exclude_file_name_regexp--sc_libvirt_unmarked_diagnostics = \
   ^(src/rpc/gendispatch\.pl$$|tests/)
@@ -1201,7 +1201,7 @@ exclude_file_name_regexp--sc_prohibit_strdup = \
   
^(docs/|examples/|src/util/virstring\.c|tests/vir(netserverclient|cgroup)mock.c|tests/commandhelper\.c$$)
 
 exclude_file_name_regexp--sc_prohibit_close = \
-  
(\.p[yl]$$|\.spec\.in$$|^docs/|^(src/util/virfile\.c|src/libvirt-stream\.c|tests/vir.+mock\.c|tests/commandhelper\.c)$$)
+  
(\.p[yl]$$|\.spec\.in$$|^docs/|^(src/util/virfile\.c|src/libvirt-stream\.c|tests/(vir.+mock\.c|commandhelper\.c|qemusecuritymock\.c))$$)
 
 exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
   
(^tests/(virhostcpu|virpcitest)data/|docs/js/.*\.js|docs/fonts/.*\.woff|\.diff|tests/virconfdata/no-newline\.conf$$)
diff --git a/src/util/virfile.h b/src/util/virfile.h
index aa4c29dc40..9304d69349 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -115,8 +115,10 @@ int virFileWrapperFdClose(virFileWrapperFdPtr dfd);
 
 void virFileWrapperFdFree(virFileWrapperFdPtr dfd);
 
-int virFileLock(int fd, bool shared, off_t start, off_t len, bool waitForLock);
-int virFileUnlock(int fd, off_t start, off_t len);
+int virFileLock(int fd, bool shared, off_t start, off_t len, bool waitForLock)
+ATTRIBUTE_NOINLINE;
+int virFileUnlock(int fd, off_t start, off_t len)
+ATTRIBUTE_NOINLINE;
 
 int virFileFlock(int fd, bool lock, bool shared);
 
@@ -385,13 +387,16 @@ VIR_DEFINE_AUTOPTR_FUNC(virFileWrapperFd, 
virFileWrapperFdFree)
 
 int virFileGetXAttr(const char *path,
 const char *name,
-char **value);
+char **value)
+ATTRIBUTE_NOINLINE;
 
 int virFileSetXAttr(const char *path,
 const char *name,
-const char *value);
+const char *value)
+ATTRIBUTE_NOINLINE;
 
 int virFileRemoveXAttr(const char *path,
-   const char *name);
+   const char *name)
+ATTRIBUTE_NOINLINE;
 
 #endif /* __VIR_FILE_H */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d7ec7e3a6f..fbecf4179d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -289,6 +289,7 @@ test_programs += qemuxml2argvtest qemuxml2xmltest \
qemucommandutiltest \
qemublocktest \
qemumigparamstest \
+   qemusecuritytest \
$(NULL)
 test_helpers += qemucapsprobe
 test_libraries += libqemumonitortestutils.la \
@@ -683,6 +684,13 @@ qemumigparamstest_SOURCES = \
 qemumigparamstest_LDADD = libqemumonitortestutils.la \
$(qemu_LDADDS) $(LDADDS)
 
+qemusecuritytest_SOURCES = \
+   qemusecuritytest.c qemusecuritytest.h \
+   qemusecuritymock.c \
+   testutils.h testutils.c \
+   testutilsqemu.h testutilsqemu.c
+qemusecuritytest_LDADD = $(qemu_LDADDS) $(LDADDS)
+
 else ! WITH_QEMU
 EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c \
domainsnapshotxml2xmltest.c \
@@ -694,6 +702,8 @@ EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c 
qemuargv2xmltest.c \
qemumemlocktest.c qemucpumock.c testutilshostcpus.h \
qemublocktest.c \
qemumigparamstest.c \
+   qemusecuritytest.c qemusecuritytest.h \
+   qemusecuritymock.c \
$(QEMUMONITORTESTUTILS_SOURCES)
 endif ! WITH_QEMU
 
diff --git a/tests/qemusecuritymock.c b/tests/qemusecuritymock.c
new file mode 100644
index 00..6148d02cb0
--- /dev/null
+++ b/tests/qemusecuritymock.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (

[libvirt] [PATCH v3 04/18] virSecurityDACTransactionRun: Implement rollback

2018-12-12 Thread Michal Privoznik
When iterating over list of paths/disk sources to relabel it may
happen that the process fails at some point. In that case, for
the sake of keeping seclabel refcount (stored in XATTRs) in sync
with reality we have to perform rollback. However, if that fails
too the only thing we can do is warn user.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_dac.c | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index f01d0b4732..7be555903d 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -229,7 +229,6 @@ virSecurityDACTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
 for (i = 0; i < list->nItems; i++) {
 virSecurityDACChownItemPtr item = list->items[i];
 
-/* TODO Implement rollback */
 if (!item->restore) {
 rv = virSecurityDACSetOwnership(list->manager,
 item->src,
@@ -246,6 +245,19 @@ virSecurityDACTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
 break;
 }
 
+for (; rv < 0 && i > 0; i--) {
+virSecurityDACChownItemPtr item = list->items[i - 1];
+
+if (!item->restore) {
+virSecurityDACRestoreFileLabelInternal(list->manager,
+   item->src,
+   item->path);
+} else {
+VIR_WARN("Ignoring failed restore attempt on %s",
+ NULLSTR(item->src ? item->src->path : item->path));
+}
+}
+
 if (list->lock)
 virSecurityManagerMetadataUnlock(list->manager, &state);
 
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 15/18] virSecuritySELinuxRestoreAllLabel: Restore more labels

2018-12-12 Thread Michal Privoznik
We are setting label on kernel, initrd, dtb and slic_table files.
But we never restored it.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_selinux.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 4e30523e2c..2d32e65f13 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -2672,6 +2672,22 @@ virSecuritySELinuxRestoreAllLabel(virSecurityManagerPtr 
mgr,
 virSecuritySELinuxRestoreFileLabel(mgr, def->os.loader->nvram, false) 
< 0)
 rc = -1;
 
+if (def->os.kernel &&
+virSecuritySELinuxRestoreFileLabel(mgr, def->os.kernel, false) < 0)
+rc = -1;
+
+if (def->os.initrd &&
+virSecuritySELinuxRestoreFileLabel(mgr, def->os.initrd, false) < 0)
+rc = -1;
+
+if (def->os.dtb &&
+virSecuritySELinuxRestoreFileLabel(mgr, def->os.dtb, false) < 0)
+rc = -1;
+
+if (def->os.slic_table &&
+virSecuritySELinuxRestoreFileLabel(mgr, def->os.slic_table, false) < 0)
+rc = -1;
+
 return rc;
 }
 
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 13/18] virSecuritySELinuxTransactionRun: Implement rollback

2018-12-12 Thread Michal Privoznik
When iterating over list of paths/disk sources to relabel it may
happen that the process fails at some point. In that case, for
the sake of keeping seclabel refcount (stored in XATTRs) in sync
with reality we have to perform rollback. However, if that fails
too the only thing we can do is warn user.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_selinux.c | 13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index f52c88259d..4b68eb2717 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -276,7 +276,6 @@ virSecuritySELinuxTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
 for (i = 0; i < list->nItems; i++) {
 virSecuritySELinuxContextItemPtr item = list->items[i];
 
-/* TODO Implement rollback */
 if (!item->restore) {
 rv = virSecuritySELinuxSetFileconHelper(list->manager,
 item->path,
@@ -293,6 +292,18 @@ virSecuritySELinuxTransactionRun(pid_t pid 
ATTRIBUTE_UNUSED,
 break;
 }
 
+for (; rv < 0 && i > 0; i--) {
+virSecuritySELinuxContextItemPtr item = list->items[i - 1];
+
+if (!item->restore) {
+virSecuritySELinuxRestoreFileLabel(list->manager,
+   item->path,
+   list->lock);
+} else {
+VIR_WARN("Ignoring failed restore attempt on %s", item->path);
+}
+}
+
 if (list->lock)
 virSecurityManagerMetadataUnlock(list->manager, &state);
 
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 07/18] security_dac: Allow callers to enable/disable label remembering/recall

2018-12-12 Thread Michal Privoznik
Because the implementation that will be used for label
remembering/recall is not atomic we have to give callers a chance
to enable or disable it. That is, enable it if and only if
metadata locking is enabled. Otherwise the feature MUST be turned
off.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_dac.c | 74 ++---
 1 file changed, 45 insertions(+), 29 deletions(-)

diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index dcd0bb558a..e5899c1746 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -182,11 +182,13 @@ static int 
virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
   const virStorageSource *src,
   const char *path,
   uid_t uid,
-  gid_t gid);
+  gid_t gid,
+  bool remember);
 
 static int virSecurityDACRestoreFileLabelInternal(virSecurityManagerPtr mgr,
   const virStorageSource *src,
-  const char *path);
+  const char *path,
+  bool recall);
 /**
  * virSecurityDACTransactionRun:
  * @pid: process pid
@@ -234,11 +236,13 @@ virSecurityDACTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
 item->src,
 item->path,
 item->uid,
-item->gid);
+item->gid,
+list->lock);
 } else {
 rv = virSecurityDACRestoreFileLabelInternal(list->manager,
 item->src,
-item->path);
+item->path,
+list->lock);
 }
 
 if (rv < 0)
@@ -251,7 +255,8 @@ virSecurityDACTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
 if (!item->restore) {
 virSecurityDACRestoreFileLabelInternal(list->manager,
item->src,
-   item->path);
+   item->path,
+   list->lock);
 } else {
 VIR_WARN("Ignoring failed restore attempt on %s",
  NULLSTR(item->src ? item->src->path : item->path));
@@ -699,7 +704,8 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
const virStorageSource *src,
const char *path,
uid_t uid,
-   gid_t gid)
+   gid_t gid,
+   bool remember)
 {
 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
 struct stat sb;
@@ -717,7 +723,7 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
 else if (rc > 0)
 return 0;
 
-if (path) {
+if (remember && path) {
 if (stat(path, &sb) < 0) {
 virReportSystemError(errno, _("unable to stat: %s"), path);
 return -1;
@@ -739,7 +745,7 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
  * this function. However, if our attempt fails, there's
  * not much we can do. XATTRs refcounting is fubar'ed and
  * the only option we have is warn users. */
-if (virSecurityDACRestoreFileLabelInternal(mgr, src, path) < 0)
+if (virSecurityDACRestoreFileLabelInternal(mgr, src, path, remember) < 
0)
 VIR_WARN("Unable to restore label on '%s'. "
  "XATTRs might have been left in inconsistent state.",
  NULLSTR(src ? src->path : path));
@@ -755,7 +761,8 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
 static int
 virSecurityDACRestoreFileLabelInternal(virSecurityManagerPtr mgr,
const virStorageSource *src,
-   const char *path)
+   const char *path,
+   bool recall)
 {
 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
 int rv;
@@ -774,7 +781,7 @@ 
virSecurityDACRestoreFileLabelInternal(virSecurityManagerPtr mgr,
 else if (rv > 0)
 return 0;
 
-if (path) {
+if (recall && path) {
 rv = virSecurityDACRecallLabel(priv, path, &uid, &gid);
 if (rv < 0)
 return -1;
@@ -793,7 +800,7 @@ stati

[libvirt] [PATCH v3 06/18] virSecurityDACRestoreAllLabel: Restore more labels

2018-12-12 Thread Michal Privoznik
We are setting label on kernel, initrd, dtb and slic_table files.
But we never restored it.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_dac.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 4935c962b9..dcd0bb558a 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1719,6 +1719,22 @@ virSecurityDACRestoreAllLabel(virSecurityManagerPtr mgr,
 virSecurityDACRestoreFileLabel(mgr, def->os.loader->nvram) < 0)
 rc = -1;
 
+if (def->os.kernel &&
+virSecurityDACRestoreFileLabel(mgr, def->os.kernel) < 0)
+rc = -1;
+
+if (def->os.initrd &&
+virSecurityDACRestoreFileLabel(mgr, def->os.initrd) < 0)
+rc = -1;
+
+if (def->os.dtb &&
+virSecurityDACRestoreFileLabel(mgr, def->os.dtb) < 0)
+rc = -1;
+
+if (def->os.slic_table &&
+virSecurityDACRestoreFileLabel(mgr, def->os.slic_table) < 0)
+rc = -1;
+
 return rc;
 }
 
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 08/18] security_dac: Remember old labels

2018-12-12 Thread Michal Privoznik
This also requires the same DAC label to be used for shared
paths. If a path is already in use by a domain (or domains) then
and the domain we are starting now wants to access the path it
has to have the same DAC label. This might look too restrictive
as the new label can still guarantee access to already running
domains but in reality it is very unlikely and usually an admin
mistake.

This requirement also simplifies seclabel remembering, because we
can store only one seclabel and have a refcounter for how many
times the path is in use. If we were to allow different labels
and store them in some sort of array the algorithm to match
labels to domains would be needlessly complicated.

Signed-off-by: Michal Privoznik 
---
 src/security/security_dac.c | 63 +++--
 1 file changed, 53 insertions(+), 10 deletions(-)

diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index e5899c1746..3264a2967c 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -29,6 +29,7 @@
 #endif
 
 #include "security_dac.h"
+#include "security_util.h"
 #include "virerror.h"
 #include "virfile.h"
 #include "viralloc.h"
@@ -411,15 +412,26 @@ virSecurityDACGetImageIds(virSecurityLabelDefPtr seclabel,
  *
  * Remember the owner of @path (represented by @uid:@gid).
  *
- * Returns: 0 on success, -1 on failure
+ * Returns: the @path refcount, or
+ *  -1 on failure
  */
 static int
 virSecurityDACRememberLabel(virSecurityDACDataPtr priv ATTRIBUTE_UNUSED,
-const char *path ATTRIBUTE_UNUSED,
-uid_t uid ATTRIBUTE_UNUSED,
-gid_t gid ATTRIBUTE_UNUSED)
+const char *path,
+uid_t uid,
+gid_t gid)
 {
-return 0;
+char *label = NULL;
+int ret = -1;
+
+if (virAsprintf(&label, "+%u:+%u",
+(unsigned int)uid,
+(unsigned int)gid) < 0)
+return -1;
+
+ret = virSecuritySetRememberedLabel(SECURITY_DAC_NAME, path, label);
+VIR_FREE(label);
+return ret;
 }
 
 /**
@@ -439,11 +451,27 @@ virSecurityDACRememberLabel(virSecurityDACDataPtr priv 
ATTRIBUTE_UNUSED,
  */
 static int
 virSecurityDACRecallLabel(virSecurityDACDataPtr priv ATTRIBUTE_UNUSED,
-  const char *path ATTRIBUTE_UNUSED,
-  uid_t *uid ATTRIBUTE_UNUSED,
-  gid_t *gid ATTRIBUTE_UNUSED)
+  const char *path,
+  uid_t *uid,
+  gid_t *gid)
 {
-return 0;
+char *label;
+int ret = -1;
+
+if (virSecurityGetRememberedLabel(SECURITY_DAC_NAME,
+  path, &label) < 0)
+goto cleanup;
+
+if (!label)
+return 1;
+
+if (virParseOwnershipIds(label, uid, gid) < 0)
+goto cleanup;
+
+ret = 0;
+ cleanup:
+VIR_FREE(label);
+return ret;
 }
 
 static virSecurityDriverStatus
@@ -709,6 +737,7 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
 {
 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
 struct stat sb;
+int refcount;
 int rc;
 
 if (!path && src && src->path &&
@@ -729,8 +758,22 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
 return -1;
 }
 
-if (virSecurityDACRememberLabel(priv, path, sb.st_uid, sb.st_gid) < 0)
+refcount = virSecurityDACRememberLabel(priv, path, sb.st_uid, 
sb.st_gid);
+if (refcount < 0) {
 return -1;
+} else if (refcount > 1) {
+/* Refcount is greater than 1 which means that there
+ * is @refcount domains using the @path. Do not
+ * change the label (as it would almost certainly
+ * cause the other domains to lose access to the
+ * @path). */
+if (sb.st_uid != uid || sb.st_gid != gid) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   _("Setting different DAC user or group on %s "
+ "which is already in use"), path);
+return -1;
+}
+}
 }
 
 VIR_INFO("Setting DAC user and group on '%s' to '%ld:%ld'",
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


[libvirt] [PATCH v3 11/18] security_selinux: Remember old labels

2018-12-12 Thread Michal Privoznik
Similarly to what I did in DAC driver, this also requires the
same SELinux label to be used for shared paths. If a path is
already in use by a domain (or domains) then and the domain we
are starting now wants to access the path it has to have the same
SELinux label. This might look too restrictive as the new label
can still guarantee access to already running domains but in
reality it is very unlikely and usually an admin mistake.

Signed-off-by: Michal Privoznik 
---
 src/security/security_selinux.c | 177 +++-
 1 file changed, 130 insertions(+), 47 deletions(-)

diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 715d9a428b..43d2ef32a5 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -33,6 +33,7 @@
 
 #include "security_driver.h"
 #include "security_selinux.h"
+#include "security_util.h"
 #include "virerror.h"
 #include "viralloc.h"
 #include "virlog.h"
@@ -197,14 +198,40 @@ virSecuritySELinuxTransactionAppend(const char *path,
 }
 
 
+static int
+virSecuritySELinuxRememberLabel(const char *path,
+const security_context_t con)
+{
+return virSecuritySetRememberedLabel(SECURITY_SELINUX_NAME,
+ path, con);
+}
+
+
+static int
+virSecuritySELinuxRecallLabel(const char *path,
+  security_context_t *con)
+{
+if (virSecurityGetRememberedLabel(SECURITY_SELINUX_NAME,
+  path, con) < 0)
+return -1;
+
+if (!con)
+return 1;
+
+return 0;
+}
+
+
 static int virSecuritySELinuxSetFileconHelper(const char *path,
   const char *tcon,
   bool optional,
-  bool privileged);
+  bool privileged,
+  bool remember);
 
 
 static int virSecuritySELinuxRestoreFileLabel(virSecurityManagerPtr mgr,
-  const char *path);
+  const char *path,
+  bool recall);
 
 
 /**
@@ -255,10 +282,12 @@ virSecuritySELinuxTransactionRun(pid_t pid 
ATTRIBUTE_UNUSED,
 rv = virSecuritySELinuxSetFileconHelper(item->path,
 item->tcon,
 item->optional,
-privileged);
+privileged,
+list->lock);
 } else {
 rv = virSecuritySELinuxRestoreFileLabel(list->manager,
-item->path);
+item->path,
+list->lock);
 }
 
 if (rv < 0)
@@ -1275,16 +1304,54 @@ virSecuritySELinuxSetFileconImpl(const char *path, 
const char *tcon,
 
 static int
 virSecuritySELinuxSetFileconHelper(const char *path, const char *tcon,
-   bool optional, bool privileged)
+   bool optional, bool privileged, bool 
remember)
 {
+security_context_t econ = NULL;
+int refcount;
 int rc;
+int ret = -1;
 
 if ((rc = virSecuritySELinuxTransactionAppend(path, tcon, optional, 
false)) < 0)
 return -1;
 else if (rc > 0)
 return 0;
 
-return virSecuritySELinuxSetFileconImpl(path, tcon, optional, privileged);
+if (remember) {
+if (getfilecon_raw(path, &econ) < 0 &&
+errno != ENOTSUP && errno != ENODATA) {
+virReportSystemError(errno,
+ _("unable to get SELinux context of %s"),
+ path);
+goto cleanup;
+}
+
+if (econ) {
+refcount = virSecuritySELinuxRememberLabel(path, econ);
+if (refcount < 0) {
+goto cleanup;
+} else if (refcount > 1) {
+/* Refcount is greater than 1 which means that there
+ * is @refcount domains using the @path. Do not
+ * change the label (as it would almost certainly
+ * cause the other domains to lose access to the
+ * @path). */
+if (STRNEQ(econ, tcon)) {
+virReportError(VIR_ERR_OPERATION_INVALID,
+   _("Setting different SELinux label on %s "
+ "which is already in use"), path);
+goto cleanup;
+}
+}
+}
+}
+
+if (virSecuritySELinuxSetFileconImpl(path, tcon, optional, privileged) < 0)
+goto cleanup;

[libvirt] [PATCH v3 09/18] virSecurityDACRestoreImageLabelInt: Restore even shared/RO disks

2018-12-12 Thread Michal Privoznik
Now that we have seclabel remembering we can safely restore
labels for shared and RO disks. In fact we need to do that to
keep seclabel refcount stored in XATTRs in sync with reality.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_dac.c | 8 
 1 file changed, 8 deletions(-)

diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 3264a2967c..533d990de1 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -932,14 +932,6 @@ virSecurityDACRestoreImageLabelInt(virSecurityManagerPtr 
mgr,
 if (!priv->dynamicOwnership)
 return 0;
 
-/* Don't restore labels on readoly/shared disks, because other VMs may
- * still be accessing these. Alternatively we could iterate over all
- * running domains and try to figure out if it is in use, but this would
- * not work for clustered filesystems, since we can't see running VMs using
- * the file on other nodes. Safest bet is thus to skip the restore step. */
-if (src->readonly || src->shared)
-return 0;
-
 secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
 if (secdef && !secdef->relabel)
 return 0;
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 12/18] security_selinux: Restore label on failed setfilecon() attempt

2018-12-12 Thread Michal Privoznik
It's important to keep XATTRs untouched (well, in the same state
they were in when entering the function). Otherwise our
refcounting would be messed up.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_selinux.c | 40 +++--
 1 file changed, 28 insertions(+), 12 deletions(-)

diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 43d2ef32a5..f52c88259d 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -222,10 +222,10 @@ virSecuritySELinuxRecallLabel(const char *path,
 }
 
 
-static int virSecuritySELinuxSetFileconHelper(const char *path,
+static int virSecuritySELinuxSetFileconHelper(virSecurityManagerPtr mgr,
+  const char *path,
   const char *tcon,
   bool optional,
-  bool privileged,
   bool remember);
 
 
@@ -252,7 +252,6 @@ virSecuritySELinuxTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
 {
 virSecuritySELinuxContextListPtr list = opaque;
 virSecurityManagerMetadataLockStatePtr state;
-bool privileged = virSecurityManagerGetPrivileged(list->manager);
 const char **paths = NULL;
 size_t npaths = 0;
 size_t i;
@@ -279,10 +278,10 @@ virSecuritySELinuxTransactionRun(pid_t pid 
ATTRIBUTE_UNUSED,
 
 /* TODO Implement rollback */
 if (!item->restore) {
-rv = virSecuritySELinuxSetFileconHelper(item->path,
+rv = virSecuritySELinuxSetFileconHelper(list->manager,
+item->path,
 item->tcon,
 item->optional,
-privileged,
 list->lock);
 } else {
 rv = virSecuritySELinuxRestoreFileLabel(list->manager,
@@ -1303,9 +1302,13 @@ virSecuritySELinuxSetFileconImpl(const char *path, const 
char *tcon,
 
 
 static int
-virSecuritySELinuxSetFileconHelper(const char *path, const char *tcon,
-   bool optional, bool privileged, bool 
remember)
+virSecuritySELinuxSetFileconHelper(virSecurityManagerPtr mgr,
+   const char *path,
+   const char *tcon,
+   bool optional,
+   bool remember)
 {
+bool privileged = virSecurityManagerGetPrivileged(mgr);
 security_context_t econ = NULL;
 int refcount;
 int rc;
@@ -1345,8 +1348,23 @@ virSecuritySELinuxSetFileconHelper(const char *path, 
const char *tcon,
 }
 }
 
-if (virSecuritySELinuxSetFileconImpl(path, tcon, optional, privileged) < 0)
+if (virSecuritySELinuxSetFileconImpl(path, tcon, optional, privileged) < 
0) {
+virErrorPtr origerr;
+
+virErrorPreserveLast(&origerr);
+/* Try to restore the label. This is done so that XATTRs
+ * are left in the same state as when the control entered
+ * this function. However, if our attempt fails, there's
+ * not much we can do. XATTRs refcounting is fubar'ed and
+ * the only option we have is warn users. */
+if (virSecuritySELinuxRestoreFileLabel(mgr, path, remember) < 0)
+VIR_WARN("Unable to restore label on '%s'. "
+ "XATTRs might have been left in inconsistent state.",
+ path);
+
+virErrorRestore(&origerr);
 goto cleanup;
+}
 
 ret = 0;
  cleanup:
@@ -1359,16 +1377,14 @@ static int
 virSecuritySELinuxSetFileconOptional(virSecurityManagerPtr mgr,
  const char *path, const char *tcon)
 {
-bool privileged = virSecurityManagerGetPrivileged(mgr);
-return virSecuritySELinuxSetFileconHelper(path, tcon, true, privileged, 
false);
+return virSecuritySELinuxSetFileconHelper(mgr, path, tcon, true, false);
 }
 
 static int
 virSecuritySELinuxSetFilecon(virSecurityManagerPtr mgr,
  const char *path, const char *tcon)
 {
-bool privileged = virSecurityManagerGetPrivileged(mgr);
-return virSecuritySELinuxSetFileconHelper(path, tcon, false, privileged, 
false);
+return virSecuritySELinuxSetFileconHelper(mgr, path, tcon, false, false);
 }
 
 static int
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 02/18] security: Include security_util

2018-12-12 Thread Michal Privoznik
This file implements wrappers over XATTR getter/setter. It
ensures the proper XATTR namespace is used.

Signed-off-by: Michal Privoznik 
---
 src/security/Makefile.inc.am |   2 +
 src/security/security_util.c | 256 +++
 src/security/security_util.h |  32 +
 3 files changed, 290 insertions(+)
 create mode 100644 src/security/security_util.c
 create mode 100644 src/security/security_util.h

diff --git a/src/security/Makefile.inc.am b/src/security/Makefile.inc.am
index f88b82df7b..0ade97d355 100644
--- a/src/security/Makefile.inc.am
+++ b/src/security/Makefile.inc.am
@@ -14,6 +14,8 @@ SECURITY_DRIVER_SOURCES = \
security/security_dac.c \
security/security_manager.h \
security/security_manager.c \
+   security/security_util.h \
+   security/security_util.c \
$(NULL)
 
 SECURITY_DRIVER_SELINUX_SOURCES = \
diff --git a/src/security/security_util.c b/src/security/security_util.c
new file mode 100644
index 00..194343c407
--- /dev/null
+++ b/src/security/security_util.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * .
+ */
+
+#include 
+
+#include "viralloc.h"
+#include "virfile.h"
+#include "virstring.h"
+#include "virerror.h"
+
+#include "security_util.h"
+
+#define VIR_FROM_THIS VIR_FROM_SECURITY
+
+/* There are four namespaces available on Linux (xattr(7)):
+ *
+ *  user - can be modified by anybody,
+ *  system - used by ACLs
+ *  security - used by SELinux
+ *  trusted - accessibly by CAP_SYS_ADMIN processes only
+ *
+ * Looks like the last one is way to go.
+ * Unfortunately, FreeBSD only supports:
+ *
+ *  user - can be modified by anybody,
+ *  system - accessible by CAP_SYS_ADMIN processes only
+ *
+ * Note that 'system' on FreeBSD corresponds to 'trusted' on
+ * Linux. So far the only point where FreeBSD and Linux can meet
+ * is NFS which still doesn't support XATTRs. Therefore we can
+ * use different namespace on each system. If NFS gains support
+ * for XATTRs then we have to find a way to deal with the
+ * different namespaces. But that is a problem for future me.
+ */
+#if defined(__linux__)
+# define XATTR_NAMESPACE "trusted"
+#elif defined(__FreeBSD__)
+# define XATTR_NAMESPACE "system"
+#endif
+
+static char *
+virSecurityGetAttrName(const char *name ATTRIBUTE_UNUSED)
+{
+char *ret = NULL;
+#ifdef XATTR_NAMESPACE
+ignore_value(virAsprintf(&ret, XATTR_NAMESPACE".libvirt.security.%s", 
name));
+#else
+errno = ENOSYS;
+virReportSystemError(errno, "%s",
+ _("Extended attributes are not supported on this 
system"));
+#endif
+return ret;
+}
+
+
+static char *
+virSecurityGetRefCountAttrName(const char *name ATTRIBUTE_UNUSED)
+{
+char *ret = NULL;
+#ifdef XATTR_NAMESPACE
+ignore_value(virAsprintf(&ret, XATTR_NAMESPACE".libvirt.security.ref_%s", 
name));
+#else
+errno = ENOSYS;
+virReportSystemError(errno, "%s",
+ _("Extended attributes are not supported on this 
system"));
+#endif
+return ret;
+}
+
+
+/**
+ * virSecurityGetRememberedLabel:
+ * @name: security driver name
+ * @path: file name
+ * @label: label
+ *
+ * For given @path and security driver (@name) fetch remembered
+ * @label. The caller must not restore label if an error is
+ * indicated or if @label is NULL upon return.
+ *
+ * The idea is that the first time
+ * virSecuritySetRememberedLabel() is called over @path the
+ * @label is recorded and refcounter is set to 1. Each subsequent
+ * call to virSecuritySetRememberedLabel() increases the counter.
+ * Counterpart to this is virSecurityGetRememberedLabel() which
+ * decreases the counter and reads the @label only if the counter
+ * reached value of zero. For any other call (i.e. when the
+ * counter is not zero), virSecurityGetRememberedLabel() set
+ * @label to NULL (to notify the caller that the refcount is not
+ * zero) and returns zero.
+ *
+ * Returns: 0 on success,
+ * -1 otherwise (with error reported)
+ */
+int
+virSecurityGetRememberedLabel(const char *name,
+  const char *path,
+  char **label)
+{
+char *ref_name = NULL;
+char *attr_name = NULL;
+char *value = NULL;
+unsigned int refcount = 0;
+int ret = -1;
+
+*label = NULL;
+
+if 

[libvirt] [PATCH v3 03/18] security_dac: Restore label on failed chown() attempt

2018-12-12 Thread Michal Privoznik
It's important to keep XATTRs untouched (well, in the same state
they were in when entering the function). Otherwise our
refcounting would be messed up.

Signed-off-by: Michal Privoznik 
Reviewed-by: Daniel P. Berrangé 
---
 src/security/security_dac.c | 20 +++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 4bdc6ed213..f01d0b4732 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -718,7 +718,25 @@ virSecurityDACSetOwnership(virSecurityManagerPtr mgr,
 VIR_INFO("Setting DAC user and group on '%s' to '%ld:%ld'",
  NULLSTR(src ? src->path : path), (long)uid, (long)gid);
 
-return virSecurityDACSetOwnershipInternal(priv, src, path, uid, gid);
+if (virSecurityDACSetOwnershipInternal(priv, src, path, uid, gid) < 0) {
+virErrorPtr origerr;
+
+virErrorPreserveLast(&origerr);
+/* Try to restore the label. This is done so that XATTRs
+ * are left in the same state as when the control entered
+ * this function. However, if our attempt fails, there's
+ * not much we can do. XATTRs refcounting is fubar'ed and
+ * the only option we have is warn users. */
+if (virSecurityDACRestoreFileLabelInternal(mgr, src, path) < 0)
+VIR_WARN("Unable to restore label on '%s'. "
+ "XATTRs might have been left in inconsistent state.",
+ NULLSTR(src ? src->path : path));
+
+virErrorRestore(&origerr);
+return -1;
+}
+
+return 0;
 }
 
 
-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH v3 00/18] Implement original label remembering

2018-12-12 Thread Michal Privoznik
v3 of:

https://www.redhat.com/archives/libvir-list/2018-November/msg01070.html

diff to v2:
- dropped 01/18 from v2
- Introduced a test
- Couple of minor adjustments as suggested in review of v2

Michal Prívozník (18):
  util: Introduce xattr getter/setter/remover
  security: Include security_util
  security_dac: Restore label on failed chown() attempt
  virSecurityDACTransactionRun: Implement rollback
  virSecurityDACRestoreAllLabel: Reorder device relabeling
  virSecurityDACRestoreAllLabel: Restore more labels
  security_dac: Allow callers to enable/disable label remembering/recall
  security_dac: Remember old labels
  virSecurityDACRestoreImageLabelInt: Restore even shared/RO disks
  security_selinux: Track if transaction is restore
  security_selinux: Remember old labels
  security_selinux: Restore label on failed setfilecon() attempt
  virSecuritySELinuxTransactionRun: Implement rollback
  virSecuritySELinuxRestoreAllLabel: Reorder device relabeling
  virSecuritySELinuxRestoreAllLabel: Restore more labels
  tests: Introduce qemusecuritytest
  tools: Provide a script to recover fubar'ed XATTRs setup
  qemu.conf: Allow users to enable/disable label remembering

 cfg.mk |   4 +-
 src/libvirt_private.syms   |   3 +
 src/qemu/libvirtd_qemu.aug |   1 +
 src/qemu/qemu.conf |   4 +
 src/qemu/qemu_conf.c   |   4 +
 src/qemu/test_libvirtd_qemu.aug.in |   1 +
 src/security/Makefile.inc.am   |   2 +
 src/security/security_dac.c| 227 ++
 src/security/security_selinux.c| 272 
 src/security/security_util.c   | 256 +++
 src/security/security_util.h   |  32 ++
 src/util/virfile.c | 121 
 src/util/virfile.h |  20 +-
 tests/Makefile.am  |  10 +
 tests/qemusecuritymock.c   | 480 +
 tests/qemusecuritytest.c   | 173 +++
 tests/qemusecuritytest.h   |  28 ++
 tools/Makefile.am  |   1 +
 tools/libvirt_recover_xattrs.sh|  96 ++
 19 files changed, 1600 insertions(+), 135 deletions(-)
 create mode 100644 src/security/security_util.c
 create mode 100644 src/security/security_util.h
 create mode 100644 tests/qemusecuritymock.c
 create mode 100644 tests/qemusecuritytest.c
 create mode 100644 tests/qemusecuritytest.h
 create mode 100755 tools/libvirt_recover_xattrs.sh

-- 
2.19.2

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH 2/4] conf: domain: Introduce virDomainDeviceInfoIterate flags

2018-12-12 Thread John Ferlan



On 12/12/18 3:29 AM, Erik Skultety wrote:
> On Tue, Dec 11, 2018 at 06:50:19PM -0500, John Ferlan wrote:
>>
>>
>> On 12/7/18 9:47 AM, Erik Skultety wrote:
>>> One of the usages of the device iterator is to run config validation.
>>> That's a problem for graphics devices, because they don't have any @info
>>> data (graphics shouldn't have been considered as devices in the first
>>> place), and simply passing NULL would crash a few callbacks invoked from
>>> the iterator. Fix this problem by introducing iterator flags.
>>
>> Somewhat confusing commit message or I'm just being dense, your choice.
> 
> I see, especially the mention of graphics devices in a patch where there's
> nothing related, how about this:
> 
> Validation of domain devices is accomplished via a generic device iterator
> which takes a callback, iterates over all kinds of supported device types and
> invokes the callback on every single device. However, there might be cases 
> when
> we need to alter the behaviour of the iteration (most notably skip or include 
> a
> group of devices). Therefore, this patch introduces iterator flags.
> 

That's fine.

> 
>>
>> Although I think that @info data for graphics devices could be moved
>> into patch4 since that's where it makes more sense (eventually at least).
>>
>>>
>>> Signed-off-by: Erik Skultety 
>>> ---
>>>  src/conf/domain_conf.c | 27 ---
>>>  1 file changed, 20 insertions(+), 7 deletions(-)
 diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
>>> index b70dca6c61..11552bff5b 100644
>>> --- a/src/conf/domain_conf.c
>>> +++ b/src/conf/domain_conf.c
>>> @@ -3703,10 +3703,18 @@ virDomainSkipBackcompatConsole(virDomainDefPtr def,
>>>  }
>>>
>>>
>>> +typedef enum {
>>> +DEVICE_INFO_ITERATE_ALL_CONSOLES = 1 << 0, /* Iterate console[0] */
>>> +} virDomainDeviceInfoIterateFlags;
>>> +
>>
>> Logic seems right vis-a-vis replacing a bool with a flag properly. I
>> don't get the name and comment, but I'm not sure I could name it better.
> 
> The iterator function itself doesn't have a perfect name, I was just trying to
> use that name to derive a new one to reflect the relation, but I can use
> virDomainDeviceIteratorFlags instead. Going one step further we might even 
> want
> to rename the iterator and drop the "Info" part since that won't be 100% once 
> I
> enable it for graphics.
> 

 I meant just the flag name itself - the typedef name is just
that and used only once, so no big deal.

>> The called function with the @all flag only processes when @all == false
> 
> So, because console[0] corresponds to the first serial console, we often
> special-case these (in general). The @all flag here just says whether the
> processing callback should skip console[0] or not, if @all == false, then
> virDomainSkipBackcompatConsole will return true, thus skipping invocation of
> the callback on this device.

Yeah I recall the [0] console entry being quite special with the details
being found in various places in the code.

In any case, if @all == false, then true is only returned if other
conditions are met too such as using/checking the [0]th entry of the
consoles list. When @all == true, then false is returned and that's the
"more normal" case as prior to this patch @all was true for all except
when virDomainDeviceInfoIterate calls virDomainDeviceInfoIterateInternal


> 
>> as I'm reading things. Anyway, if someone has a better idea, then they
>> should speak up before you push!
> 
> Let me know whether the suggested update to the commit message along with the
> changes to naming are okay and I'll proceed with merging the patch.

Sure things are fine

John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCH 4/4] conf: domain: gfx: Iterate over graphics devices when doing validation

2018-12-12 Thread Erik Skultety
On Tue, Dec 11, 2018 at 06:54:31PM -0500, John Ferlan wrote:
>
>
> On 12/7/18 9:47 AM, Erik Skultety wrote:
> > The validation code for graphics has been in place for a while, but
> > because it is only executed from the device iterator, that validation
> > code was never truly run. The unfortunate side effect of this whole mess
>
> dang confusing postparse and validation processing...  when you say
> "device iterator" you meant the hypervisor specific device iterator,
> right?  That is, what's called by deviceValidateCallback or the call
> into qemuDomainDeviceDefValidateGraphics. I'm just trying to follow the
> wording, nothing more, nothing less.

By iterator I mean virDomainDeviceInfoIterateInternal.

>
> > was that a few capabilities were missing from the test suite, which in
> > turn meant that a few graphics test which expected a failure happily
>
> graphics tests (the s on test)
>
> > accepted whatever failure the parser returned which made them succeed
> > even though in reality we allowed to start a domain with multiple
> > OpenGL-enabled graphics devices.
>
> add blank line between paragraphs
>
> > This patch enables iteration over graphics devices. Unsurprisingly,
> > a few tests started failing as a result, so fix those too.
> >
> > Signed-off-by: Erik Skultety 
> > ---
> >  src/conf/domain_conf.c   | 13 -
> >  tests/qemuxml2argvtest.c |  7 ++-
> >  tests/qemuxml2xmltest.c  | 10 +++---
> >  3 files changed, 21 insertions(+), 9 deletions(-)
> >
> > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> > index 11552bff5b..a4c762a210 100644
> > --- a/src/conf/domain_conf.c
> > +++ b/src/conf/domain_conf.c
> > @@ -3705,6 +3705,7 @@ virDomainSkipBackcompatConsole(virDomainDefPtr def,
> >
> >  typedef enum {
> >  DEVICE_INFO_ITERATE_ALL_CONSOLES = 1 << 0, /* Iterate console[0] */
> > +DEVICE_INFO_ITERATE_GRAPHICS = 1 << 1 /* Iterate graphics */
> >  } virDomainDeviceInfoIterateFlags;
> >
> >  /*
> > @@ -3870,6 +3871,15 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr 
> > def,
> >  return rc;
> >  }
> >
> > +if (iteratorFlags & DEVICE_INFO_ITERATE_GRAPHICS) {
> > +device.type = VIR_DOMAIN_DEVICE_GRAPHICS;
> > +for (i = 0; i < def->ngraphics; i++) {
> > +device.data.graphics = def->graphics[i];
> > +if ((rc = cb(def, &device, NULL, opaque)) != 0)
>
> So the only caller to this passes cb=virDomainDefValidateDeviceIterator
> which ironically doesn't use @info (e.g. the 3rd param):
>
> virDomainDefValidateDeviceIterator(virDomainDefPtr def,
>virDomainDeviceDefPtr dev,
>virDomainDeviceInfoPtr info
> ATTRIBUTE_UNUSED,
>void *opaque)

Looking at the function signature, it might be worth doing a bit of a refactor
on the iterator, since @info is treated as unused in a few cases, I'll try
looking into that as a follow-up.


>
> I know these are generic functions, but some day if someone changes that
> helper to "use" @info can I assume that some test would fail in a most
> spectacular way?

It most certainly will.

>
> Not a problem here, just looking to confirm my own feeling on this with
> what you'd expect.  You may want to even add a comment noting that for a
> graphics device the @info isn't used (remember my patch2 comment), so
> one has to be careful which callers can set the iterate flag that dumps
> you here.  Say nothing for the called function - if it expects something
> and gets NULL, all bets are off. I can assume it wouldn't be picked up
> by the compiler's ATTRIBUTE_NONNULL too unless the prototype for the @cb
> was set to have that.
>
> > +return rc;
> > +}
> > +}
> > +
> >  /* Coverity is not very happy with this - all dead_error_condition */
> >  #if !STATIC_ANALYSIS
> >  /* This switch statement is here to trigger compiler warning when 
> > adding
> > @@ -6348,7 +6358,8 @@ virDomainDefValidate(virDomainDefPtr def,
> >  /* iterate the devices */
> >  if (virDomainDeviceInfoIterateInternal(def,
> > 
> > virDomainDefValidateDeviceIterator,
> > -   
> > DEVICE_INFO_ITERATE_ALL_CONSOLES,
> > +   
> > (DEVICE_INFO_ITERATE_ALL_CONSOLES |
> > +DEVICE_INFO_ITERATE_GRAPHICS),
> > &data) < 0)
> >  return -1;
> >
> > diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
> > index 528139654c..05451863ad 100644
> > --- a/tests/qemuxml2argvtest.c
> > +++ b/tests/qemuxml2argvtest.c
> > @@ -1299,7 +1299,7 @@ mymain(void)
> >
> >  DO_TEST("graphics-sdl",
> >  QEMU_CAPS_DEVICE_VGA);
> > -DO_TEST_FAILURE("graphics-sdl-egl-headless", NONE);
> > +DO_TEST_PARSE_ERROR_CAPS_LATEST("graphics-sdl-egl-headless");
>
> W

  1   2   >