Devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- 12 participants
- 40091 discussions
The access, modify and change times are added to volumes and
corresponding xml representations.
---
docs/schemas/storagevol.rng | 17 +++++++++++++++++
src/conf/storage_conf.c | 9 +++++++++
src/conf/storage_conf.h | 9 +++++++++
src/storage/storage_backend.c | 4 ++++
4 files changed, 39 insertions(+)
diff --git a/docs/schemas/storagevol.rng b/docs/schemas/storagevol.rng
index 7a74331..fc7eb09 100644
--- a/docs/schemas/storagevol.rng
+++ b/docs/schemas/storagevol.rng
@@ -63,6 +63,22 @@
</optional>
</define>
+ <define name='timestamps'>
+ <optional>
+ <element name='timestamps'>
+ <element name='atime'>
+ <ref name='unsignedLong'/>
+ </element>
+ <element name='mtime'>
+ <ref name='unsignedLong'/>
+ </element>
+ <element name='ctime'>
+ <ref name='unsignedLong'/>
+ </element>
+ </element>
+ </optional>
+ </define>
+
<define name='target'>
<element name='target'>
<optional>
@@ -72,6 +88,7 @@
</optional>
<ref name='format'/>
<ref name='permissions'/>
+ <ref name='timestamps'/>
<optional>
<ref name='encryption'/>
</optional>
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index ab8df9e..a4cdac8 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -1272,6 +1272,15 @@ virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
virBufferAddLit(buf," </permissions>\n");
+ virBufferAddLit(buf," <timestamps>\n");
+ virBufferAsprintf(buf," <atime>%llu</atime>\n",
+ (unsigned long long) def->timestamps.atime);
+ virBufferAsprintf(buf," <mtime>%llu</mtime>\n",
+ (unsigned long long) def->timestamps.mtime);
+ virBufferAsprintf(buf," <ctime>%llu</ctime>\n",
+ (unsigned long long) def->timestamps.ctime);
+ virBufferAddLit(buf," </timestamps>\n");
+
if (def->encryption) {
virBufferAdjustIndent(buf, 4);
if (virStorageEncryptionFormat(buf, def->encryption) < 0)
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index 5733b57..8cd1d63 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -46,6 +46,14 @@ struct _virStoragePerms {
/* Storage volumes */
+typedef struct _virStorageTimestamps virStorageTimestamps;
+typedef virStorageTimestamps *virStorageTimestampsPtr;
+struct _virStorageTimestamps {
+ time_t atime;
+ time_t mtime;
+ time_t ctime;
+};
+
/*
* How the volume's data is stored on underlying
@@ -77,6 +85,7 @@ struct _virStorageVolTarget {
char *path;
int format;
virStoragePerms perms;
+ virStorageTimestamps timestamps;
int type; /* only used by disk backend for partition type */
/* Currently used only in virStorageVolDef.target, not in .backingstore. */
virStorageEncryptionPtr encryption;
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index e2e9b51..c827e3c 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -1209,6 +1209,10 @@ virStorageBackendUpdateVolTargetInfoFD(virStorageVolTargetPtr target,
target->perms.uid = sb.st_uid;
target->perms.gid = sb.st_gid;
+ target->timestamps.atime = sb.st_atime;
+ target->timestamps.mtime = sb.st_mtime;
+ target->timestamps.ctime = sb.st_ctime;
+
VIR_FREE(target->perms.label);
#if HAVE_SELINUX
--
1.7.9.5
2
22
[libvirt] [PATCH v2] qemu: Allow to attach/detach controller device persistently
by Osier Yang 03 Aug '12
by Osier Yang 03 Aug '12
03 Aug '12
* src/conf/domain_conf.c:
- Add virDomainControllerFind to find controller device by type
and index.
- Add virDomainControllerRemove to remove the controller device
from maintained controler list.
* src/conf/domain_conf.h:
- Declare the two new helpers.
* src/libvirt_private.syms:
- Expose private symbols for the two new helpers.
* src/qemu/qemu_driver.c:
- Support attach/detach controller device persistently
* src/qemu/qemu_hotplug.c:
- Use the two helpers to simplify the codes.
v1 - v2:
- Allow to detach the controller too.
---
src/conf/domain_conf.c | 37 ++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 3 +-
src/libvirt_private.syms | 2 +
src/qemu/qemu_driver.c | 35 ++++++++++++++++++++++++++++++++-
src/qemu/qemu_hotplug.c | 47 ++++++++++++---------------------------------
5 files changed, 87 insertions(+), 37 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 41726ff..a7ae604 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -7554,6 +7554,43 @@ void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
def->ncontrollers++;
}
+int
+virDomainControllerFind(virDomainDefPtr def,
+ int type, int idx)
+{
+ int i;
+
+ for (i = 0 ; i < def->ncontrollers ; i++) {
+ if ((def->controllers[i]->type == type) &&
+ (def->controllers[i]->idx == idx)) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+virDomainControllerDefPtr
+virDomainControllerRemove(virDomainDefPtr def, size_t i)
+{
+ virDomainControllerDefPtr controller = def->controllers[i];
+
+ if (def->ncontrollers > 1) {
+ memmove(def->controllers + i,
+ def->controllers + i + 1,
+ sizeof(*def->controllers) *
+ (def->ncontrollers - (i + 1)));
+ def->ncontrollers--;
+ if (VIR_REALLOC_N(def->controllers, def->ncontrollers) < 0) {
+ /* ignore, harmless */
+ }
+ } else {
+ VIR_FREE(def->controllers);
+ def->ncontrollers = 0;
+ }
+
+ return controller;
+}
int virDomainLeaseIndex(virDomainDefPtr def,
virDomainLeaseDefPtr lease)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 469d3b6..b102a43 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2043,7 +2043,8 @@ int virDomainControllerInsert(virDomainDefPtr def,
virDomainControllerDefPtr controller);
void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
virDomainControllerDefPtr controller);
-
+int virDomainControllerFind(virDomainDefPtr def, int type, int idx);
+virDomainControllerDefPtr virDomainControllerRemove(virDomainDefPtr def, size_t i);
int virDomainLeaseIndex(virDomainDefPtr def,
virDomainLeaseDefPtr lease);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 734c881..9f14077 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -266,12 +266,14 @@ virDomainClockOffsetTypeFromString;
virDomainClockOffsetTypeToString;
virDomainConfigFile;
virDomainControllerDefFree;
+virDomainControllerFind;
virDomainControllerInsert;
virDomainControllerInsertPreAlloced;
virDomainControllerModelSCSITypeFromString;
virDomainControllerModelSCSITypeToString;
virDomainControllerModelUSBTypeFromString;
virDomainControllerModelUSBTypeToString;
+virDomainControllerRemove;
virDomainControllerTypeToString;
virDomainCpuPlacementModeTypeFromString;
virDomainCpuPlacementModeTypeToString;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6cf3882..2d9c3a9 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5535,6 +5535,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
virDomainNetDefPtr net;
virDomainHostdevDefPtr hostdev;
virDomainLeaseDefPtr lease;
+ virDomainControllerDefPtr controller;
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
@@ -5607,6 +5608,23 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
dev->data.lease = NULL;
break;
+ case VIR_DOMAIN_DEVICE_CONTROLLER:
+ controller = dev->data.controller;
+ if (virDomainControllerFind(vmdef, controller->type,
+ controller->idx) > 0) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Target already exists"));
+ return -1;
+ }
+
+ if (virDomainControllerInsert(vmdef, controller) < 0)
+ return -1;
+ dev->data.controller = NULL;
+
+ if (qemuDomainAssignAddresses(vmdef, NULL, NULL) < 0)
+ return -1;
+ break;
+
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("persistent attach of device is not supported"));
@@ -5624,6 +5642,8 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
virDomainNetDefPtr net, det_net;
virDomainHostdevDefPtr hostdev, det_hostdev;
virDomainLeaseDefPtr lease, det_lease;
+ virDomainControllerDefPtr cont, det_cont;
+ int idx;
switch (dev->type) {
case VIR_DOMAIN_DEVICE_DISK:
@@ -5650,8 +5670,6 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
break;
case VIR_DOMAIN_DEVICE_HOSTDEV: {
- int idx;
-
hostdev = dev->data.hostdev;
if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
@@ -5674,6 +5692,19 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
virDomainLeaseDefFree(det_lease);
break;
+ case VIR_DOMAIN_DEVICE_CONTROLLER:
+ cont = dev->data.controller;
+ if ((idx = virDomainControllerFind(vmdef, cont->type,
+ cont->idx)) < 0) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("device not present in domain configuration"));
+ return -1;
+ }
+ det_cont = virDomainControllerRemove(vmdef, idx);
+ virDomainControllerDefFree(det_cont);
+
+ break;
+
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("persistent detach of device is not supported"));
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 7880606..c3ac938 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -308,21 +308,17 @@ int qemuDomainAttachPciControllerDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainControllerDefPtr controller)
{
- int i;
int ret = -1;
const char* type = virDomainControllerTypeToString(controller->type);
char *devstr = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
bool releaseaddr = false;
- for (i = 0 ; i < vm->def->ncontrollers ; i++) {
- if ((vm->def->controllers[i]->type == controller->type) &&
- (vm->def->controllers[i]->idx == controller->idx)) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("target %s:%d already exists"),
- type, controller->idx);
- return -1;
- }
+ if (virDomainControllerFind(vm->def, controller->type, controller->idx) > 0) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("target %s:%d already exists"),
+ type, controller->idx);
+ return -1;
}
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
@@ -1874,19 +1870,13 @@ int qemuDomainDetachPciControllerDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev)
{
- int i, ret = -1;
+ int idx, ret = -1;
virDomainControllerDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
- for (i = 0 ; i < vm->def->ncontrollers ; i++) {
- if ((vm->def->controllers[i]->type == dev->data.controller->type) &&
- (vm->def->controllers[i]->idx == dev->data.controller->idx)) {
- detach = vm->def->controllers[i];
- break;
- }
- }
-
- if (!detach) {
+ if ((idx = virDomainControllerFind(vm->def,
+ dev->data.controller->type,
+ dev->data.controller->idx)) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("disk controller %s:%d not found"),
virDomainControllerTypeToString(dev->data.controller->type),
@@ -1894,6 +1884,8 @@ int qemuDomainDetachPciControllerDevice(struct qemud_driver *driver,
goto cleanup;
}
+ detach = vm->def->controllers[idx];
+
if (!virDomainDeviceAddressIsValid(&detach->info,
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
@@ -1934,27 +1926,14 @@ int qemuDomainDetachPciControllerDevice(struct qemud_driver *driver,
}
qemuDomainObjExitMonitorWithDriver(driver, vm);
- if (vm->def->ncontrollers > 1) {
- memmove(vm->def->controllers + i,
- vm->def->controllers + i + 1,
- sizeof(*vm->def->controllers) *
- (vm->def->ncontrollers - (i + 1)));
- vm->def->ncontrollers--;
- if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers) < 0) {
- /* ignore, harmless */
- }
- } else {
- VIR_FREE(vm->def->controllers);
- vm->def->ncontrollers = 0;
- }
+ virDomainControllerRemove(vm->def, idx);
+ virDomainControllerDefFree(detach);
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
detach->info.addr.pci.slot) < 0)
VIR_WARN("Unable to release PCI address on controller");
- virDomainControllerDefFree(detach);
-
ret = 0;
cleanup:
--
1.7.7.3
2
3
Add test for memory/maxmem set and get on domain running/shutdown
---
scripts/domain/310-memory-set-get.t | 98 +++++++++++++++++++++++++++++++++++
1 files changed, 98 insertions(+), 0 deletions(-)
create mode 100644 scripts/domain/310-memory-set-get.t
diff --git a/scripts/domain/310-memory-set-get.t b/scripts/domain/310-memory-set-get.t
new file mode 100644
index 0000000..71886a6
--- /dev/null
+++ b/scripts/domain/310-memory-set-get.t
@@ -0,0 +1,98 @@
+# -*- perl -*-
+#
+# Copyright (C) 2012-2013 Red Hat, Inc.
+# Copyright (C) 2012-2013 Kyla Zhang <weizhan(a)redhat.com>
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+domain/310-memory-set-get.t: test set and get memory/max memory
+
+=head1 DESCRIPTION
+
+The test case validates that the set memory, set max memory and get
+max memory works well for domain.
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 15;
+
+use Sys::Virt::TCK;
+use Sys::Virt::TCK::NetworkHelpers;
+use Test::Exception;
+use File::Spec::Functions qw(catfile catdir rootdir);
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END { $tck->cleanup if $tck; }
+
+diag "Define a new real domain, default memory is 1048576";
+my $dom_name ="tck310memtest";
+
+my $dom = prepare_test_disk_and_vm($tck, $conn, $dom_name);
+
+diag "Set max memory for domain";
+lives_ok(sub { $dom->set_max_memory("1572864") }, "Set max memory succeed");
+
+diag "Get max memory for domain when domain is inactive";
+is($dom->get_max_memory(), 1572864, "Get max memory is same as set value 1572864");
+
+diag "Start inactive domain";
+$dom->create;
+ok($dom->get_id() > 0, "running domain has an ID > 0");
+sleep(30);
+
+diag "Set memory for current state";
+lives_ok(sub { $dom->set_memory("924288", Sys::Virt::Domain::MEM_CONFIG) }, "Set memory succeed in persistent config");
+
+diag "get memory of running domain";
+is($dom->get_info()->{memory}, 1048576, "Get current memory is 1048576");
+
+diag "Get max memory for domain when domain is active";
+is($dom->get_max_memory(), 1572864, "Get max memory is same as set value 1572864");
+
+diag "Set memory for current state";
+lives_ok(sub { $dom->set_memory("724288", Sys::Virt::Domain::MEM_CURRENT) }, "Set memory succeed in current state");
+sleep(3);
+
+diag "Check memory of running domain";
+is($dom->get_info()->{memory}, 724288, "Get current memory is same as set value 724288");
+
+diag "Set memory for live state";
+lives_ok(sub { $dom->set_memory("824288", Sys::Virt::Domain::MEM_LIVE) }, "Set memory succeed in live state");
+sleep(3);
+
+diag "Check memory of running domain";
+is($dom->get_info()->{memory}, 824288, "Get current memory is same as set value 824288");
+
+diag "Try setting max memory when domain is running";
+ok_error(sub { $dom->set_max_memory("1048576") }, "not allowed to set max memory when domain is running");
+
+diag "Destroying the transient domain";
+$dom->destroy;
+
+diag "Check memory of shutdown domain";
+is($dom->get_info()->{memory}, 924288, "Get memory is 624288 when domain is shutdown");
+
+diag "Set max memory with set_memory";
+lives_ok(sub { $dom->set_memory("1148576", Sys::Virt::Domain::MEM_MAXIMUM) }, "Set max memory succeed with set_memory");
+
+diag "Get max memory for domain";
+is($dom->get_info()->{maxMem}, 1148576, "Get max memory is same as set value 1148576");
+
+diag "Try setting live state memory when domain is shutdown";
+ok_error(sub { $dom->set_memory("824288", Sys::Virt::Domain::MEM_LIVE) }, "not allowed to set live state memory when domain is shutdown");
--
1.7.1
3
2
03 Aug '12
capability.rng: Guest features can be in any order.
nodedev.rng: Added <driver> element, <capability> phys_function and
virt_functions for PCI devices.
storagepool.rng: Owner or group ID can be -1.
---
docs/schemas/capability.rng | 76 +++++++++++++++++++++--------------------
docs/schemas/nodedev.rng | 37 ++++++++++++++++++++
docs/schemas/storagepool.rng | 4 +-
3 files changed, 78 insertions(+), 39 deletions(-)
diff --git a/docs/schemas/capability.rng b/docs/schemas/capability.rng
index 06ff685..c392e44 100644
--- a/docs/schemas/capability.rng
+++ b/docs/schemas/capability.rng
@@ -296,43 +296,45 @@
<define name='features'>
<element name='features'>
- <optional>
- <element name='pae'>
- <empty/>
- </element>
- </optional>
- <optional>
- <element name='nonpae'>
- <empty/>
- </element>
- </optional>
- <optional>
- <element name='ia64_be'>
- <empty/>
- </element>
- </optional>
- <optional>
- <element name='acpi'>
- <ref name='featuretoggle'/>
- <empty/>
- </element>
- </optional>
- <optional>
- <element name='apic'>
- <ref name='featuretoggle'/>
- <empty/>
- </element>
- </optional>
- <optional>
- <element name='cpuselection'>
- <empty/>
- </element>
- </optional>
- <optional>
- <element name='deviceboot'>
- <empty/>
- </element>
- </optional>
+ <interleave>
+ <optional>
+ <element name='pae'>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name='nonpae'>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name='ia64_be'>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name='acpi'>
+ <ref name='featuretoggle'/>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name='apic'>
+ <ref name='featuretoggle'/>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name='cpuselection'>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name='deviceboot'>
+ <empty/>
+ </element>
+ </optional>
+ </interleave>
</element>
</define>
diff --git a/docs/schemas/nodedev.rng b/docs/schemas/nodedev.rng
index a73c2e5..c07a97d 100644
--- a/docs/schemas/nodedev.rng
+++ b/docs/schemas/nodedev.rng
@@ -15,6 +15,12 @@
<element name="parent"><text/></element>
</optional>
+ <optional>
+ <element name="driver">
+ <element name="name"><text/></element>
+ </element>
+ </optional>
+
<zeroOrMore>
<ref name="capability"/>
</zeroOrMore>
@@ -115,6 +121,28 @@
</choice>
</element>
+ <optional>
+ <element name='capability'>
+ <attribute name='type'>
+ <value>phys_function</value>
+ </attribute>
+ <optional>
+ <ref name='address'/>
+ </optional>
+ </element>
+ </optional>
+
+ <optional>
+ <element name='capability'>
+ <attribute name='type'>
+ <value>virt_functions</value>
+ </attribute>
+ <optional>
+ <ref name='address'/>
+ </optional>
+ </element>
+ </optional>
+
</define>
<define name='capusbdev'>
@@ -369,6 +397,15 @@
</element>
</define>
+ <define name='address'>
+ <element name='address'>
+ <attribute name='domain'><ref name='hexuint'/></attribute>
+ <attribute name='bus'><ref name='hexuint'/></attribute>
+ <attribute name='slot'><ref name='hexuint'/></attribute>
+ <attribute name='function'><ref name='hexuint'/></attribute>
+ </element>
+ </define>
+
<define name='hexuint'>
<data type='string'>
<param name="pattern">(0x)?[0-9a-f]+</param>
diff --git a/docs/schemas/storagepool.rng b/docs/schemas/storagepool.rng
index 039798a..8d33f70 100644
--- a/docs/schemas/storagepool.rng
+++ b/docs/schemas/storagepool.rng
@@ -178,10 +178,10 @@
<ref name='unsignedInt'/>
</element>
<element name='owner'>
- <ref name='unsignedInt'/>
+ <data type='int'/>
</element>
<element name='group'>
- <ref name='unsignedInt'/>
+ <data type='int'/>
</element>
<optional>
<element name='label'>
--
1.7.8.6
2
3
[libvirt] [PATCH v2][TCK 1/2] Extend image and memory size for installing guest
by Kyla Zhang 03 Aug '12
by Kyla Zhang 03 Aug '12
03 Aug '12
In fedora 17 with less than 512M memory will cause installation hang,
also the previous image size is too small, so improve them.
---
lib/Sys/Virt/TCK/NetworkHelpers.pm | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/Sys/Virt/TCK/NetworkHelpers.pm b/lib/Sys/Virt/TCK/NetworkHelpers.pm
index 6ff9eaa..f7f6d70 100644
--- a/lib/Sys/Virt/TCK/NetworkHelpers.pm
+++ b/lib/Sys/Virt/TCK/NetworkHelpers.pm
@@ -66,7 +66,7 @@ sub build_domain{
# We want a bigger disk than normal
$guest->rmdisk();
- my $diskpath = $tck->create_sparse_disk("nwfilter", "main.img", 2048);
+ my $diskpath = $tck->create_sparse_disk("nwfilter", "main.img", 5120);
$guest->disk(src => $diskpath,
dst => "vda",
type=> "file");
@@ -107,8 +107,8 @@ sub build_domain{
}
# common configuration
- $guest->maxmem("524288");
- $guest->memory("524288");
+ $guest->maxmem("1048576");
+ $guest->memory("1048576");
$guest->graphics(type => "vnc",
port => "-1",
autoport => "yes",
--
1.7.1
3
2
Detected when building --without-avahi.
* src/libvirt_private.syms (virnetservermdns.h): Move...
* src/libvirt_avahi.syms: ...to new file.
* src/Makefile.am (USED_SYM_FILES, EXTRA_DIST): Use it.
---
I'm debating whether to push this under the build-breaker rule.
Unfortunately, while this solved my build on an Ubuntu machine,
I have other machines which are failing for other symbols (some
SASL related, and one for xenLinuxDomainBlockStats), so it's
probably better to fix everything instead of just half the problem.
src/Makefile.am | 7 ++++++-
src/libvirt_avahi.syms | 13 +++++++++++++
src/libvirt_private.syms | 13 -------------
3 files changed, 19 insertions(+), 14 deletions(-)
create mode 100644 src/libvirt_avahi.syms
diff --git a/src/Makefile.am b/src/Makefile.am
index da3d0cd..98bad3d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1344,6 +1344,10 @@ if HAVE_SASL
USED_SYM_FILES += libvirt_sasl.syms
endif
+if HAVE_AVAHI
+USED_SYM_FILES += libvirt_avahi.syms
+endif
+
EXTRA_DIST += \
libvirt_public.syms \
libvirt_private.syms \
@@ -1357,7 +1361,8 @@ EXTRA_DIST += \
libvirt_qemu.syms \
libvirt_sasl.syms \
libvirt_vmx.syms \
- libvirt_xenxs.syms
+ libvirt_xenxs.syms \
+ libvirt_avahi.syms
GENERATED_SYM_FILES = libvirt.syms libvirt.def libvirt_qemu.def
diff --git a/src/libvirt_avahi.syms b/src/libvirt_avahi.syms
new file mode 100644
index 0000000..9bfed41
--- /dev/null
+++ b/src/libvirt_avahi.syms
@@ -0,0 +1,13 @@
+# Conditional on HAVE_AVAHI
+
+# virnetservermdns.h
+virNetServerMDNSAddEntry;
+virNetServerMDNSAddGroup;
+virNetServerMDNSEntryFree;
+virNetServerMDNSFree;
+virNetServerMDNSGroupFree;
+virNetServerMDNSNew;
+virNetServerMDNSRemoveEntry;
+virNetServerMDNSRemoveGroup;
+virNetServerMDNSStart;
+virNetServerMDNSStop;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 83ca99f..71341a2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1541,19 +1541,6 @@ virNetServerClientStartKeepAlive;
virNetServerClientWantClose;
-# virnetservermdns.h
-virNetServerMDNSAddEntry;
-virNetServerMDNSAddGroup;
-virNetServerMDNSEntryFree;
-virNetServerMDNSFree;
-virNetServerMDNSGroupFree;
-virNetServerMDNSNew;
-virNetServerMDNSRemoveEntry;
-virNetServerMDNSRemoveGroup;
-virNetServerMDNSStart;
-virNetServerMDNSStop;
-
-
# virnetserverprogram.h
virNetServerProgramDispatch;
virNetServerProgramFree;
--
1.7.11.2
3
8
Since we've introduced close callbacks we can drop this SIGINT magic
(which doesn't work now neither) and fully utilize the new feature.
---
tools/virsh.c | 45 ++++++++++++++++-----------------------------
1 files changed, 16 insertions(+), 29 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 4670ee6..b95a008 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -568,31 +568,16 @@ static int disconnected = 0; /* we may have been disconnected */
/*
* vshCatchDisconnect:
*
- * We get here when a SIGPIPE is being raised, we can't do much in the
- * handler, just save the fact it was raised
- */
-static void vshCatchDisconnect(int sig, siginfo_t *siginfo,
- void *context ATTRIBUTE_UNUSED) {
- if (sig == SIGPIPE ||
- (SA_SIGINFO && siginfo->si_signo == SIGPIPE))
- disconnected++;
-}
-
-/*
- * vshSetupSignals:
- *
- * Catch SIGPIPE signals which may arise when disconnection
- * from libvirtd occurs
+ * We get here when the connection was closed. We can't do much in the
+ * handler, just save the fact it was raised.
*/
static void
-vshSetupSignals(void) {
- struct sigaction sig_action;
-
- sig_action.sa_sigaction = vshCatchDisconnect;
- sig_action.sa_flags = SA_SIGINFO;
- sigemptyset(&sig_action.sa_mask);
-
- sigaction(SIGPIPE, &sig_action, NULL);
+vshCatchDisconnect(virConnectPtr conn ATTRIBUTE_UNUSED,
+ int reason,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ if (reason != VIR_CONNECT_CLOSE_REASON_CLIENT)
+ disconnected++;
}
/*
@@ -614,10 +599,15 @@ vshReconnect(vshControl *ctl)
ctl->conn = virConnectOpenAuth(ctl->name,
virConnectAuthPtrDefault,
ctl->readonly ? VIR_CONNECT_RO : 0);
- if (!ctl->conn)
+ if (!ctl->conn) {
vshError(ctl, "%s", _("Failed to reconnect to the hypervisor"));
- else if (connected)
- vshError(ctl, "%s", _("Reconnected to the hypervisor"));
+ } else {
+ if (virConnectRegisterCloseCallback(ctl->conn, vshCatchDisconnect,
+ NULL, NULL) < 0)
+ vshError(ctl, "%s", _("Unable to register disconnect callback"));
+ if (connected)
+ vshError(ctl, "%s", _("Reconnected to the hypervisor"));
+ }
disconnected = 0;
ctl->useGetInfo = false;
ctl->useSnapshotOld = false;
@@ -2458,9 +2448,6 @@ vshInit(vshControl *ctl)
/* set up the library error handler */
virSetErrorFunc(NULL, virshErrorHandler);
- /* set up the signals handlers to catch disconnections */
- vshSetupSignals();
-
if (virEventRegisterDefaultImpl() < 0)
return false;
--
1.7.8.6
2
2
[libvirt] [PATCH v3 0/7] Introduce API for dumping domain IP addresses
by Michal Privoznik 02 Aug '12
by Michal Privoznik 02 Aug '12
02 Aug '12
This feature has been requested for a very long time. However,
we had to wait for guest agent to obtain reliable results as
user might create totally different structure of interfaces than
seen from outside (e.g. bonding, virtual interfaces, etc.).
That's the main reason why sniffing for domain traffic can
return bogus results. Fortunately, qemu guest agent implement
requested part for a while so nothing holds us back anymore.
To make matters worse, guest OS can assign whatever name to
an interface and changing MAC inside guest isn't propagated
to the host which in the end see original one.
Therefore, finding correlation between interface within guest
and the host side end is left as exercise for mgmt applications.
This API is called virDomainInterfacesAddresses (okay, maybe
too many plurals) and returns a dynamically allocated array
of virDomainInterface struct. We agreed on this in previous versions.
Michal Privoznik (7):
Introduce virDomainInterfacesAddresses API
virsh: Expose virDomainInterfacesAddresses
qemu_agent: Implement 'guest-network-get-interfaces' command handling
qemu: Implement virDomainInterfacesAddresses
remote: Implement virDomainInterfacesAddresses
python: Expose virDomainInterfacesAddresses
python: create example for dumping domain IP addresses
daemon/remote.c | 124 +++++++++++++++++++++++++++++++
examples/python/Makefile.am | 2 +-
examples/python/README | 1 +
examples/python/domipaddrs.py | 50 +++++++++++++
include/libvirt/libvirt.h.in | 36 +++++++++
python/generator.py | 1 +
python/libvirt-override-api.xml | 6 ++
python/libvirt-override.c | 115 ++++++++++++++++++++++++++++
src/driver.h | 5 +
src/libvirt.c | 98 ++++++++++++++++++++++++
src/libvirt_public.syms | 1 +
src/qemu/qemu_agent.c | 156 +++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_agent.h | 3 +
src/qemu/qemu_driver.c | 76 +++++++++++++++++++
src/remote/remote_driver.c | 88 ++++++++++++++++++++++
src/remote/remote_protocol.x | 24 ++++++-
src/remote_protocol-structs | 24 ++++++
tools/virsh-domain-monitor.c | 112 ++++++++++++++++++++++++++++
tools/virsh.pod | 11 +++
19 files changed, 931 insertions(+), 2 deletions(-)
create mode 100644 examples/python/domipaddrs.py
--
1.7.8.6
1
7
[libvirt] [PATCH] Introduce an internal API for handling file based lockspaces
by Daniel P. Berrange 02 Aug '12
by Daniel P. Berrange 02 Aug '12
02 Aug '12
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The previously introduced virFile{Lock,Unlock} APIs provide a
way to acquire/release fcntl() locks on individual files. For
unknown reason though, the POSIX spec says that fcntl() locks
are released when *any* file handle refering to the same path
is closed. In the following sequence
threadA: fd1 = open("foo")
threadB: fd2 = open("foo")
threadA: virFileLock(fd1)
threadB: virFileLock(fd2)
threadB: close(fd2)
you'd expect threadA to come out holding a lock on 'foo', and
indeed it does hold a lock for a very short time. Unfortunately
when threadB does close(fd2) this releases the lock associated
with fd1. For the current libvirt use case for virFileLock -
pidfiles - this doesn't matter since the lock is acquired
at startup while single threaded an never released until
exit.
To provide a more generally useful API though, it is neccessary
to introduce a slightly higher level abstraction, which is to
be referred to as a "lockspace". This is to be provided by
a virLockSpacePtr object in src/util/virlockspace.{c,h}. The
core idea is that the lockspace keeps track of what files are
already open+locked. This means that when a 2nd thread comes
along and tries to acquire a lock, it doesn't end up opening
and closing a new FD. The lockspace just checks the current
list of held locks and immediately returns VIR_ERR_RESOURCE_BUSY.
NB, the API as it stands is designed on the basis that the
files being locked are not being otherwise opened and used
by the application code. ie the files which are used to
maintain the locks are not the files associated with the
resources themselves. One approach to using this API is to
acquire locks based on a hash of the filepath.
eg to lock /var/lib/libvirt/images/foo.img the application
might do
virLockSpacePtr lockspace = virLockSpaceNew("/var/lib/libvirt/imagelocks");
lockname = md5sum("/var/lib/libvirt/images/foo.img")
virLockSpaceAcquireLock(lockspace, lockname)
This patch is the basis for the soon to be re-submitted
patch series providing a virtlockd daemon
---
.gitignore | 1 +
include/libvirt/virterror.h | 2 +
src/Makefile.am | 1 +
src/libvirt_private.syms | 9 +
src/util/virlockspace.c | 419 ++++++++++++++++++++++++++++++++++++++++++++
src/util/virlockspace.h | 51 ++++++
src/util/virterror.c | 9 +-
tests/Makefile.am | 7 +-
tests/virlockspacetest.c | 311 ++++++++++++++++++++++++++++++++
9 files changed, 808 insertions(+), 2 deletions(-)
create mode 100644 src/util/virlockspace.c
create mode 100644 src/util/virlockspace.h
create mode 100644 tests/virlockspacetest.c
diff --git a/.gitignore b/.gitignore
index 5ea281a..9e566c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,6 +157,7 @@
/tests/virdrivermoduletest
/tests/virhashtest
/tests/virkeyfiletest
+/tests/virlockspacetest
/tests/virnet*test
/tests/virshtest
/tests/virtimetest
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index ad8e101..3e72cb7 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -110,6 +110,7 @@ typedef enum {
VIR_FROM_AUTH = 46, /* Error from auth handling */
VIR_FROM_DBUS = 47, /* Error from DBus */
VIR_FROM_PARALLELS = 48, /* Error from Parallels */
+ VIR_FROM_LOCKSPACE = 49, /* Error from lockspace */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_DOMAIN_LAST
@@ -277,6 +278,7 @@ typedef enum {
VIR_ERR_MIGRATE_UNSAFE = 81, /* Migration is not safe */
VIR_ERR_OVERFLOW = 82, /* integer overflow */
VIR_ERR_BLOCK_COPY_ACTIVE = 83, /* action prevented by block copy job */
+ VIR_ERR_RESOURCE_BUSY = 84, /* resource is already in use */
} virErrorNumber;
/**
diff --git a/src/Makefile.am b/src/Makefile.am
index b48ce65..527a2b8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@ UTIL_SOURCES = \
util/virkeycode.c util/virkeycode.h \
util/virkeyfile.c util/virkeyfile.h \
util/virkeymaps.h \
+ util/virlockspace.c util/virlockspace.h \
util/virmacaddr.h util/virmacaddr.c \
util/virnetdev.h util/virnetdev.c \
util/virnetdevbandwidth.h util/virnetdevbandwidth.c \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ac392fe..69f021d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1248,6 +1248,15 @@ virKeyFileHasGroup;
virKeyFileGetValueString;
+# virlockspace.h
+virLockSpaceNew;
+virLockSpaceFree;
+virLockSpaceCreateResource;
+virLockSpaceDeleteResource;
+virLockSpaceAcquireResource;
+virLockSpaceReleaseResource;
+
+
# virmacaddr.h
virMacAddrCmp;
virMacAddrCmpRaw;
diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c
new file mode 100644
index 0000000..727036b
--- /dev/null
+++ b/src/util/virlockspace.c
@@ -0,0 +1,419 @@
+/*
+ * virlockspace.c: simple file based lockspaces
+ *
+ * Copyright (C) 2012 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include "virlockspace.h"
+#include "logging.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "virfile.h"
+#include "virhash.h"
+#include "threads.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define VIR_FROM_THIS VIR_FROM_LOCKSPACE
+
+typedef struct _virLockSpaceResource virLockSpaceResource;
+typedef virLockSpaceResource *virLockSpaceResourcePtr;
+
+struct _virLockSpaceResource {
+ char *name;
+ char *path;
+ int fd;
+ int flags;
+ unsigned int holdCount;
+};
+
+struct _virLockSpace {
+ char *dir;
+ virMutex lock;
+
+ virHashTablePtr resources;
+};
+
+
+static char *virLockSpaceGetResourcePath(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ char *ret;
+ if (virAsprintf(&ret, "%s/%s", lockspace->dir, resname) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ return ret;
+}
+
+
+static void virLockSpaceResourceFree(virLockSpaceResourcePtr res)
+{
+ if (!res)
+ return;
+
+ if (res->holdCount &&
+ (res->flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE)) {
+ if (res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) {
+ /* We must upgrade to an exclusive lock to ensure
+ * no one else still has it before trying to delete */
+ if (virFileLock(res->fd, false, 0, 1) < 0) {
+ VIR_DEBUG("Could not upgrade shared lease to exclusive, not deleting");
+ } else {
+ unlink(res->path);
+ }
+ } else {
+ unlink(res->path);
+ }
+ }
+
+ VIR_FORCE_CLOSE(res->fd);
+ VIR_FREE(res->path);
+ VIR_FREE(res->name);
+ VIR_FREE(res);
+}
+
+
+static virLockSpaceResourcePtr
+virLockSpaceResourceNew(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags)
+{
+ virLockSpaceResourcePtr res;
+ bool shared = !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED);
+
+ if (VIR_ALLOC(res) < 0)
+ return NULL;
+
+ res->fd = -1;
+ res->flags = flags;
+
+ if (!(res->name = strdup(resname)))
+ goto no_memory;
+
+ if (!(res->path = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto no_memory;
+
+ if (flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) {
+ while (1) {
+ struct stat a, b;
+ if ((res->fd = open(res->path, O_RDWR|O_CREAT, 0600)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to open/create resource %s"),
+ res->path);
+ goto error;
+ }
+
+ if (virSetCloseExec(res->fd) < 0) {
+ virReportSystemError(errno,
+ _("Failed to set close-on-exec flag '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (fstat(res->fd, &b) < 0) {
+ virReportSystemError(errno,
+ _("Unable to check status of pid file '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (virFileLock(res->fd, shared, 0, 1) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ } else {
+ virReportSystemError(errno,
+ _("Unable to acquire lock on '%s'"),
+ res->path);
+ }
+ goto error;
+ }
+
+ /* Now make sure the pidfile we locked is the same
+ * one that now exists on the filesystem
+ */
+ if (stat(res->path, &a) < 0) {
+ char ebuf[1024] ATTRIBUTE_UNUSED;
+ VIR_DEBUG("Resource '%s' disappeared: %s",
+ res->path, virStrerror(errno, ebuf, sizeof(ebuf)));
+ VIR_FORCE_CLOSE(res->fd);
+ /* Someone else must be racing with us, so try agin */
+ continue;
+ }
+
+ if (a.st_ino == b.st_ino)
+ break;
+
+ VIR_DEBUG("Resource '%s' was recreated", res->path);
+ VIR_FORCE_CLOSE(res->fd);
+ /* Someone else must be racing with us, so try agin */
+ }
+ } else {
+ if ((res->fd = open(res->path, O_RDWR)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to open resource %s"),
+ res->path);
+ goto error;
+ }
+
+ if (virSetCloseExec(res->fd) < 0) {
+ virReportSystemError(errno,
+ _("Failed to set close-on-exec flag '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (virFileLock(res->fd, !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED), 0, 0) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ } else {
+ virReportSystemError(errno,
+ _("Unable to acquire lock on '%s'"),
+ res->path);
+ }
+ goto error;
+ }
+ }
+ res->holdCount = 1;
+
+ return res;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockSpaceResourceFree(res);
+ return NULL;
+}
+
+
+static void virLockSpaceResourceDataFree(void *opaque, const void *name ATTRIBUTE_UNUSED)
+{
+ virLockSpaceResourcePtr res = opaque;
+ virLockSpaceResourceFree(res);
+}
+
+
+virLockSpacePtr virLockSpaceNew(const char *directory)
+{
+ virLockSpacePtr lockspace;
+
+ if (VIR_ALLOC(lockspace) < 0)
+ return NULL;
+
+ if (virMutexInit(&lockspace->lock) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to initialize lockspace mutex"));
+ VIR_FREE(lockspace);
+ return NULL;
+ }
+
+ if (!(lockspace->dir = strdup(directory)))
+ goto no_memory;
+
+ if (!(lockspace->resources = virHashCreate(10,
+ virLockSpaceResourceDataFree)))
+ goto error;
+
+ if (virFileExists(directory)) {
+ if (!virFileIsDir(directory)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Lockspace location %s exists, but is not a directory"),
+ directory);
+ goto error;
+ }
+ } else {
+ if (virFileMakePathWithMode(directory, 0700) < 0) {
+ virReportSystemError(errno,
+ _("Unable to create lockspace %s"),
+ directory);
+ goto error;
+ }
+ }
+
+ return lockspace;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockSpaceFree(lockspace);
+ return NULL;
+}
+
+
+void virLockSpaceFree(virLockSpacePtr lockspace)
+{
+ if (!lockspace)
+ return;
+
+ virHashFree(lockspace->resources);
+ VIR_FREE(lockspace->dir);
+ virMutexDestroy(&lockspace->lock);
+ VIR_FREE(lockspace);
+}
+
+
+int virLockSpaceCreateResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ char *respath = NULL;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(respath = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto cleanup;
+
+ if (virFileTouch(respath, 0600) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ VIR_FREE(respath);
+ return ret;
+}
+
+
+int virLockSpaceDeleteResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ char *respath = NULL;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(respath = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto cleanup;
+
+ if (unlink(respath) < 0 &&
+ errno != ENOENT) {
+ virReportSystemError(errno,
+ _("Unable to delete lockspace resource %s"),
+ respath);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ VIR_FREE(respath);
+ return ret;
+}
+
+
+int virLockSpaceAcquireResource(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags)
+{
+ int ret = -1;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s flags=%x", lockspace, resname, flags);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ if ((res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) &&
+ (flags & VIR_LOCK_SPACE_ACQUIRE_SHARED)) {
+ res->holdCount++;
+ goto done;
+ }
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(res = virLockSpaceResourceNew(lockspace, resname, flags)))
+ goto cleanup;
+
+ if (virHashAddEntry(lockspace->resources, resname, res) < 0) {
+ virLockSpaceResourceFree(res);
+ goto cleanup;
+ }
+
+done:
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ return ret;
+}
+
+
+int virLockSpaceReleaseResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if (!(res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is not locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (res->holdCount == 1) {
+ if (virHashRemoveEntry(lockspace->resources, resname) < 0)
+ goto cleanup;
+ } else {
+ res->holdCount--;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ return ret;
+}
diff --git a/src/util/virlockspace.h b/src/util/virlockspace.h
new file mode 100644
index 0000000..6d91728
--- /dev/null
+++ b/src/util/virlockspace.h
@@ -0,0 +1,51 @@
+/*
+ * virlockspace.h: simple file based lockspaces
+ *
+ * Copyright (C) 2012 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_LOCK_SPACE_H__
+# define __VIR_LOCK_SPACE_H__
+
+#include "internal.h"
+
+typedef struct _virLockSpace virLockSpace;
+typedef virLockSpace *virLockSpacePtr;
+
+virLockSpacePtr virLockSpaceNew(const char *directory);
+
+void virLockSpaceFree(virLockSpacePtr lockspace);
+
+int virLockSpaceCreateResource(virLockSpacePtr lockspace,
+ const char *resname);
+int virLockSpaceDeleteResource(virLockSpacePtr lockspace,
+ const char *resname);
+
+typedef enum {
+ VIR_LOCK_SPACE_ACQUIRE_SHARED = (1 << 0),
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE = (1 << 1),
+} virLockSpaceAcquireFlags;
+
+int virLockSpaceAcquireResource(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags);
+
+int virLockSpaceReleaseResource(virLockSpacePtr lockspace,
+ const char *resname);
+
+#endif /* __VIR_LOCK_SPACE_H__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index a40cfe0..74f511a 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -112,7 +112,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"URI Utils", /* 45 */
"Authentication Utils",
"DBus Utils",
- "Parallels Cloud Server"
+ "Parallels Cloud Server",
+ "Lock Space",
)
@@ -1185,6 +1186,12 @@ virErrorMsg(virErrorNumber error, const char *info)
else
errmsg = _("block copy still active: %s");
break;
+ case VIR_ERR_RESOURCE_BUSY:
+ if (info == NULL)
+ errmsg = _("resource busy");
+ else
+ errmsg = _("resource busy %s");
+ break;
}
return errmsg;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b931cea..8ca6441 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -91,7 +91,7 @@ test_programs = virshtest sockettest \
virhashtest virnetmessagetest virnetsockettest \
utiltest virnettlscontexttest shunloadtest \
virtimetest viruritest virkeyfiletest \
- virauthconfigtest
+ virauthconfigtest virlockspacetest
if WITH_DRIVER_MODULES
test_programs += virdrivermoduletest
@@ -503,6 +503,11 @@ virtimetest_SOURCES = \
virtimetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
virtimetest_LDADD = $(LDADDS)
+virlockspacetest_SOURCES = \
+ virlockspacetest.c testutils.h testutils.c
+virlockspacetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
+virlockspacetest_LDADD = $(LDADDS)
+
viruritest_SOURCES = \
viruritest.c testutils.h testutils.c
viruritest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c
new file mode 100644
index 0000000..37175cb
--- /dev/null
+++ b/tests/virlockspacetest.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2011 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <signal.h>
+
+#include "testutils.h"
+#include "util.h"
+#include "virterror_internal.h"
+#include "memory.h"
+#include "logging.h"
+
+#include "virlockspace.h"
+
+#define VIR_FROM_THIS VIR_FROM_RPC
+
+#define LOCKSPACE_DIR abs_builddir "/virlockspacedata"
+
+static int testLockSpaceCreate(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLifecycle(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockExcl(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockExclAuto(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockShr(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_SHARED) < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_SHARED) < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockShrAuto(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_SHARED |
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) == 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_SHARED |
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int
+mymain(void)
+{
+ int ret = 0;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ if (virtTestRun("Lockspace creation", 1, testLockSpaceCreate, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lifecycle", 1, testLockSpaceResourceLifecycle, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock excl", 1, testLockSpaceResourceLockExcl, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock shr", 1, testLockSpaceResourceLockShr, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock excl auto", 1, testLockSpaceResourceLockExclAuto, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock shr auto", 1, testLockSpaceResourceLockShrAuto, NULL) < 0)
+ ret = -1;
+
+ return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN(mymain)
--
1.7.11.2
1
1
[libvirt] [PATCH v2] Introduce an internal API for handling file based lockspaces
by Daniel P. Berrange 02 Aug '12
by Daniel P. Berrange 02 Aug '12
02 Aug '12
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The previously introduced virFile{Lock,Unlock} APIs provide a
way to acquire/release fcntl() locks on individual files. For
unknown reason though, the POSIX spec says that fcntl() locks
are released when *any* file handle refering to the same path
is closed. In the following sequence
threadA: fd1 = open("foo")
threadB: fd2 = open("foo")
threadA: virFileLock(fd1)
threadB: virFileLock(fd2)
threadB: close(fd2)
you'd expect threadA to come out holding a lock on 'foo', and
indeed it does hold a lock for a very short time. Unfortunately
when threadB does close(fd2) this releases the lock associated
with fd1. For the current libvirt use case for virFileLock -
pidfiles - this doesn't matter since the lock is acquired
at startup while single threaded an never released until
exit.
To provide a more generally useful API though, it is neccessary
to introduce a slightly higher level abstraction, which is to
be referred to as a "lockspace". This is to be provided by
a virLockSpacePtr object in src/util/virlockspace.{c,h}. The
core idea is that the lockspace keeps track of what files are
already open+locked. This means that when a 2nd thread comes
along and tries to acquire a lock, it doesn't end up opening
and closing a new FD. The lockspace just checks the current
list of held locks and immediately returns VIR_ERR_RESOURCE_BUSY.
NB, the API as it stands is designed on the basis that the
files being locked are not being otherwise opened and used
by the application code. One approach to using this API is to
acquire locks based on a hash of the filepath.
eg to lock /var/lib/libvirt/images/foo.img the application
might do
virLockSpacePtr lockspace = virLockSpaceNew("/var/lib/libvirt/imagelocks");
lockname = md5sum("/var/lib/libvirt/images/foo.img")
virLockSpaceAcquireLock(lockspace, lockname)
It is also possible to do locks directly on resources by
using a NULL lockspace directory and then using the file
path as the lock name eg
virLockSpacePtr lockspace = virLockSpaceNew(NULL)
virLockSpaceAcquireLock(lockspace, "/var/lib/libvirt/images/foo.img")
This is only safe todo though if no other part of the proces
will be opening the files. This will be the case when this
code is used inside the soon-to-be-reposted virlockd daemon
---
.gitignore | 1 +
include/libvirt/virterror.h | 2 +
src/Makefile.am | 1 +
src/libvirt_private.syms | 9 +
src/util/virlockspace.c | 430 ++++++++++++++++++++++++++++++++++++++++++++
src/util/virlockspace.h | 51 ++++++
src/util/virterror.c | 9 +-
tests/Makefile.am | 7 +-
tests/virlockspacetest.c | 360 +++++++++++++++++++++++++++++++++++++
9 files changed, 868 insertions(+), 2 deletions(-)
create mode 100644 src/util/virlockspace.c
create mode 100644 src/util/virlockspace.h
create mode 100644 tests/virlockspacetest.c
diff --git a/.gitignore b/.gitignore
index 5ea281a..9e566c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,6 +157,7 @@
/tests/virdrivermoduletest
/tests/virhashtest
/tests/virkeyfiletest
+/tests/virlockspacetest
/tests/virnet*test
/tests/virshtest
/tests/virtimetest
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index ad8e101..3e72cb7 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -110,6 +110,7 @@ typedef enum {
VIR_FROM_AUTH = 46, /* Error from auth handling */
VIR_FROM_DBUS = 47, /* Error from DBus */
VIR_FROM_PARALLELS = 48, /* Error from Parallels */
+ VIR_FROM_LOCKSPACE = 49, /* Error from lockspace */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_DOMAIN_LAST
@@ -277,6 +278,7 @@ typedef enum {
VIR_ERR_MIGRATE_UNSAFE = 81, /* Migration is not safe */
VIR_ERR_OVERFLOW = 82, /* integer overflow */
VIR_ERR_BLOCK_COPY_ACTIVE = 83, /* action prevented by block copy job */
+ VIR_ERR_RESOURCE_BUSY = 84, /* resource is already in use */
} virErrorNumber;
/**
diff --git a/src/Makefile.am b/src/Makefile.am
index b48ce65..527a2b8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@ UTIL_SOURCES = \
util/virkeycode.c util/virkeycode.h \
util/virkeyfile.c util/virkeyfile.h \
util/virkeymaps.h \
+ util/virlockspace.c util/virlockspace.h \
util/virmacaddr.h util/virmacaddr.c \
util/virnetdev.h util/virnetdev.c \
util/virnetdevbandwidth.h util/virnetdevbandwidth.c \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ac392fe..69f021d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1248,6 +1248,15 @@ virKeyFileHasGroup;
virKeyFileGetValueString;
+# virlockspace.h
+virLockSpaceNew;
+virLockSpaceFree;
+virLockSpaceCreateResource;
+virLockSpaceDeleteResource;
+virLockSpaceAcquireResource;
+virLockSpaceReleaseResource;
+
+
# virmacaddr.h
virMacAddrCmp;
virMacAddrCmpRaw;
diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c
new file mode 100644
index 0000000..adc3170
--- /dev/null
+++ b/src/util/virlockspace.c
@@ -0,0 +1,430 @@
+/*
+ * virlockspace.c: simple file based lockspaces
+ *
+ * Copyright (C) 2012 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include "virlockspace.h"
+#include "logging.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "virfile.h"
+#include "virhash.h"
+#include "threads.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define VIR_FROM_THIS VIR_FROM_LOCKSPACE
+
+typedef struct _virLockSpaceResource virLockSpaceResource;
+typedef virLockSpaceResource *virLockSpaceResourcePtr;
+
+struct _virLockSpaceResource {
+ char *name;
+ char *path;
+ int fd;
+ int flags;
+ unsigned int holdCount;
+};
+
+struct _virLockSpace {
+ char *dir;
+ virMutex lock;
+
+ virHashTablePtr resources;
+};
+
+
+static char *virLockSpaceGetResourcePath(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ char *ret;
+ if (lockspace->dir) {
+ if (virAsprintf(&ret, "%s/%s", lockspace->dir, resname) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ } else {
+ if (!(ret = strdup(resname))) {
+ virReportOOMError();
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+
+static void virLockSpaceResourceFree(virLockSpaceResourcePtr res)
+{
+ if (!res)
+ return;
+
+ if (res->holdCount &&
+ (res->flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE)) {
+ if (res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) {
+ /* We must upgrade to an exclusive lock to ensure
+ * no one else still has it before trying to delete */
+ if (virFileLock(res->fd, false, 0, 1) < 0) {
+ VIR_DEBUG("Could not upgrade shared lease to exclusive, not deleting");
+ } else {
+ unlink(res->path);
+ }
+ } else {
+ unlink(res->path);
+ }
+ }
+
+ VIR_FORCE_CLOSE(res->fd);
+ VIR_FREE(res->path);
+ VIR_FREE(res->name);
+ VIR_FREE(res);
+}
+
+
+static virLockSpaceResourcePtr
+virLockSpaceResourceNew(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags)
+{
+ virLockSpaceResourcePtr res;
+ bool shared = !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED);
+
+ if (VIR_ALLOC(res) < 0)
+ return NULL;
+
+ res->fd = -1;
+ res->flags = flags;
+
+ if (!(res->name = strdup(resname)))
+ goto no_memory;
+
+ if (!(res->path = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto no_memory;
+
+ if (flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) {
+ while (1) {
+ struct stat a, b;
+ if ((res->fd = open(res->path, O_RDWR|O_CREAT, 0600)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to open/create resource %s"),
+ res->path);
+ goto error;
+ }
+
+ if (virSetCloseExec(res->fd) < 0) {
+ virReportSystemError(errno,
+ _("Failed to set close-on-exec flag '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (fstat(res->fd, &b) < 0) {
+ virReportSystemError(errno,
+ _("Unable to check status of pid file '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (virFileLock(res->fd, shared, 0, 1) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ } else {
+ virReportSystemError(errno,
+ _("Unable to acquire lock on '%s'"),
+ res->path);
+ }
+ goto error;
+ }
+
+ /* Now make sure the pidfile we locked is the same
+ * one that now exists on the filesystem
+ */
+ if (stat(res->path, &a) < 0) {
+ char ebuf[1024] ATTRIBUTE_UNUSED;
+ VIR_DEBUG("Resource '%s' disappeared: %s",
+ res->path, virStrerror(errno, ebuf, sizeof(ebuf)));
+ VIR_FORCE_CLOSE(res->fd);
+ /* Someone else must be racing with us, so try agin */
+ continue;
+ }
+
+ if (a.st_ino == b.st_ino)
+ break;
+
+ VIR_DEBUG("Resource '%s' was recreated", res->path);
+ VIR_FORCE_CLOSE(res->fd);
+ /* Someone else must be racing with us, so try agin */
+ }
+ } else {
+ if ((res->fd = open(res->path, O_RDWR)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to open resource %s"),
+ res->path);
+ goto error;
+ }
+
+ if (virSetCloseExec(res->fd) < 0) {
+ virReportSystemError(errno,
+ _("Failed to set close-on-exec flag '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (virFileLock(res->fd, !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED), 0, 0) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ } else {
+ virReportSystemError(errno,
+ _("Unable to acquire lock on '%s'"),
+ res->path);
+ }
+ goto error;
+ }
+ }
+ res->holdCount = 1;
+
+ return res;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockSpaceResourceFree(res);
+ return NULL;
+}
+
+
+static void virLockSpaceResourceDataFree(void *opaque, const void *name ATTRIBUTE_UNUSED)
+{
+ virLockSpaceResourcePtr res = opaque;
+ virLockSpaceResourceFree(res);
+}
+
+
+virLockSpacePtr virLockSpaceNew(const char *directory)
+{
+ virLockSpacePtr lockspace;
+
+ if (VIR_ALLOC(lockspace) < 0)
+ return NULL;
+
+ if (virMutexInit(&lockspace->lock) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to initialize lockspace mutex"));
+ VIR_FREE(lockspace);
+ return NULL;
+ }
+
+ if (directory &&
+ !(lockspace->dir = strdup(directory)))
+ goto no_memory;
+
+ if (!(lockspace->resources = virHashCreate(10,
+ virLockSpaceResourceDataFree)))
+ goto error;
+
+ if (directory) {
+ if (virFileExists(directory)) {
+ if (!virFileIsDir(directory)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Lockspace location %s exists, but is not a directory"),
+ directory);
+ goto error;
+ }
+ } else {
+ if (virFileMakePathWithMode(directory, 0700) < 0) {
+ virReportSystemError(errno,
+ _("Unable to create lockspace %s"),
+ directory);
+ goto error;
+ }
+ }
+ }
+
+ return lockspace;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockSpaceFree(lockspace);
+ return NULL;
+}
+
+
+void virLockSpaceFree(virLockSpacePtr lockspace)
+{
+ if (!lockspace)
+ return;
+
+ virHashFree(lockspace->resources);
+ VIR_FREE(lockspace->dir);
+ virMutexDestroy(&lockspace->lock);
+ VIR_FREE(lockspace);
+}
+
+
+int virLockSpaceCreateResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ char *respath = NULL;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(respath = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto cleanup;
+
+ if (virFileTouch(respath, 0600) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ VIR_FREE(respath);
+ return ret;
+}
+
+
+int virLockSpaceDeleteResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ char *respath = NULL;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(respath = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto cleanup;
+
+ if (unlink(respath) < 0 &&
+ errno != ENOENT) {
+ virReportSystemError(errno,
+ _("Unable to delete lockspace resource %s"),
+ respath);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ VIR_FREE(respath);
+ return ret;
+}
+
+
+int virLockSpaceAcquireResource(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags)
+{
+ int ret = -1;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s flags=%x", lockspace, resname, flags);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ if ((res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) &&
+ (flags & VIR_LOCK_SPACE_ACQUIRE_SHARED)) {
+ res->holdCount++;
+ goto done;
+ }
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(res = virLockSpaceResourceNew(lockspace, resname, flags)))
+ goto cleanup;
+
+ if (virHashAddEntry(lockspace->resources, resname, res) < 0) {
+ virLockSpaceResourceFree(res);
+ goto cleanup;
+ }
+
+done:
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ return ret;
+}
+
+
+int virLockSpaceReleaseResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if (!(res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is not locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (res->holdCount == 1) {
+ if (virHashRemoveEntry(lockspace->resources, resname) < 0)
+ goto cleanup;
+ } else {
+ res->holdCount--;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ return ret;
+}
diff --git a/src/util/virlockspace.h b/src/util/virlockspace.h
new file mode 100644
index 0000000..6d91728
--- /dev/null
+++ b/src/util/virlockspace.h
@@ -0,0 +1,51 @@
+/*
+ * virlockspace.h: simple file based lockspaces
+ *
+ * Copyright (C) 2012 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_LOCK_SPACE_H__
+# define __VIR_LOCK_SPACE_H__
+
+#include "internal.h"
+
+typedef struct _virLockSpace virLockSpace;
+typedef virLockSpace *virLockSpacePtr;
+
+virLockSpacePtr virLockSpaceNew(const char *directory);
+
+void virLockSpaceFree(virLockSpacePtr lockspace);
+
+int virLockSpaceCreateResource(virLockSpacePtr lockspace,
+ const char *resname);
+int virLockSpaceDeleteResource(virLockSpacePtr lockspace,
+ const char *resname);
+
+typedef enum {
+ VIR_LOCK_SPACE_ACQUIRE_SHARED = (1 << 0),
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE = (1 << 1),
+} virLockSpaceAcquireFlags;
+
+int virLockSpaceAcquireResource(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags);
+
+int virLockSpaceReleaseResource(virLockSpacePtr lockspace,
+ const char *resname);
+
+#endif /* __VIR_LOCK_SPACE_H__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index a40cfe0..74f511a 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -112,7 +112,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"URI Utils", /* 45 */
"Authentication Utils",
"DBus Utils",
- "Parallels Cloud Server"
+ "Parallels Cloud Server",
+ "Lock Space",
)
@@ -1185,6 +1186,12 @@ virErrorMsg(virErrorNumber error, const char *info)
else
errmsg = _("block copy still active: %s");
break;
+ case VIR_ERR_RESOURCE_BUSY:
+ if (info == NULL)
+ errmsg = _("resource busy");
+ else
+ errmsg = _("resource busy %s");
+ break;
}
return errmsg;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b931cea..8ca6441 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -91,7 +91,7 @@ test_programs = virshtest sockettest \
virhashtest virnetmessagetest virnetsockettest \
utiltest virnettlscontexttest shunloadtest \
virtimetest viruritest virkeyfiletest \
- virauthconfigtest
+ virauthconfigtest virlockspacetest
if WITH_DRIVER_MODULES
test_programs += virdrivermoduletest
@@ -503,6 +503,11 @@ virtimetest_SOURCES = \
virtimetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
virtimetest_LDADD = $(LDADDS)
+virlockspacetest_SOURCES = \
+ virlockspacetest.c testutils.h testutils.c
+virlockspacetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
+virlockspacetest_LDADD = $(LDADDS)
+
viruritest_SOURCES = \
viruritest.c testutils.h testutils.c
viruritest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c
new file mode 100644
index 0000000..ea77ff5
--- /dev/null
+++ b/tests/virlockspacetest.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2011 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+#include "testutils.h"
+#include "util.h"
+#include "virterror_internal.h"
+#include "memory.h"
+#include "logging.h"
+
+#include "virlockspace.h"
+
+#define VIR_FROM_THIS VIR_FROM_RPC
+
+#define LOCKSPACE_DIR abs_builddir "/virlockspacedata"
+
+static int testLockSpaceCreate(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLifecycle(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockExcl(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockExclAuto(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockShr(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_SHARED) < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_SHARED) < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockShrAuto(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_SHARED |
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) == 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_SHARED |
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockPath(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(NULL);
+
+ mkdir(LOCKSPACE_DIR, 0700);
+
+ if (virLockSpaceCreateResource(lockspace, LOCKSPACE_DIR "/foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, LOCKSPACE_DIR "/foo", 0) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, LOCKSPACE_DIR "/foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, LOCKSPACE_DIR "/foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, LOCKSPACE_DIR "/foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, LOCKSPACE_DIR "/foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+
+static int
+mymain(void)
+{
+ int ret = 0;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ if (virtTestRun("Lockspace creation", 1, testLockSpaceCreate, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lifecycle", 1, testLockSpaceResourceLifecycle, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock excl", 1, testLockSpaceResourceLockExcl, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock shr", 1, testLockSpaceResourceLockShr, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock excl auto", 1, testLockSpaceResourceLockExclAuto, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock shr auto", 1, testLockSpaceResourceLockShrAuto, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res full path", 1, testLockSpaceResourceLockPath, NULL) < 0)
+ ret = -1;
+
+ return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN(mymain)
--
1.7.11.2
1
0