[libvirt] [PATCH] nwfilter: do not create ebtables chain unnecessarily
by Stefan Berger
If only iptables rules are created then two unnecessary ebtables chains
are also created. This patch fixes this.
The chains had been cleaned up properly when the interface disappeared,
though.
---
src/nwfilter/nwfilter_ebiptables_driver.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
Index: libvirt-iterator/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- libvirt-iterator.orig/src/nwfilter/nwfilter_ebiptables_driver.c
+++ libvirt-iterator/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -3622,10 +3622,12 @@ ebiptablesApplyNewRules(const char *ifna
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
/* create needed chains */
- if (ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_in_set , 1,
- &ebtChains, &nEbtChains) < 0 ||
- ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_out_set, 0,
- &ebtChains, &nEbtChains) < 0) {
+ if ((virHashSize(chains_in_set) > 0 &&
+ ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_in_set , 1,
+ &ebtChains, &nEbtChains) < 0) ||
+ (virHashSize(chains_out_set) > 0 &&
+ ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_out_set, 0,
+ &ebtChains, &nEbtChains) < 0)) {
goto tear_down_tmpebchains;
}
13 years
[libvirt] [PATCH] add a default event handle, to passthough the new events come from qemu
by shaohef@linux.vnet.ibm.com
From: Shaohe Feng <shaohef(a)linux.vnet.ibm.com>
Basically, this feature can go along with qemu monitor passthrough.
That way, if we use new commands in the monitor that generate new events, we want
some way to receive those new events too.
In order to test this patch, see the attached python test case. When domains are started,
it will be able to catch RESUME events.
Signed-off-by: Shaohe Feng <shaohef(a)linux.vnet.ibm.com>
---
daemon/remote.c | 34 ++++++++++++++++++++++
include/libvirt/libvirt.h.in | 14 +++++++++
python/libvirt-override-virConnect.py | 12 ++++++++
python/libvirt-override.c | 50 +++++++++++++++++++++++++++++++++
src/conf/domain_event.c | 46 ++++++++++++++++++++++++++++++
src/conf/domain_event.h | 5 +++
src/libvirt_private.syms | 2 +
src/qemu/qemu_monitor.c | 9 ++++++
src/qemu/qemu_monitor.h | 6 ++++
src/qemu/qemu_monitor_json.c | 31 ++++++++++++++++++++
src/qemu/qemu_process.c | 23 +++++++++++++++
src/remote/remote_driver.c | 31 ++++++++++++++++++++
src/remote/remote_protocol.x | 8 ++++-
src/remote_protocol-structs | 5 +++
14 files changed, 275 insertions(+), 1 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 245d41c..ef7d513 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -426,6 +426,38 @@ mem_error:
return -1;
}
+static int remoteRelayDomainEventDefault(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *rawEvent,
+ void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+ remote_domain_event_default_event_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain default event event %s %d %s",
+ dom->name, dom->id, rawEvent);
+
+ /* build return data */
+ memset(&data, 0, sizeof data);
+ data.rawEvent = (char*)strdup(rawEvent);
+ if (data.rawEvent == NULL)
+ goto mem_error;
+ make_nonnull_domain(&data.dom, dom);
+ remoteDispatchDomainEventSend(client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_DEFAULT_EVENT,
+ (xdrproc_t)xdr_remote_domain_event_default_event_msg, &data);
+
+ return 0;
+
+mem_error:
+ virReportOOMError();
+ VIR_FREE(data.rawEvent);
+ return -1;
+}
+
static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
@@ -461,6 +493,8 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventIOErrorReason),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDefault),
+
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 07617be..5ccf8c7 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2975,6 +2975,19 @@ typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
int type,
int status,
void *opaque);
+/**
+ * virConnectDomainEventDefaultCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @rawEvent: the content of the unknow or un-implementation event
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_DEFAULT with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventDefaultCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *rawEvent,
+ void *opaque);
/**
* VIR_DOMAIN_EVENT_CALLBACK:
@@ -2995,6 +3008,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON = 6, /* virConnectDomainEventIOErrorReasonCallback */
VIR_DOMAIN_EVENT_ID_CONTROL_ERROR = 7, /* virConnectDomainEventGenericCallback */
VIR_DOMAIN_EVENT_ID_BLOCK_JOB = 8, /* virConnectDomainEventBlockJobCallback */
+ VIR_DOMAIN_EVENT_ID_DEFAULT = 9, /* virConnectDomainEventDefaultCallback */
/*
* NB: this enum value will increase over time as new events are
diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py
index 65b5342..f00cbb9 100644
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -125,6 +125,18 @@
except AttributeError:
pass
+ def dispatchDomainEventDefaultCallback(self, dom, path, cbData):
+ """Dispatches events to python user Default event callbacks
+ """
+ try:
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), path, opaque)
+ return 0
+ except AttributeError:
+ pass
+
def domainEventDeregisterAny(self, callbackID):
"""Removes a Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index d65423d..c674390 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -4329,6 +4329,53 @@ libvirt_virConnectDomainEventBlockJobCallback(virConnectPtr conn ATTRIBUTE_UNUSE
return ret;
}
+static int
+libvirt_virConnectDomainEventDefaultCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *rawEvent,
+ void *opaque)
+{
+ PyObject *pyobj_cbData = (PyObject*)opaque;
+ PyObject *pyobj_dom;
+ PyObject *pyobj_ret;
+ PyObject *pyobj_conn;
+ PyObject *dictKey;
+ int ret = -1;
+
+ LIBVIRT_ENSURE_THREAD_STATE;
+
+ /* Create a python instance of this virDomainPtr */
+ virDomainRef(dom);
+ pyobj_dom = libvirt_virDomainPtrWrap(dom);
+ Py_INCREF(pyobj_cbData);
+
+ dictKey = libvirt_constcharPtrWrap("conn");
+ pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
+ Py_DECREF(dictKey);
+
+ /* Call the Callback Dispatcher */
+ pyobj_ret = PyObject_CallMethod(pyobj_conn,
+ (char*)"dispatchDomainEventDefaultCallback",
+ (char*)"OsO",
+ pyobj_dom, rawEvent, pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if (!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
static PyObject *
libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
PyObject * args)
@@ -4386,6 +4433,9 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBlockJobCallback);
break;
+ case VIR_DOMAIN_EVENT_ID_DEFAULT:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventDefaultCallback);
+ break;
}
if (!cb) {
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 3189346..04f44fb 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -88,6 +88,9 @@ struct _virDomainEvent {
int type;
int status;
} blockJob;
+ struct {
+ char *rawEvent;
+ }defaultEvent;
} data;
};
@@ -509,6 +512,9 @@ void virDomainEventFree(virDomainEventPtr event)
case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
VIR_FREE(event->data.blockJob.path);
break;
+ case VIR_DOMAIN_EVENT_ID_DEFAULT:
+ VIR_FREE(event->data.defaultEvent.rawEvent);
+ break;
}
VIR_FREE(event->dom.name);
@@ -923,6 +929,40 @@ virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
path, type, status);
}
+static virDomainEventPtr
+virDomainEventDefaultNew(int id, const char *name, unsigned char *uuid,
+ const char *rawEvent)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_DEFAULT,
+ id, name, uuid);
+ if (ev) {
+ if (!(ev->data.defaultEvent.rawEvent = strdup(rawEvent))) {
+ virReportOOMError();
+ VIR_FREE(ev->dom.name);
+ VIR_FREE(ev);
+ return NULL;
+ }
+ }
+
+ return ev;
+}
+
+virDomainEventPtr virDomainEventDefaultNewFromObj(virDomainObjPtr obj,
+ const char *rawEvent)
+{
+
+ return virDomainEventDefaultNew(obj->def->id, obj->def->name,
+ obj->def->uuid, rawEvent);
+}
+
+virDomainEventPtr virDomainEventDefaultNewFromDom(virDomainPtr dom,
+ const char *rawEvent)
+{
+ return virDomainEventDefaultNew(dom->id, dom->name, dom->uuid,
+ rawEvent);
+}
+
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom)
{
virDomainEventPtr ev =
@@ -1083,6 +1123,12 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
+ case VIR_DOMAIN_EVENT_ID_DEFAULT:
+ ((virConnectDomainEventDefaultCallback)cb)(conn, dom,
+ event->data.defaultEvent.rawEvent,
+ cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index b06be16..401f781 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -178,6 +178,11 @@ virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
int type,
int status);
+virDomainEventPtr virDomainEventDefaultNewFromObj(virDomainObjPtr obj,
+ const char *rawEvent);
+virDomainEventPtr virDomainEventDefaultNewFromDom(virDomainPtr dom,
+ const char *rawEvent);
+
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1ac486f..1dcfc3e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -457,6 +457,8 @@ virDomainWatchdogModelTypeToString;
# domain_event.h
virDomainEventBlockJobNewFromObj;
virDomainEventBlockJobNewFromDom;
+virDomainEventDefaultNewFromObj;
+virDomainEventDefaultNewFromDom;
virDomainEventCallbackListAdd;
virDomainEventCallbackListAddID;
virDomainEventCallbackListCount;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index c9dd69e..a2b4036 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -976,6 +976,15 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorEmitDefaultEvent(qemuMonitorPtr mon,
+ const char *rawEvent)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+ QEMU_MONITOR_CALLBACK(mon, ret, domainDefaultEvent, mon->vm,
+ rawEvent);
+ return ret;
+}
int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 3ec78ad..23a03e5 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -123,6 +123,9 @@ struct _qemuMonitorCallbacks {
const char *diskAlias,
int type,
int status);
+ int (*domainDefaultEvent)(qemuMonitorPtr mon,
+ virDomainObjPtr vm,
+ const char *rawEvent)
};
@@ -194,6 +197,9 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
int type,
int status);
+int qemuMonitorEmitDefaultEvent(qemuMonitorPtr mon,
+ const char *rawEvent);
+
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 3d383c8..dab03cd 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -58,6 +58,7 @@ static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr
static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBlockJob(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleDefaultEvent(qemuMonitorPtr mon, virJSONValuePtr data);
struct {
const char *type;
@@ -74,6 +75,7 @@ struct {
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
{ "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJob, },
+ { "DEFAULT_UNKNOW_EVENT", qemuMonitorJSONHandleDefaultEvent, },
};
@@ -83,6 +85,7 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
{
const char *type;
int i;
+ int findEventFlag = -1;
VIR_DEBUG("mon=%p obj=%p", mon, obj);
type = virJSONValueObjectGetString(obj, "event");
@@ -98,9 +101,24 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
VIR_DEBUG("handle %s handler=%p data=%p", type,
eventHandlers[i].handler, data);
(eventHandlers[i].handler)(mon, data);
+ findEventFlag = 0;
break;
}
}
+ if (findEventFlag != 0) {
+ if (!STREQ(eventHandlers[ARRAY_CARDINALITY(eventHandlers)-1].type, "DEFAULT_UNKNOW_EVENT")) {
+ VIR_ERROR("the last element is not the default event handler");
+ }
+ else {
+ char *event = NULL;
+ event = virJSONValueToString(obj);
+ if (event != NULL){
+ VIR_DEBUG("Unknow event,call default event handler %s",event);
+ free(event);
+ }
+ (eventHandlers[ARRAY_CARDINALITY(eventHandlers)-1].handler)(mon, obj);
+ }
+ }
return 0;
}
@@ -720,6 +738,19 @@ out:
}
+static void qemuMonitorJSONHandleDefaultEvent(qemuMonitorPtr mon, virJSONValuePtr data)
+{
+ char *defaultEventStr = NULL;
+ defaultEventStr = virJSONValueToString(data);
+ if (defaultEventStr == NULL){
+ VIR_ERROR("Can not get string form JSONValue");
+ return;
+ }
+ qemuMonitorEmitDefaultEvent(mon, defaultEventStr);
+ free(defaultEventStr);
+}
+
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
const char *cmd_str,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index a7fe86c..46881eb 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -713,6 +713,28 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
}
static int
+qemuProcessHandleDefaultEvent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm,
+ const char *rawEvent)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainEventPtr event = NULL;
+
+ virDomainObjLock(vm);
+ event = virDomainEventDefaultNewFromObj(vm, rawEvent);
+
+ virDomainObjUnlock(vm);
+
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
+
+static int
qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
int phase,
@@ -829,6 +851,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainIOError = qemuProcessHandleIOError,
.domainGraphics = qemuProcessHandleGraphics,
.domainBlockJob = qemuProcessHandleBlockJob,
+ .domainDefaultEvent = qemuProcessHandleDefaultEvent,
};
static int
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 2b2f41e..9648661 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -228,6 +228,11 @@ remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteDomainBuildEventDefaultEvent(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
remoteDomainBuildEventRTCChange,
@@ -265,6 +270,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
remoteDomainBuildEventBlockJob,
sizeof(remote_domain_event_block_job_msg),
(xdrproc_t)xdr_remote_domain_event_block_job_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_DEFAULT_EVENT,
+ remoteDomainBuildEventDefaultEvent,
+ sizeof(remote_domain_event_default_event_msg),
+ (xdrproc_t)xdr_remote_domain_event_default_event_msg },
};
enum virDrvOpenRemoteFlags {
@@ -3220,6 +3229,28 @@ remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
}
static void
+remoteDomainBuildEventDefaultEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_default_event_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventDefaultNewFromDom(dom, msg->rawEvent);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
+
+static void
remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque)
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index c8a92fd..81c6a4e 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2010,6 +2010,11 @@ struct remote_domain_event_block_job_msg {
int status;
};
+struct remote_domain_event_default_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string rawEvent;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
@@ -2525,7 +2530,8 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_MIGRATE_GET_MAX_SPEED = 242, /* autogen autogen */
REMOTE_PROC_DOMAIN_BLOCK_STATS_FLAGS = 243, /* skipgen skipgen */
REMOTE_PROC_DOMAIN_SNAPSHOT_GET_PARENT = 244, /* autogen autogen */
- REMOTE_PROC_DOMAIN_RESET = 245 /* autogen autogen */
+ REMOTE_PROC_DOMAIN_RESET = 245, /* autogen autogen */
+ REMOTE_PROC_DOMAIN_EVENT_DEFAULT_EVENT = 246 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 69175cc..7d0d0d4 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1509,6 +1509,10 @@ struct remote_domain_event_block_job_msg {
int type;
int status;
};
+struct remote_domain_event_default_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string rawEvent;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;
@@ -1971,4 +1975,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_BLOCK_STATS_FLAGS = 243,
REMOTE_PROC_DOMAIN_SNAPSHOT_GET_PARENT = 244,
REMOTE_PROC_DOMAIN_RESET = 245,
+ REMOTE_PROC_DOMAIN_EVENT_DEFAULT_EVENT = 246,
};
--
1.7.6
13 years
[libvirt] [PATCH] migration: Add more specific error code/message on migration abort
by Peter Krempa
A generic error code was returned, if the user aborted a migration job.
This made it hard to distinguish between a user requested abort and an
error that might have occured. This patch introduces a new error code,
which is returned if a migration API call fails. This makes it easier to
distinguish between failure while mirgrating and an user requested
abort.
* include/libvirt/virterror.h: - add new error code
* src/util/virterror.c: - add message for the new error code
* src/qemu/qemu_migration.h: - Emit operation aborted error instead of
operation failed, on migration abort
---
include/libvirt/virterror.h | 2 ++
src/qemu/qemu_migration.c | 2 +-
src/util/virterror.c | 6 ++++++
3 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 7063ef6..e896d67 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -241,6 +241,8 @@ typedef enum {
VIR_ERR_STORAGE_POOL_BUILT = 76, /* storage pool already built */
VIR_ERR_SNAPSHOT_REVERT_RISKY = 77, /* force was not requested for a
risky domain snapshot revert */
+ VIR_ERR_OPERATION_ABORTED = 78, /* operation on a domain was
+ canceled/aborted by user */
} virErrorNumber;
/**
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 8c4ecc8..7e4135b 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -905,7 +905,7 @@ qemuMigrationUpdateJobStatus(struct qemud_driver *driver,
case QEMU_MONITOR_MIGRATION_STATUS_CANCELLED:
priv->job.info.type = VIR_DOMAIN_JOB_CANCELLED;
- qemuReportError(VIR_ERR_OPERATION_FAILED,
+ qemuReportError(VIR_ERR_OPERATION_ABORTED,
_("%s: %s"), job, _("canceled by client"));
break;
}
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 44a276a..380dc56 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -1213,6 +1213,12 @@ virErrorMsg(virErrorNumber error, const char *info)
else
errmsg = _("revert requires force: %s");
break;
+ case VIR_ERR_OPERATION_ABORTED:
+ if (info == NULL)
+ errmsg = _("operation aborted");
+ else
+ errmsg = _("operation aborted: %s");
+ break;
}
return (errmsg);
}
--
1.7.3.4
13 years
[libvirt] [PATCH] qemu: detect truncated file as invalid save image
by Eric Blake
If managed save fails at the right point in time, then the save
image can end up with 0 bytes in length (no valid header), and
our attempts in commit 55d88def to detect and skip invalid save
files missed this case.
* src/qemu/qemu_driver.c (qemuDomainSaveImageOpen): Also unlink
empty file as corrupt. Reported by Dennis Householder.
---
src/qemu/qemu_driver.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 725b593..0d99ce4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3852,6 +3852,15 @@ qemuDomainSaveImageOpen(struct qemud_driver *driver,
goto error;
if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
+ if (unlink_corrupt) {
+ if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
+ virReportSystemError(errno,
+ _("cannot remove corrupt file: %s"),
+ path);
+ goto error;
+ }
+ return -3;
+ }
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("failed to read qemu header"));
goto error;
--
1.7.7.4
13 years
[libvirt] [PATCH] qemu: Don't drop hostdev config until security label restore
by Michal Privoznik
Currently, on device detach, we parse given XML, find the device
in domain object, free it and try to restore security labels.
However, in some cases (e.g. usb hostdev) parsed XML contains
less information than freed device. In usb case it is bus & device
IDs. These are needed during label restoring as a symlink into
/dev/bus is generated from them. Therefore don't drop device
configuration until security labels are restored.
---
src/qemu/qemu_hotplug.c | 38 ++++++++++++++++++++++++++------------
src/qemu/qemu_hotplug.h | 6 ------
2 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index b28a8cb..4067bb0 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1952,9 +1952,11 @@ cleanup:
return ret;
}
-int qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
- virDomainObjPtr vm,
- virDomainDeviceDefPtr dev)
+static int
+qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev,
+ virDomainHostdevDefPtr *detach_ret)
{
virDomainHostdevDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -2050,14 +2052,19 @@ int qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
VIR_FREE(vm->def->hostdevs);
vm->def->nhostdevs = 0;
}
- virDomainHostdevDefFree(detach);
+ if (detach_ret)
+ *detach_ret = detach;
+ else
+ virDomainHostdevDefFree(detach);
return ret;
}
-int qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
- virDomainObjPtr vm,
- virDomainDeviceDefPtr dev)
+static int
+qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virDomainDeviceDefPtr dev,
+ virDomainHostdevDefPtr *detach_ret)
{
virDomainHostdevDefPtr detach = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -2129,7 +2136,10 @@ int qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
VIR_FREE(vm->def->hostdevs);
vm->def->nhostdevs = 0;
}
- virDomainHostdevDefFree(detach);
+ if (detach_ret)
+ *detach_ret = detach;
+ else
+ virDomainHostdevDefFree(detach);
return ret;
}
@@ -2139,6 +2149,7 @@ int qemuDomainDetachHostDevice(struct qemud_driver *driver,
virDomainDeviceDefPtr dev)
{
virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+ virDomainHostdevDefPtr detach = NULL;
int ret;
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
@@ -2150,10 +2161,10 @@ int qemuDomainDetachHostDevice(struct qemud_driver *driver,
switch (hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
- ret = qemuDomainDetachHostPciDevice(driver, vm, dev);
+ ret = qemuDomainDetachHostPciDevice(driver, vm, dev, &detach);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
- ret = qemuDomainDetachHostUsbDevice(driver, vm, dev);
+ ret = qemuDomainDetachHostUsbDevice(driver, vm, dev, &detach);
break;
default:
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -2162,10 +2173,13 @@ int qemuDomainDetachHostDevice(struct qemud_driver *driver,
return -1;
}
- if (virSecurityManagerRestoreHostdevLabel(driver->securityManager,
- vm, dev->data.hostdev) < 0)
+ if (ret == 0 &&
+ virSecurityManagerRestoreHostdevLabel(driver->securityManager,
+ vm, detach) < 0)
VIR_WARN("Failed to restore host device labelling");
+ virDomainHostdevDefFree(detach);
+
return ret;
}
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 6c69225..0310361 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -92,12 +92,6 @@ int qemuDomainDetachPciControllerDevice(struct qemud_driver *driver,
int qemuDomainDetachNetDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev);
-int qemuDomainDetachHostPciDevice(struct qemud_driver *driver,
- virDomainObjPtr vm,
- virDomainDeviceDefPtr dev);
-int qemuDomainDetachHostUsbDevice(struct qemud_driver *driver,
- virDomainObjPtr vm,
- virDomainDeviceDefPtr dev);
int qemuDomainDetachHostDevice(struct qemud_driver *driver,
virDomainObjPtr vm,
virDomainDeviceDefPtr dev);
--
1.7.3.4
13 years
[libvirt] [PATCH v4] virsh: Add option to undefine storage with domains
by Peter Krempa
Add an option for virsh undefine command, to remove associated storage
volumes while undefining a domain. This patch allows the user to remove
associated (libvirt managed ) storage volumes while undefining a domain.
The new option --storage for the undefine command takes a string
argument that consists of comma separated list of target or source path
of volumes to be undefined. Volumes are removed after the domain has
been successfully undefined,
If a volume is not part of a storage pool, the user is warned to remove
the volume in question himself.
Option --wipe-storage may be specified along with this, that ensures
the image is wiped before removing.
Option --remove-all-storage enables the user to remove all storage. The
name is chosen long as the users should be aware what they're about to
do.
---
Changes to v3:
- fix ton'o'typos (I should install a spell checker.)
- add a new variable to hold copy of argument to avoid confusion,
typecasting ...
- break volume string into tokens just once and store it in an array
- add both target and source as volume description
( both are needed, as the user should know which volume he shoud
delete, if the domain vanishes )
- reformat argument string in man
- add example containing source path
tools/virsh.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 18 ++++++
2 files changed, 198 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index f6571f7..84b5e61 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -1924,6 +1924,13 @@ static const vshCmdInfo info_undefine[] = {
static const vshCmdOptDef opts_undefine[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name or uuid")},
{"managed-save", VSH_OT_BOOL, 0, N_("remove domain managed state file")},
+ {"storage", VSH_OT_DATA, VSH_OFLAG_NONE,
+ N_("remove associated storage volumes (comma separated list of targets "
+ "or source paths) (see domblklist)")},
+ {"remove-all-storage", VSH_OT_BOOL, 0,
+ N_("remove all associated storage volumes (use with caution)")},
+ {"wipe-storage", VSH_OT_BOOL, VSH_OFLAG_NONE,
+ N_("wipe data on the removed volumes")},
{"snapshots-metadata", VSH_OT_BOOL, 0,
N_("remove all domain snapshot metadata, if inactive")},
{NULL, 0, 0, NULL}
@@ -1940,6 +1947,9 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
/* User-requested actions. */
bool managed_save = vshCommandOptBool(cmd, "managed-save");
bool snapshots_metadata = vshCommandOptBool(cmd, "snapshots-metadata");
+ bool wipe_storage = vshCommandOptBool(cmd, "wipe-storage");
+ bool remove_storage = false;
+ bool remove_all_storage = vshCommandOptBool(cmd, "remove-all-storage");
/* Positive if these items exist. */
int has_managed_save = 0;
int has_snapshots_metadata = 0;
@@ -1949,6 +1959,24 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
bool snapshots_safe = false;
int rc = -1;
int running;
+ /* list of volumes to remove along with this domain */
+ const char *volumes_arg = NULL;
+ char *volumes = NULL;
+ char **volume_tokens = NULL;
+ char *volume_tok = NULL;
+ int nvolume_tokens = 0;
+ char *def = NULL;
+ char *source = NULL;
+ char *target = NULL;
+ int vol_i;
+ int tok_i;
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ xmlNodePtr *vol_nodes = NULL;
+ int nvolumes = 0;
+ virStorageVolPtr vol = NULL;
+ bool vol_del_failed = false;
if (managed_save) {
flags |= VIR_DOMAIN_UNDEFINE_MANAGED_SAVE;
@@ -1965,6 +1993,17 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
return false;
+ /* check if a string that should contain list of volumes to remove is present */
+ if (vshCommandOptString(cmd, "storage", &volumes_arg) > 0) {
+ volumes = vshStrdup(ctl, volumes_arg);
+
+ if (remove_all_storage) {
+ vshError(ctl, _("Specified both --storage and --remove-all-storage"));
+ goto cleanup;
+ }
+ remove_storage = true;
+ }
+
/* Do some flag manipulation. The goal here is to disable bits
* from flags to reduce the likelihood of a server rejecting
* unknown flag bits, as well as to track conditions which are
@@ -2027,6 +2066,20 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
snapshots_safe = true;
}
+ /* Stash domain description for later use */
+ if (remove_storage || remove_all_storage) {
+ if (running) {
+ vshError(ctl, _("Storage volume deletion is supported only on stopped domains"));
+ goto cleanup;
+ }
+
+ if (!(def = virDomainGetXMLDesc(dom, 0))) {
+ vshError(ctl, _("Could not retrieve domain XML description"));
+ goto cleanup;
+ }
+ }
+
/* Generally we want to try the new API first. However, while
* virDomainUndefineFlags was introduced at the same time as
* VIR_DOMAIN_UNDEFINE_MANAGED_SAVE in 0.9.4, the
@@ -2076,9 +2129,138 @@ out:
ret = true;
} else {
vshError(ctl, _("Failed to undefine domain %s"), name);
+ goto cleanup;
+ }
+
+ /* try to undefine storage volumes associated with this domain, if it's requested */
+ if (remove_storage || remove_all_storage) {
+ ret = false;
+
+ /* tokenize the string from user and save it's parts into an array */
+ if (volumes) {
+ /* count the delimiters */
+ volume_tok = volumes;
+ nvolume_tokens = 1; /* we need at least one member */
+ while (*volume_tok) {
+ if (*volume_tok == ',')
+ nvolume_tokens++;
+ volume_tok++;
+ }
+
+ volume_tokens = vshCalloc(ctl, nvolume_tokens, sizeof(char *));
+
+ /* tokenize the input string */
+ nvolume_tokens = 0;
+ volume_tok = volumes;
+ do {
+ volume_tokens[nvolume_tokens] = strsep(&volume_tok, ",");
+ nvolume_tokens++;
+ } while (volume_tok);
+ }
+
+ doc = virXMLParseStringCtxt(def, _("(domain_definition)"), &ctxt);
+ if (!doc)
+ goto cleanup;
+
+ nvolumes = virXPathNodeSet("./devices/disk", ctxt, &vol_nodes);
+
+ if (nvolumes < 0)
+ goto cleanup;
+
+ for (vol_i = 0; vol_i < nvolumes; vol_i++) {
+ ctxt->node = vol_nodes[vol_i];
+ VIR_FREE(target);
+ VIR_FREE(source);
+ if (vol) {
+ virStorageVolFree(vol);
+ vol = NULL;
+ }
+
+ /* get volume source and target paths */
+ if (!(target = virXPathString("string(./target/@dev)", ctxt))) {
+ vshError(ctl, _("Failed to enumerate devices"));
+ goto cleanup;
+ }
+
+ if (!(source = virXPathString("string("
+ "./source/@file|"
+ "./source/@dir|"
+ "./source/@name|"
+ "./source/@dev)", ctxt)) &&
+ virGetLastError())
+ goto cleanup;
+
+ /* lookup if volume was selected by user */
+ if (volumes) {
+ volume_tok = NULL;
+ for (tok_i = 0; tok_i < nvolume_tokens; tok_i++) {
+ if (volume_tokens[tok_i] &&
+ (STREQ_NULLABLE(volume_tokens[tok_i], target) ||
+ STREQ_NULLABLE(volume_tokens[tok_i], source))) {
+ volume_tok = volume_tokens[tok_i];
+ volume_tokens[tok_i] = NULL;
+ break;
+ }
+ }
+ if (!volume_tok)
+ continue;
+ }
+
+ if (!source)
+ continue;
+
+ if (!(vol = virStorageVolLookupByPath(ctl->conn, source))) {
+ vshPrint(ctl,
+ _("Storage volume '%s'(%s) is not managed by libvirt. "
+ "Remove it manually.\n"), target, source);
+ virResetLastError();
+ continue;
+ }
+
+ if (wipe_storage) {
+ vshPrint(ctl, _("Wiping volume '%s'(%s) ... "), target, source);
+ fflush(stdout);
+ if (virStorageVolWipe(vol, 0) < 0) {
+ vshError(ctl, _("Failed! Volume not removed."));
+ vol_del_failed = true;
+ continue;
+ } else {
+ vshPrint(ctl, _("Done.\n"));
+ }
+ }
+
+ /* delete the volume */
+ if (virStorageVolDelete(vol, 0) < 0) {
+ vshError(ctl, _("Failed to remove storage volume '%s'(%s)"),
+ target, source);
+ vol_del_failed = true;
+ }
+ vshPrint(ctl, _("Volume '%s' removed.\n"), volume_tok?volume_tok:source);
+ }
+
+ /* print volumes specified by user that were not found in domain definition */
+ if (volumes) {
+ for (tok_i = 0; tok_i < nvolume_tokens; tok_i++) {
+ if (volume_tokens[tok_i])
+ vshPrint(ctl, _("Volume '%s' was not found in domain's "
+ "definition.\n"),
+ volume_tokens[tok_i]);
+ }
+ }
+
+ if (!vol_del_failed)
+ ret = true;
}
cleanup:
+ VIR_FREE(source);
+ VIR_FREE(target);
+ VIR_FREE(volumes);
+ VIR_FREE(volume_tokens);
+ VIR_FREE(def);
+ VIR_FREE(vol_nodes);
+ xmlFreeDoc(doc);
+ xmlXPathFreeContext(ctxt);
virDomainFree(dom);
return ret;
}
diff --git a/tools/virsh.pod b/tools/virsh.pod
index c468f13..3976166 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1181,6 +1181,7 @@ Output the device used for the TTY console of the domain. If the information
is not available the processes will provide an exit code of 1.
=item B<undefine> I<domain-id> [I<--managed-save>] [I<--snapshots-metadata>]
+[I<--storage> B<volumes> | I<--remove-all-storage> I<--wipe-storage>]
Undefine a domain. If the domain is running, this converts it to a
transient domain, without stopping it. If the domain is inactive,
@@ -1196,6 +1197,23 @@ domain. Without the flag, attempts to undefine an inactive domain with
snapshot metadata will fail. If the domain is active, this flag is
ignored.
+The I<--storage> flag takes a parameter B<volumes>, that is a comma separated
+list of volume target names or source paths of storage volumes to be removed
+along with the undefined domain. Volumes can be undefined and thus removed only
+on inactive domains. Volume deletion is only attempted after the domain is
+undefined; if not all of the requested volumes could be deleted, the
+error message indicates what still remains behind. If a volume path is not
+found in the domain definition, it's treated as if the volume was successfully
+deleteted.
+(See B<domblklist> for list of target names associated to a domain).
+Example: --storage vda,/path/to/storage.img
+
+The I<--remove-all-storage> flag specifies that all of the domain's storage
+volumes should be deleted.
+
+The flag I<--wipe-storage> specifies that the storage volumes should be
+wiped before removal.
+
NOTE: For an inactive domain, the domain name or UUID must be used as the
I<domain-id>.
--
1.7.3.4
13 years
[libvirt] possible 0.9.8 regression?
by Jim Fehlig
Hi All,
I've noticed a regression in libvirt 0.9.8 on some of my kvm test machines
# virsh start opensuse12
error: Failed to start domain opensuse12
error: Cannot open network interface control socket: Permission denied
Opening a control socket for setting MAC addr, etc. failed with EACCES.
In 0.9.7, the socket was opened with domain AF_INET, type SOCK_STREAM,
which of course works on this system. In 0.9.8, the socket is opened
with AF_PACKET, SOCK_DGRAM. Interestingly, a small test program calling
'socket(AF_PACKET, SOCK_DGRAM, 0)' works on this system.
libvirt is built with '--without-capng --without-apparmor
--without-selinux' and libvirtd is running with uid=euid=0.
I'm really baffled why this fails in libvirtd but works otherwise. Any
ideas?
Thanks,
Jim
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
int main(int argc, char **argv)
{
int fd;
printf("Testing socket(2)...\n");
printf("Opening AF_INET, SOCK_STREAM socket\n");
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
printf("socket(2) failed with %s\n", strerror(errno));
exit(1);
}
close(fd);
printf("Opening AF_PACKET, SOCK_DGRAM socket\n");
fd = socket(AF_PACKET, SOCK_DGRAM, 0);
if (fd < 0) {
printf("socket(2) failed with %s\n", strerror(errno));
exit(1);
}
close(fd);
printf("Done!\n");
exit(0);
}
13 years
[libvirt] [PATCH] Fix default migration speed in qemu driver
by Jim Fehlig
In commit 6f84e110 I mistakenly set default migration speed to
33554432 Mb! The units of migMaxBandwidth is Mb, with conversion
handled in qemuMonitor{JSON,Text}SetMigrationSpeed().
Also, remove definition of QEMU_DOMAIN_FILE_MIG_BANDWIDTH_MAX since
it is no longer used after reverting commit ef1065cf.
---
src/qemu/qemu_domain.h | 9 +--------
1 files changed, 1 insertions(+), 8 deletions(-)
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 35f9440..f40fa09 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -36,14 +36,7 @@
(1 << VIR_DOMAIN_VIRT_KVM) | \
(1 << VIR_DOMAIN_VIRT_XEN))
-# define QEMU_DOMAIN_DEFAULT_MIG_BANDWIDTH_MAX (32 << 20)
-# if ULONG_MAX == 4294967295
-/* Qemu has a 64-bit limit, but we are limited by our historical choice of
- * representing bandwidth in a long instead of a 64-bit int. */
-# define QEMU_DOMAIN_FILE_MIG_BANDWIDTH_MAX ULONG_MAX
-# else
-# define QEMU_DOMAIN_FILE_MIG_BANDWIDTH_MAX (INT64_MAX / (1024 * 1024))
-# endif
+# define QEMU_DOMAIN_DEFAULT_MIG_BANDWIDTH_MAX 32
# define JOB_MASK(job) (1 << (job - 1))
# define DEFAULT_JOB_MASK \
--
1.7.7
13 years
[libvirt] Need source for sanlock and libvirt-lock-sanlock
by Upendra Moturi
Hello
Can some please point me the location of sanlock and
libvirt-lock-sanlock source.
And also install them from source.
--
Thanks and Regards,
Upendra.M
As a leading developer of IT infrastructure software solutions,
Hexagrid developed the first cloud computing platform that directly
aligns with the real-world IT delivery models of both solution
providers and enterprises. Hexagrid provides all the software and
support that IT organizations need to successfully build public,
private, or hybrid clouds that fit their specific business and
end-user requirements. Hexagrid cloud solutions truly simplify and
expedite virtual IT management, empowering successful cloud computing
strategies that quickly increase profits by pooling resources,
delivering control, and building value. Our Software, Your Cloud. For
more information, visit www.hexagrid.com and follow @Hexagrid on
Twitter
13 years
[libvirt] [libvirt-glib] Add annotations for gvir_stream_add_watch{_full}
by Christophe Fergeau
This should silence this compile warning:
GEN LibvirtGObject-1.0.gir
libvirt-gobject-stream.c:603: Warning: LibvirtGObject:
gvir_stream_add_watch: argument func: Missing (scope) annotation for
callback without GDestroyNotify (valid: call, async)
This also adds API documentation for these functions.
---
libvirt-gobject/libvirt-gobject-stream.c | 26 ++++++++++++++++++++++++++
1 files changed, 26 insertions(+), 0 deletions(-)
diff --git a/libvirt-gobject/libvirt-gobject-stream.c b/libvirt-gobject/libvirt-gobject-stream.c
index 6d8bbb8..6b75819 100644
--- a/libvirt-gobject/libvirt-gobject-stream.c
+++ b/libvirt-gobject/libvirt-gobject-stream.c
@@ -613,6 +613,18 @@ GSourceFuncs gvir_stream_source_funcs = {
.finalize = gvir_stream_source_finalize,
};
+
+/**
+ * gvir_stream_add_watch: (skip):
+ * @stream: the stream
+ * @cond: the conditions to watch for (bitfield of #GVirStreamIOCondition)
+ * @func: (closure opaque): the function to call when the condition is satisfied
+ * @opaque: (closure): user data to pass to @func
+ *
+ * Adds a watch for @stream to the mainloop
+ *
+ * Returns: the event source id
+ */
guint gvir_stream_add_watch(GVirStream *stream,
GVirStreamIOCondition cond,
GVirStreamIOFunc func,
@@ -626,6 +638,20 @@ guint gvir_stream_add_watch(GVirStream *stream,
NULL);
}
+/**
+ * gvir_stream_add_watch_full:
+ * @stream: the stream
+ * @priority: the priority of the #GVirStream source
+ * @cond: the conditions to watch for (bitfield of #GVirStreamIOCondition)
+ * @func: (closure opaque): the function to call when the condition is satisfied
+ * @opaque: (closure): user data to pass to @func
+ * @notify: the function to call when the source is removed
+ *
+ * Adds a watch for @stream to the mainloop
+ *
+ * Returns: the event source id
+ * Rename to: gvir_stream_add_watch
+ */
guint gvir_stream_add_watch_full(GVirStream *stream,
gint priority,
GVirStreamIOCondition cond,
--
1.7.7.3
13 years