[libvirt] [PATCH 00/16] Misc fixes and refactoring of LXC driver

The first 7 patches in this series are a set of misc fixes I identified while working on the LXC driver code. The remaining 9 patches heavily re-arrange, re-factor and re-name the LXC driver code. The intent is to make the code layout closer in style to the QEMU driver, to facilitate its future growth in size & complexity

From: "Daniel P. Berrange" <berrange@redhat.com> Turning on the building of driver modules in libvirt.spec.in means that installing 'libvirt' no longer pulls in all the drivers. For upgrade compatibility we need to list all drivers module sub-RPMs against the 'libvirt' RPM. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- libvirt.spec.in | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libvirt.spec.in b/libvirt.spec.in index ec2b3b4..3f6382b 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -320,8 +320,18 @@ Requires: libvirt-daemon-config-network = %{version}-%{release} %if %{with_nwfilter} Requires: libvirt-daemon-config-nwfilter = %{version}-%{release} %endif -# XXX when we turn on driver modules, we need to add -# deps on each driver (Requires: libvirt-daemon-drv-qemu) +Requires: libvirt-daemon-driver-libxl = %{version}-%{release} +Requires: libvirt-daemon-driver-lxc = %{version}-%{release} +Requires: libvirt-daemon-driver-qemu = %{version}-%{release} +Requires: libvirt-daemon-driver-uml = %{version}-%{release} +Requires: libvirt-daemon-driver-xen = %{version}-%{release} + +Requires: libvirt-daemon-driver-interface = %{version}-%{release} +Requires: libvirt-daemon-driver-secret = %{version}-%{release} +Requires: libvirt-daemon-driver-storage = %{version}-%{release} +Requires: libvirt-daemon-driver-network = %{version}-%{release} +Requires: libvirt-daemon-driver-nodedev = %{version}-%{release} +Requires: libvirt-daemon-driver-nwfilter = %{version}-%{release} %endif Requires: libvirt-client = %{version}-%{release} -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:22PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Turning on the building of driver modules in libvirt.spec.in means that installing 'libvirt' no longer pulls in all the drivers. For upgrade compatibility we need to list all drivers module sub-RPMs against the 'libvirt' RPM.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- libvirt.spec.in | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in index ec2b3b4..3f6382b 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -320,8 +320,18 @@ Requires: libvirt-daemon-config-network = %{version}-%{release} %if %{with_nwfilter} Requires: libvirt-daemon-config-nwfilter = %{version}-%{release} %endif -# XXX when we turn on driver modules, we need to add -# deps on each driver (Requires: libvirt-daemon-drv-qemu) +Requires: libvirt-daemon-driver-libxl = %{version}-%{release} +Requires: libvirt-daemon-driver-lxc = %{version}-%{release} +Requires: libvirt-daemon-driver-qemu = %{version}-%{release} +Requires: libvirt-daemon-driver-uml = %{version}-%{release} +Requires: libvirt-daemon-driver-xen = %{version}-%{release} + +Requires: libvirt-daemon-driver-interface = %{version}-%{release} +Requires: libvirt-daemon-driver-secret = %{version}-%{release} +Requires: libvirt-daemon-driver-storage = %{version}-%{release} +Requires: libvirt-daemon-driver-network = %{version}-%{release} +Requires: libvirt-daemon-driver-nodedev = %{version}-%{release} +Requires: libvirt-daemon-driver-nwfilter = %{version}-%{release} %endif Requires: libvirt-client = %{version}-%{release}
ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> When sending SIGHUP to libvirtd, it will trigger the virStateDriver reload operation. This is intended to reload the configuration files for guests. For unknown historical reasons this is also triggering autostart of all guests. Autostart is generally expected to be something that happens on OS startup. Starting VMs on SIGHUP will violate that expectation and potentially cause dangerous scenarios if the admin has explicitly shutdown a misbehaving VM that has been marked as autostart Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/lxc/lxc_driver.c | 2 -- src/qemu/qemu_driver.c | 2 -- src/uml/uml_driver.c | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 2d931db..c341125 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2750,8 +2750,6 @@ lxcReload(void) { lxcNotifyLoadDomain, lxc_driver); lxcDriverUnlock(lxc_driver); - lxcAutostartConfigs(lxc_driver); - return 0; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d3988b8..46000f4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -805,8 +805,6 @@ qemudReload(void) { qemudNotifyLoadDomain, qemu_driver); qemuDriverUnlock(qemu_driver); - qemuAutostartDomains(qemu_driver); - return 0; } diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 098ee7b..b8d0ab7 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -553,8 +553,6 @@ umlReload(void) { umlNotifyLoadDomain, uml_driver); umlDriverUnlock(uml_driver); - umlAutostartConfigs(uml_driver); - return 0; } -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:23PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
When sending SIGHUP to libvirtd, it will trigger the virStateDriver reload operation. This is intended to reload the configuration files for guests. For unknown historical reasons this is also triggering autostart of all guests. Autostart is generally expected to be something that happens on OS startup. Starting VMs on SIGHUP will violate that expectation and potentially cause dangerous scenarios if the admin has explicitly shutdown a misbehaving VM that has been marked as autostart
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/lxc/lxc_driver.c | 2 -- src/qemu/qemu_driver.c | 2 -- src/uml/uml_driver.c | 2 -- 3 files changed, 6 deletions(-)
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 2d931db..c341125 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -2750,8 +2750,6 @@ lxcReload(void) { lxcNotifyLoadDomain, lxc_driver); lxcDriverUnlock(lxc_driver);
- lxcAutostartConfigs(lxc_driver); - return 0; }
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d3988b8..46000f4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -805,8 +805,6 @@ qemudReload(void) { qemudNotifyLoadDomain, qemu_driver); qemuDriverUnlock(qemu_driver);
- qemuAutostartDomains(qemu_driver); - return 0; }
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 098ee7b..b8d0ab7 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -553,8 +553,6 @@ umlReload(void) { umlNotifyLoadDomain, uml_driver); umlDriverUnlock(uml_driver);
- umlAutostartConfigs(uml_driver); - return 0; }
Okay, in any case it's a bug. The chances to find out why that was introduced in the first place is more likely if we push the fix and test. ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> Allow detection of EOF in virNetClient via an callback function, triggered from the socket event handler Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/rpc/virnetclient.c | 43 +++++++++++++++++++++++++++++++++++++++---- src/rpc/virnetclient.h | 8 ++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index f877934..326efb2 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -101,6 +101,11 @@ struct _virNetClient { virKeepAlivePtr keepalive; bool wantClose; + + + virNetClientEOFCallback eofCb; + void *eofOpaque; + virFreeCallback eofFf; }; @@ -122,6 +127,19 @@ static void virNetClientUnlock(virNetClientPtr client) } +void virNetClientSetEOFNotify(virNetClientPtr client, + virNetClientEOFCallback cb, + void *opaque, + virFreeCallback ff) +{ + virNetClientLock(client); + client->eofCb = cb; + client->eofOpaque = opaque; + client->eofFf = ff; + virNetClientUnlock(client); +} + + static void virNetClientIncomingEvent(virNetSocketPtr sock, int events, void *opaque); @@ -460,6 +478,9 @@ void virNetClientFree(virNetClientPtr client) return; } + if (client->eofFf && client->eofOpaque) + client->eofFf(client->eofOpaque); + for (i = 0 ; i < client->nprograms ; i++) virNetClientProgramFree(client->programs[i]); VIR_FREE(client->programs); @@ -1636,17 +1657,21 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); virNetSocketRemoveIOCallback(sock); - goto done; + goto eof; } if (events & VIR_EVENT_HANDLE_WRITABLE) { - if (virNetClientIOHandleOutput(client) < 0) + if (virNetClientIOHandleOutput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } } if (events & VIR_EVENT_HANDLE_READABLE) { - if (virNetClientIOHandleInput(client) < 0) + if (virNetClientIOHandleInput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } } /* Remove completed calls or signal their threads. */ @@ -1655,8 +1680,18 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, NULL); virNetClientIOUpdateCallback(client, true); -done: virNetClientUnlock(client); + +done: + return; + +eof: + if (client->eofCb) { + virNetClientEOFCallback eofCb = client->eofCb; + void *eofOpaque = client->eofOpaque; + virNetClientUnlock(client); + eofCb(client, eofOpaque); + } } diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h index 13b4f96..6e9219a 100644 --- a/src/rpc/virnetclient.h +++ b/src/rpc/virnetclient.h @@ -51,6 +51,14 @@ virNetClientPtr virNetClientNewSSH(const char *nodename, virNetClientPtr virNetClientNewExternal(const char **cmdargv); +typedef void (*virNetClientEOFCallback)(virNetClientPtr client, + void *opaque); + +void virNetClientSetEOFNotify(virNetClientPtr client, + virNetClientEOFCallback cb, + void *opaque, + virFreeCallback ff); + void virNetClientRef(virNetClientPtr client); int virNetClientGetFD(virNetClientPtr client); -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:24PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Allow detection of EOF in virNetClient via an callback function, triggered from the socket event handler
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/rpc/virnetclient.c | 43 +++++++++++++++++++++++++++++++++++++++---- src/rpc/virnetclient.h | 8 ++++++++ 2 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index f877934..326efb2 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -101,6 +101,11 @@ struct _virNetClient {
virKeepAlivePtr keepalive; bool wantClose; + + + virNetClientEOFCallback eofCb; + void *eofOpaque; + virFreeCallback eofFf; };
Initialized to NULL by virtue of VIR_ALLOC() in virNetClientNew()
@@ -122,6 +127,19 @@ static void virNetClientUnlock(virNetClientPtr client) }
+void virNetClientSetEOFNotify(virNetClientPtr client, + virNetClientEOFCallback cb, + void *opaque, + virFreeCallback ff) +{ + virNetClientLock(client); + client->eofCb = cb; + client->eofOpaque = opaque; + client->eofFf = ff; + virNetClientUnlock(client); +} + + static void virNetClientIncomingEvent(virNetSocketPtr sock, int events, void *opaque); @@ -460,6 +478,9 @@ void virNetClientFree(virNetClientPtr client) return; }
+ if (client->eofFf && client->eofOpaque) + client->eofFf(client->eofOpaque); + for (i = 0 ; i < client->nprograms ; i++) virNetClientProgramFree(client->programs[i]); VIR_FREE(client->programs); @@ -1636,17 +1657,21 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); virNetSocketRemoveIOCallback(sock); - goto done; + goto eof; }
if (events & VIR_EVENT_HANDLE_WRITABLE) { - if (virNetClientIOHandleOutput(client) < 0) + if (virNetClientIOHandleOutput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } }
if (events & VIR_EVENT_HANDLE_READABLE) { - if (virNetClientIOHandleInput(client) < 0) + if (virNetClientIOHandleInput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } }
What about the case ? if (client->haveTheBuck || client->wantClose) ? sure it's induced locally instead of getting raised by an eof
/* Remove completed calls or signal their threads. */ @@ -1655,8 +1680,18 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, NULL); virNetClientIOUpdateCallback(client, true);
-done: virNetClientUnlock(client); + +done: + return; + +eof: + if (client->eofCb) { + virNetClientEOFCallback eofCb = client->eofCb; + void *eofOpaque = client->eofOpaque; + virNetClientUnlock(client); + eofCb(client, eofOpaque); + } }
diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h index 13b4f96..6e9219a 100644 --- a/src/rpc/virnetclient.h +++ b/src/rpc/virnetclient.h @@ -51,6 +51,14 @@ virNetClientPtr virNetClientNewSSH(const char *nodename,
virNetClientPtr virNetClientNewExternal(const char **cmdargv);
+typedef void (*virNetClientEOFCallback)(virNetClientPtr client, + void *opaque); + +void virNetClientSetEOFNotify(virNetClientPtr client, + virNetClientEOFCallback cb, + void *opaque, + virFreeCallback ff); + void virNetClientRef(virNetClientPtr client);
int virNetClientGetFD(virNetClientPtr client);
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Jul 19, 2012 at 04:18:33PM +0800, Daniel Veillard wrote:
@@ -1636,17 +1657,21 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); virNetSocketRemoveIOCallback(sock); - goto done; + goto eof; }
if (events & VIR_EVENT_HANDLE_WRITABLE) { - if (virNetClientIOHandleOutput(client) < 0) + if (virNetClientIOHandleOutput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } }
if (events & VIR_EVENT_HANDLE_READABLE) { - if (virNetClientIOHandleInput(client) < 0) + if (virNetClientIOHandleInput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } }
What about the case ? if (client->haveTheBuck || client->wantClose) ? sure it's induced locally instead of getting raised by an eof
If either of those conditions are true, the virNetClientIncomingEvent method should not be invoked - we just have a check for those at the top as a sanity check. In the haveTheBuck==true case, this callback will be activated again once the buck is released, so we'll deal with EOF callbacks correctly. In the wantClose==true case, we might miss out invoking the EOF callback - I suspect this is only a problem if the app code explicitly asked for a close itself, or if the keepalive code triggers. I'll check into this and if there are any fixes required, I'll do them as a followup patch. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Thu, Jul 19, 2012 at 09:58:58AM +0100, Daniel P. Berrange wrote:
On Thu, Jul 19, 2012 at 04:18:33PM +0800, Daniel Veillard wrote:
@@ -1636,17 +1657,21 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); virNetSocketRemoveIOCallback(sock); - goto done; + goto eof; }
if (events & VIR_EVENT_HANDLE_WRITABLE) { - if (virNetClientIOHandleOutput(client) < 0) + if (virNetClientIOHandleOutput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } }
if (events & VIR_EVENT_HANDLE_READABLE) { - if (virNetClientIOHandleInput(client) < 0) + if (virNetClientIOHandleInput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } }
What about the case ? if (client->haveTheBuck || client->wantClose) ? sure it's induced locally instead of getting raised by an eof
If either of those conditions are true, the virNetClientIncomingEvent method should not be invoked - we just have a check for those at the top as a sanity check. In the haveTheBuck==true case, this callback will be activated again once the buck is released, so we'll deal with EOF callbacks correctly. In the wantClose==true case, we might miss out invoking the EOF callback - I suspect this is only a problem if the app code explicitly asked for a close itself, or if the keepalive code triggers.
I'll check into this and if there are any fixes required, I'll do them as a followup patch.
Okay, ACK ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Jul 19, 2012 at 05:44:13PM +0800, Daniel Veillard wrote:
On Thu, Jul 19, 2012 at 09:58:58AM +0100, Daniel P. Berrange wrote:
On Thu, Jul 19, 2012 at 04:18:33PM +0800, Daniel Veillard wrote:
@@ -1636,17 +1657,21 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); virNetSocketRemoveIOCallback(sock); - goto done; + goto eof; }
if (events & VIR_EVENT_HANDLE_WRITABLE) { - if (virNetClientIOHandleOutput(client) < 0) + if (virNetClientIOHandleOutput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } }
if (events & VIR_EVENT_HANDLE_READABLE) { - if (virNetClientIOHandleInput(client) < 0) + if (virNetClientIOHandleInput(client) < 0) { virNetSocketRemoveIOCallback(sock); + goto eof; + } }
What about the case ? if (client->haveTheBuck || client->wantClose) ? sure it's induced locally instead of getting raised by an eof
If either of those conditions are true, the virNetClientIncomingEvent method should not be invoked - we just have a check for those at the top as a sanity check. In the haveTheBuck==true case, this callback will be activated again once the buck is released, so we'll deal with EOF callbacks correctly. In the wantClose==true case, we might miss out invoking the EOF callback - I suspect this is only a problem if the app code explicitly asked for a close itself, or if the keepalive code triggers.
I'll check into this and if there are any fixes required, I'll do them as a followup patch.
Okay, ACK !
Actually based on Jiri's comments, I'll hold off pushing this and post a new version. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Wed, Jul 18, 2012 at 17:32:24 +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Allow detection of EOF in virNetClient via an callback function, triggered from the socket event handler
EOF callback is nice but since we have keepalive, sockets can also be closed by clients without actually triggering EOF. Should we rather implement a virNetClientCloseCallback with a parameter that would indicate whether the socket was closed externally (EOF) or internally (keepalive)? Such callback could even be visible to apps as a public API so that they are notified about closed connection even when they have no pending call. Jirka

On Thu, Jul 19, 2012 at 10:59:40AM +0200, Jiri Denemark wrote:
On Wed, Jul 18, 2012 at 17:32:24 +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Allow detection of EOF in virNetClient via an callback function, triggered from the socket event handler
EOF callback is nice but since we have keepalive, sockets can also be closed by clients without actually triggering EOF. Should we rather implement a virNetClientCloseCallback with a parameter that would indicate whether the socket was closed externally (EOF) or internally (keepalive)? Such callback could even be visible to apps as a public API so that they are notified about closed connection even when they have no pending call.
Hmm, yes, I had considered whether we could make this available to the public API to avoid virt-manager needing the hacks it currently does. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

From: "Daniel P. Berrange" <berrange@redhat.com> In the delayed close mode, we're just waiting for final data to be written back to the client. While waiting, we should not bother to read more data from the client. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/rpc/virnetserverclient.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 30f0cc8..d6b348b 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -152,9 +152,10 @@ virNetServerClientCalculateHandleMode(virNetServerClientPtr client) { mode |= VIR_EVENT_HANDLE_WRITABLE; } } else { - /* If there is a message on the rx queue then + /* If there is a message on the rx queue, and + * we're not in middle of a delayedClose, then * we're wanting more input */ - if (client->rx) + if (client->rx && !client->delayedClose) mode |= VIR_EVENT_HANDLE_READABLE; /* If there are one or more messages to send back to client, -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:25PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
In the delayed close mode, we're just waiting for final data to be written back to the client. While waiting, we should not bother to read more data from the client.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/rpc/virnetserverclient.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 30f0cc8..d6b348b 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -152,9 +152,10 @@ virNetServerClientCalculateHandleMode(virNetServerClientPtr client) { mode |= VIR_EVENT_HANDLE_WRITABLE; } } else { - /* If there is a message on the rx queue then + /* If there is a message on the rx queue, and + * we're not in middle of a delayedClose, then * we're wanting more input */ - if (client->rx) + if (client->rx && !client->delayedClose) mode |= VIR_EVENT_HANDLE_READABLE;
/* If there are one or more messages to send back to client,
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> To allow virNetServerRun/virNetServerQuit to be invoked multiple times, we must reset the 'quit' flag in virNetServerRun Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/rpc/virnetserver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 16846c5..257cef7 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -700,6 +700,8 @@ void virNetServerRun(virNetServerPtr srv) goto cleanup; #endif + srv->quit = 0; + if (srv->autoShutdownTimeout && (timerid = virEventAddTimeout(-1, virNetServerAutoShutdownTimer, -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:26PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
To allow virNetServerRun/virNetServerQuit to be invoked multiple times, we must reset the 'quit' flag in virNetServerRun
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/rpc/virnetserver.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 16846c5..257cef7 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -700,6 +700,8 @@ void virNetServerRun(virNetServerPtr srv) goto cleanup; #endif
+ srv->quit = 0; + if (srv->autoShutdownTimeout && (timerid = virEventAddTimeout(-1, virNetServerAutoShutdownTimer,
ACK, we have the lock there, fine, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> In the socket event handler for the RPC client we must deal with read/write events, before checking for EOF, otherwise we might close the socket before we've read & acted upon the last RPC messages Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/rpc/virnetclient.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 326efb2..ec82da7 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -1653,13 +1653,6 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, VIR_DEBUG("Event fired %p %d", sock, events); - if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) { - VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " - "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); - virNetSocketRemoveIOCallback(sock); - goto eof; - } - if (events & VIR_EVENT_HANDLE_WRITABLE) { if (virNetClientIOHandleOutput(client) < 0) { virNetSocketRemoveIOCallback(sock); @@ -1674,6 +1667,13 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, } } + if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) { + VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " + "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); + virNetSocketRemoveIOCallback(sock); + goto eof; + } + /* Remove completed calls or signal their threads. */ virNetClientCallRemovePredicate(&client->waitDispatch, virNetClientIOEventLoopRemoveDone, @@ -1687,6 +1687,7 @@ done: eof: if (client->eofCb) { + VIR_DEBUG("EOF %p %d", sock, events); virNetClientEOFCallback eofCb = client->eofCb; void *eofOpaque = client->eofOpaque; virNetClientUnlock(client); -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:27PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
In the socket event handler for the RPC client we must deal with read/write events, before checking for EOF, otherwise we might close the socket before we've read & acted upon the last RPC messages
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/rpc/virnetclient.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 326efb2..ec82da7 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -1653,13 +1653,6 @@ void virNetClientIncomingEvent(virNetSocketPtr sock,
VIR_DEBUG("Event fired %p %d", sock, events);
- if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) { - VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " - "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); - virNetSocketRemoveIOCallback(sock); - goto eof; - } - if (events & VIR_EVENT_HANDLE_WRITABLE) { if (virNetClientIOHandleOutput(client) < 0) { virNetSocketRemoveIOCallback(sock); @@ -1674,6 +1667,13 @@ void virNetClientIncomingEvent(virNetSocketPtr sock, } }
+ if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) { + VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " + "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); + virNetSocketRemoveIOCallback(sock); + goto eof; + } + /* Remove completed calls or signal their threads. */ virNetClientCallRemovePredicate(&client->waitDispatch, virNetClientIOEventLoopRemoveDone, @@ -1687,6 +1687,7 @@ done:
eof: if (client->eofCb) { + VIR_DEBUG("EOF %p %d", sock, events); virNetClientEOFCallback eofCb = client->eofCb; void *eofOpaque = client->eofOpaque; virNetClientUnlock(client);
ACK, context depends on 3/16 Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> Make sure that libvirt_private.syms has all the internal symbols from APIs in src/rpc/*.h and src/util/cgroup.h, since the LXC controller/driver will shortly need them Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/libvirt_private.syms | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 03f7f3e..734c881 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -60,11 +60,14 @@ virCapabilitiesSetMacPrefix; # cgroup.h virCgroupAddTask; +virCgroupAllowDevice; virCgroupAllowDeviceMajor; virCgroupAllowDevicePath; virCgroupControllerTypeFromString; virCgroupControllerTypeToString; virCgroupDenyAllDevices; +virCgroupDenyDevice; +virCgroupDenyDeviceMajor; virCgroupDenyDevicePath; virCgroupForDomain; virCgroupForDriver; @@ -1291,7 +1294,61 @@ virMacAddrSetRaw; # virnetclient.h +virNetClientAddProgram; +virNetClientAddStream; +virNetClientClose; +virNetClientDupFD; +virNetClientFree; +virNetClientGetFD; +virNetClientGetTLSKeySize; virNetClientHasPassFD; +virNetClientIsEncrypted; +virNetClientIsOpen; +virNetClientKeepAliveIsSupported; +virNetClientKeepAliveStart; +virNetClientKeepAliveStop; +virNetClientLocalAddrString; +virNetClientNewExternal; +virNetClientNewSSH; +virNetClientNewTCP; +virNetClientNewUNIX; +virNetClientRef; +virNetClientRemoteAddrString; +virNetClientRemoveStream; +virNetClientSendNoReply; +virNetClientSendNonBlock; +virNetClientSendWithReply; +virNetClientSendWithReplyStream; +virNetClientSetEOFNotify; +virNetClientSetSASLSession; +virNetClientSetTLSSession; + + +# virnetclientprogram.h +virNetClientProgramCall; +virNetClientProgramDispatch; +virNetClientProgramFree; +virNetClientProgramGetProgram; +virNetClientProgramGetVersion; +virNetClientProgramMatches; +virNetClientProgramNew; +virNetClientProgramRef; + + +# virnetclientstream.h +virNetClientStreamEOF; +virNetClientStreamEventAddCallback; +virNetClientStreamEventRemoveCallback; +virNetClientStreamEventUpdateCallback; +virNetClientStreamFree; +virNetClientStreamMatches; +virNetClientStreamNew; +virNetClientStreamQueuePacket; +virNetClientStreamRaiseError; +virNetClientStreamRecvPacket; +virNetClientStreamRef; +virNetClientStreamSendPacket; +virNetClientStreamSetError; # virnetdev.h @@ -1406,6 +1463,30 @@ virNetMessageSaveError; xdr_virNetMessageError; +# virnetsaslcontext.h +virNetSASLContextCheckIdentity; +virNetSASLContextFree; +virNetSASLContextNewClient; +virNetSASLContextNewServer; +virNetSASLContextRef; +virNetSASLSessionClientStart; +virNetSASLSessionClientStep; +virNetSASLSessionDecode; +virNetSASLSessionEncode; +virNetSASLSessionExtKeySize; +virNetSASLSessionFree; +virNetSASLSessionGetIdentity; +virNetSASLSessionGetKeySize; +virNetSASLSessionGetMaxBufSize; +virNetSASLSessionListMechanisms; +virNetSASLSessionNewClient; +virNetSASLSessionNewServer; +virNetSASLSessionRef; +virNetSASLSessionSecProps; +virNetSASLSessionServerStart; +virNetSASLSessionServerStep; + + # virnetserver.h virNetServerAddProgram; virNetServerAddService; @@ -1422,6 +1503,7 @@ virNetServerRun; virNetServerServiceFree; virNetServerServiceNewTCP; virNetServerServiceNewUNIX; +virNetServerSetTLSContext; virNetServerUpdateServices; @@ -1432,27 +1514,51 @@ virNetServerClientDelayedClose; virNetServerClientFree; virNetServerClientGetAuth; virNetServerClientGetFD; +virNetServerClientGetIdentity; virNetServerClientGetPrivateData; virNetServerClientGetReadonly; virNetServerClientGetTLSKeySize; virNetServerClientGetUNIXIdentity; virNetServerClientHasTLSSession; virNetServerClientImmediateClose; +virNetServerClientInit; +virNetServerClientInitKeepAlive; +virNetServerClientIsClosed; virNetServerClientIsSecure; virNetServerClientLocalAddrString; +virNetServerClientNeedAuth; +virNetServerClientNew; virNetServerClientRef; virNetServerClientRemoteAddrString; virNetServerClientRemoveFilter; virNetServerClientSendMessage; virNetServerClientSetCloseHook; +virNetServerClientSetDispatcher; virNetServerClientSetIdentity; virNetServerClientSetPrivateData; +virNetServerClientSetSASLSession; virNetServerClientStartKeepAlive; +virNetServerClientWantClose; + + +# virnetservermdns.h +virNetServerMDNSAddEntry; +virNetServerMDNSAddGroup; +virNetServerMDNSEntryFree; +virNetServerMDNSFree; +virNetServerMDNSGroupFree; +virNetServerMDNSNew; +virNetServerMDNSRemoveEntry; +virNetServerMDNSRemoveGroup; +virNetServerMDNSStart; +virNetServerMDNSStop; # virnetserverprogram.h +virNetServerProgramDispatch; virNetServerProgramFree; virNetServerProgramGetID; +virNetServerProgramGetPriority; virNetServerProgramGetVersion; virNetServerProgramMatches; virNetServerProgramNew; @@ -1460,18 +1566,39 @@ virNetServerProgramRef; virNetServerProgramSendReplyError; virNetServerProgramSendStreamData; virNetServerProgramSendStreamError; +virNetServerProgramUnknownError; + + +# virnetserverservice.h +virNetServerServiceClose; +virNetServerServiceFree; +virNetServerServiceGetAuth; +virNetServerServiceGetPort; +virNetServerServiceIsReadonly; +virNetServerServiceNewTCP; +virNetServerServiceNewUNIX; +virNetServerServiceRef; +virNetServerServiceSetDispatcher; +virNetServerServiceToggle; # virnetsocket.h virNetSocketAccept; +virNetSocketAddIOCallback; +virNetSocketClose; virNetSocketDupFD; virNetSocketFree; virNetSocketGetFD; +virNetSocketGetPort; +virNetSocketGetUNIXIdentity; +virNetSocketHasCachedData; virNetSocketHasPassFD; +virNetSocketHasPendingData; virNetSocketIsLocal; virNetSocketListen; virNetSocketLocalAddrString; virNetSocketNewConnectCommand; +virNetSocketNewConnectExternal; virNetSocketNewConnectSSH; virNetSocketNewConnectTCP; virNetSocketNewConnectUNIX; @@ -1479,9 +1606,14 @@ virNetSocketNewListenTCP; virNetSocketNewListenUNIX; virNetSocketRead; virNetSocketRecvFD; +virNetSocketRef; virNetSocketRemoteAddrString; +virNetSocketRemoveIOCallback; virNetSocketSendFD; virNetSocketSetBlocking; +virNetSocketSetSASLSession; +virNetSocketSetTLSSession; +virNetSocketUpdateIOCallback; virNetSocketWrite; @@ -1489,12 +1621,20 @@ virNetSocketWrite; virNetTLSContextCheckCertificate; virNetTLSContextFree; virNetTLSContextNewClient; +virNetTLSContextNewClientPath; virNetTLSContextNewServer; virNetTLSContextNewServerPath; +virNetTLSContextRef; +virNetTLSInit; virNetTLSSessionFree; +virNetTLSSessionGetHandshakeStatus; +virNetTLSSessionGetKeySize; virNetTLSSessionHandshake; virNetTLSSessionNew; +virNetTLSSessionRead; +virNetTLSSessionRef; virNetTLSSessionSetIOCallbacks; +virNetTLSSessionWrite; # virnodesuspend.h -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:28PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Make sure that libvirt_private.syms has all the internal symbols from APIs in src/rpc/*.h and src/util/cgroup.h, since the LXC controller/driver will shortly need them
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/libvirt_private.syms | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 03f7f3e..734c881 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -60,11 +60,14 @@ virCapabilitiesSetMacPrefix;
# cgroup.h virCgroupAddTask; +virCgroupAllowDevice; virCgroupAllowDeviceMajor; virCgroupAllowDevicePath; virCgroupControllerTypeFromString; virCgroupControllerTypeToString; virCgroupDenyAllDevices; +virCgroupDenyDevice; +virCgroupDenyDeviceMajor; virCgroupDenyDevicePath; virCgroupForDomain; virCgroupForDriver; @@ -1291,7 +1294,61 @@ virMacAddrSetRaw;
# virnetclient.h +virNetClientAddProgram; +virNetClientAddStream; +virNetClientClose; +virNetClientDupFD; +virNetClientFree; +virNetClientGetFD; +virNetClientGetTLSKeySize; virNetClientHasPassFD; +virNetClientIsEncrypted; +virNetClientIsOpen; +virNetClientKeepAliveIsSupported; +virNetClientKeepAliveStart; +virNetClientKeepAliveStop; +virNetClientLocalAddrString; +virNetClientNewExternal; +virNetClientNewSSH; +virNetClientNewTCP; +virNetClientNewUNIX; +virNetClientRef; +virNetClientRemoteAddrString; +virNetClientRemoveStream; +virNetClientSendNoReply; +virNetClientSendNonBlock; +virNetClientSendWithReply; +virNetClientSendWithReplyStream; +virNetClientSetEOFNotify; +virNetClientSetSASLSession; +virNetClientSetTLSSession; + + +# virnetclientprogram.h +virNetClientProgramCall; +virNetClientProgramDispatch; +virNetClientProgramFree; +virNetClientProgramGetProgram; +virNetClientProgramGetVersion; +virNetClientProgramMatches; +virNetClientProgramNew; +virNetClientProgramRef; + + +# virnetclientstream.h +virNetClientStreamEOF; +virNetClientStreamEventAddCallback; +virNetClientStreamEventRemoveCallback; +virNetClientStreamEventUpdateCallback; +virNetClientStreamFree; +virNetClientStreamMatches; +virNetClientStreamNew; +virNetClientStreamQueuePacket; +virNetClientStreamRaiseError; +virNetClientStreamRecvPacket; +virNetClientStreamRef; +virNetClientStreamSendPacket; +virNetClientStreamSetError;
# virnetdev.h @@ -1406,6 +1463,30 @@ virNetMessageSaveError; xdr_virNetMessageError;
+# virnetsaslcontext.h +virNetSASLContextCheckIdentity; +virNetSASLContextFree; +virNetSASLContextNewClient; +virNetSASLContextNewServer; +virNetSASLContextRef; +virNetSASLSessionClientStart; +virNetSASLSessionClientStep; +virNetSASLSessionDecode; +virNetSASLSessionEncode; +virNetSASLSessionExtKeySize; +virNetSASLSessionFree; +virNetSASLSessionGetIdentity; +virNetSASLSessionGetKeySize; +virNetSASLSessionGetMaxBufSize; +virNetSASLSessionListMechanisms; +virNetSASLSessionNewClient; +virNetSASLSessionNewServer; +virNetSASLSessionRef; +virNetSASLSessionSecProps; +virNetSASLSessionServerStart; +virNetSASLSessionServerStep; + + # virnetserver.h virNetServerAddProgram; virNetServerAddService; @@ -1422,6 +1503,7 @@ virNetServerRun; virNetServerServiceFree; virNetServerServiceNewTCP; virNetServerServiceNewUNIX; +virNetServerSetTLSContext; virNetServerUpdateServices;
@@ -1432,27 +1514,51 @@ virNetServerClientDelayedClose; virNetServerClientFree; virNetServerClientGetAuth; virNetServerClientGetFD; +virNetServerClientGetIdentity; virNetServerClientGetPrivateData; virNetServerClientGetReadonly; virNetServerClientGetTLSKeySize; virNetServerClientGetUNIXIdentity; virNetServerClientHasTLSSession; virNetServerClientImmediateClose; +virNetServerClientInit; +virNetServerClientInitKeepAlive; +virNetServerClientIsClosed; virNetServerClientIsSecure; virNetServerClientLocalAddrString; +virNetServerClientNeedAuth; +virNetServerClientNew; virNetServerClientRef; virNetServerClientRemoteAddrString; virNetServerClientRemoveFilter; virNetServerClientSendMessage; virNetServerClientSetCloseHook; +virNetServerClientSetDispatcher; virNetServerClientSetIdentity; virNetServerClientSetPrivateData; +virNetServerClientSetSASLSession; virNetServerClientStartKeepAlive; +virNetServerClientWantClose; + + +# virnetservermdns.h +virNetServerMDNSAddEntry; +virNetServerMDNSAddGroup; +virNetServerMDNSEntryFree; +virNetServerMDNSFree; +virNetServerMDNSGroupFree; +virNetServerMDNSNew; +virNetServerMDNSRemoveEntry; +virNetServerMDNSRemoveGroup; +virNetServerMDNSStart; +virNetServerMDNSStop;
# virnetserverprogram.h +virNetServerProgramDispatch; virNetServerProgramFree; virNetServerProgramGetID; +virNetServerProgramGetPriority; virNetServerProgramGetVersion; virNetServerProgramMatches; virNetServerProgramNew; @@ -1460,18 +1566,39 @@ virNetServerProgramRef; virNetServerProgramSendReplyError; virNetServerProgramSendStreamData; virNetServerProgramSendStreamError; +virNetServerProgramUnknownError; + + +# virnetserverservice.h +virNetServerServiceClose; +virNetServerServiceFree; +virNetServerServiceGetAuth; +virNetServerServiceGetPort; +virNetServerServiceIsReadonly; +virNetServerServiceNewTCP; +virNetServerServiceNewUNIX; +virNetServerServiceRef; +virNetServerServiceSetDispatcher; +virNetServerServiceToggle;
# virnetsocket.h virNetSocketAccept; +virNetSocketAddIOCallback; +virNetSocketClose; virNetSocketDupFD; virNetSocketFree; virNetSocketGetFD; +virNetSocketGetPort; +virNetSocketGetUNIXIdentity; +virNetSocketHasCachedData; virNetSocketHasPassFD; +virNetSocketHasPendingData; virNetSocketIsLocal; virNetSocketListen; virNetSocketLocalAddrString; virNetSocketNewConnectCommand; +virNetSocketNewConnectExternal; virNetSocketNewConnectSSH; virNetSocketNewConnectTCP; virNetSocketNewConnectUNIX; @@ -1479,9 +1606,14 @@ virNetSocketNewListenTCP; virNetSocketNewListenUNIX; virNetSocketRead; virNetSocketRecvFD; +virNetSocketRef; virNetSocketRemoteAddrString; +virNetSocketRemoveIOCallback; virNetSocketSendFD; virNetSocketSetBlocking; +virNetSocketSetSASLSession; +virNetSocketSetTLSSession; +virNetSocketUpdateIOCallback; virNetSocketWrite;
@@ -1489,12 +1621,20 @@ virNetSocketWrite; virNetTLSContextCheckCertificate; virNetTLSContextFree; virNetTLSContextNewClient; +virNetTLSContextNewClientPath; virNetTLSContextNewServer; virNetTLSContextNewServerPath; +virNetTLSContextRef; +virNetTLSInit; virNetTLSSessionFree; +virNetTLSSessionGetHandshakeStatus; +virNetTLSSessionGetKeySize; virNetTLSSessionHandshake; virNetTLSSessionNew; +virNetTLSSessionRead; +virNetTLSSessionRef; virNetTLSSessionSetIOCallbacks; +virNetTLSSessionWrite;
# virnodesuspend.h
Sorting looks preserved, ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> Move the LXC driver code related to the virDomainObjPtr private data into separate lxc_domain.{c,h} files to reduce the size of lxc_driver.c Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/Makefile.am | 1 + src/lxc/lxc_domain.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_domain.h | 37 +++++++++++++++++++++++++++++++++++ src/lxc/lxc_driver.c | 33 ++----------------------------- 4 files changed, 93 insertions(+), 31 deletions(-) create mode 100644 src/lxc/lxc_domain.c create mode 100644 src/lxc/lxc_domain.h diff --git a/src/Makefile.am b/src/Makefile.am index bfe74d3..e18b0dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -350,6 +350,7 @@ endif LXC_DRIVER_SOURCES = \ lxc/lxc_conf.c lxc/lxc_conf.h \ lxc/lxc_container.c lxc/lxc_container.h \ + lxc/lxc_domain.c lxc/lxc_domain.h \ lxc/lxc_driver.c lxc/lxc_driver.h LXC_CONTROLLER_SOURCES = \ diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c new file mode 100644 index 0000000..75fd74f --- /dev/null +++ b/src/lxc/lxc_domain.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_domain.h: LXC domain helpers + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <config.h> + +#include "lxc_domain.h" + +#include "memory.h" + +static void *lxcDomainObjPrivateAlloc(void) +{ + lxcDomainObjPrivatePtr priv; + + if (VIR_ALLOC(priv) < 0) + return NULL; + + priv->monitor = -1; + priv->monitorWatch = -1; + + return priv; +} + +static void lxcDomainObjPrivateFree(void *data) +{ + lxcDomainObjPrivatePtr priv = data; + + VIR_FREE(priv); +} + + +void lxcDomainSetPrivateDataHooks(virCapsPtr caps) +{ + caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc; + caps->privateDataFreeFunc = lxcDomainObjPrivateFree; +} diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h new file mode 100644 index 0000000..e97b2b4 --- /dev/null +++ b/src/lxc/lxc_domain.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_domain.h: LXC domain helpers + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __LXC_DOMAIN_H__ +# define __LXC_DOMAIN_H__ + +# include "lxc_conf.h" + +typedef struct _lxcDomainObjPrivate lxcDomainObjPrivate; +typedef lxcDomainObjPrivate *lxcDomainObjPrivatePtr; +struct _lxcDomainObjPrivate { + int monitor; + int monitorWatch; +}; + +void lxcDomainSetPrivateDataHooks(virCapsPtr caps); + +#endif /* __LXC_DOMAIN_H__ */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index c341125..d3895d5 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -40,6 +40,7 @@ #include "datatypes.h" #include "lxc_conf.h" #include "lxc_container.h" +#include "lxc_domain.h" #include "lxc_driver.h" #include "memory.h" #include "util.h" @@ -69,14 +70,6 @@ #define LXC_NB_MEM_PARAM 3 -typedef struct _lxcDomainObjPrivate lxcDomainObjPrivate; -typedef lxcDomainObjPrivate *lxcDomainObjPrivatePtr; -struct _lxcDomainObjPrivate { - int monitor; - int monitorWatch; -}; - - static int lxcStartup(int privileged); static int lxcShutdown(void); static lxc_driver_t *lxc_driver = NULL; @@ -92,27 +85,6 @@ static void lxcDriverUnlock(lxc_driver_t *driver) virMutexUnlock(&driver->lock); } -static void *lxcDomainObjPrivateAlloc(void) -{ - lxcDomainObjPrivatePtr priv; - - if (VIR_ALLOC(priv) < 0) - return NULL; - - priv->monitor = -1; - priv->monitorWatch = -1; - - return priv; -} - -static void lxcDomainObjPrivateFree(void *data) -{ - lxcDomainObjPrivatePtr priv = data; - - VIR_FREE(priv); -} - - static void lxcDomainEventQueue(lxc_driver_t *driver, virDomainEventPtr event); @@ -2678,8 +2650,7 @@ static int lxcStartup(int privileged) if ((lxc_driver->caps = lxcCapsInit(lxc_driver)) == NULL) goto cleanup; - lxc_driver->caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc; - lxc_driver->caps->privateDataFreeFunc = lxcDomainObjPrivateFree; + lxcDomainSetPrivateDataHooks(lxc_driver->caps); if (lxcProcessAutoDestroyInit(lxc_driver) < 0) goto cleanup; -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:29PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Move the LXC driver code related to the virDomainObjPtr private data into separate lxc_domain.{c,h} files to reduce the size of lxc_driver.c
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/Makefile.am | 1 + src/lxc/lxc_domain.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_domain.h | 37 +++++++++++++++++++++++++++++++++++ src/lxc/lxc_driver.c | 33 ++-----------------------------
Improving the diff report here in git which would match the identical chunks moved from one file to another would be a great improvement :-)
4 files changed, 93 insertions(+), 31 deletions(-) create mode 100644 src/lxc/lxc_domain.c create mode 100644 src/lxc/lxc_domain.h
diff --git a/src/Makefile.am b/src/Makefile.am index bfe74d3..e18b0dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -350,6 +350,7 @@ endif LXC_DRIVER_SOURCES = \ lxc/lxc_conf.c lxc/lxc_conf.h \ lxc/lxc_container.c lxc/lxc_container.h \ + lxc/lxc_domain.c lxc/lxc_domain.h \ lxc/lxc_driver.c lxc/lxc_driver.h
LXC_CONTROLLER_SOURCES = \ diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c new file mode 100644 index 0000000..75fd74f --- /dev/null +++ b/src/lxc/lxc_domain.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_domain.h: LXC domain helpers + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <config.h> + +#include "lxc_domain.h" + +#include "memory.h" + +static void *lxcDomainObjPrivateAlloc(void) +{ + lxcDomainObjPrivatePtr priv; + + if (VIR_ALLOC(priv) < 0) + return NULL; + + priv->monitor = -1; + priv->monitorWatch = -1; + + return priv; +} + +static void lxcDomainObjPrivateFree(void *data) +{ + lxcDomainObjPrivatePtr priv = data; + + VIR_FREE(priv); +} + + +void lxcDomainSetPrivateDataHooks(virCapsPtr caps) +{ + caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc; + caps->privateDataFreeFunc = lxcDomainObjPrivateFree; +} diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h new file mode 100644 index 0000000..e97b2b4 --- /dev/null +++ b/src/lxc/lxc_domain.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_domain.h: LXC domain helpers + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __LXC_DOMAIN_H__ +# define __LXC_DOMAIN_H__ + +# include "lxc_conf.h" + +typedef struct _lxcDomainObjPrivate lxcDomainObjPrivate; +typedef lxcDomainObjPrivate *lxcDomainObjPrivatePtr; +struct _lxcDomainObjPrivate { + int monitor; + int monitorWatch; +}; + +void lxcDomainSetPrivateDataHooks(virCapsPtr caps); + +#endif /* __LXC_DOMAIN_H__ */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index c341125..d3895d5 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -40,6 +40,7 @@ #include "datatypes.h" #include "lxc_conf.h" #include "lxc_container.h" +#include "lxc_domain.h" #include "lxc_driver.h" #include "memory.h" #include "util.h" @@ -69,14 +70,6 @@
#define LXC_NB_MEM_PARAM 3
-typedef struct _lxcDomainObjPrivate lxcDomainObjPrivate; -typedef lxcDomainObjPrivate *lxcDomainObjPrivatePtr; -struct _lxcDomainObjPrivate { - int monitor; - int monitorWatch; -}; - - static int lxcStartup(int privileged); static int lxcShutdown(void); static lxc_driver_t *lxc_driver = NULL; @@ -92,27 +85,6 @@ static void lxcDriverUnlock(lxc_driver_t *driver) virMutexUnlock(&driver->lock); }
-static void *lxcDomainObjPrivateAlloc(void) -{ - lxcDomainObjPrivatePtr priv; - - if (VIR_ALLOC(priv) < 0) - return NULL; - - priv->monitor = -1; - priv->monitorWatch = -1; - - return priv; -} - -static void lxcDomainObjPrivateFree(void *data) -{ - lxcDomainObjPrivatePtr priv = data; - - VIR_FREE(priv); -} - - static void lxcDomainEventQueue(lxc_driver_t *driver, virDomainEventPtr event);
@@ -2678,8 +2650,7 @@ static int lxcStartup(int privileged) if ((lxc_driver->caps = lxcCapsInit(lxc_driver)) == NULL) goto cleanup;
- lxc_driver->caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc; - lxc_driver->caps->privateDataFreeFunc = lxcDomainObjPrivateFree; + lxcDomainSetPrivateDataHooks(lxc_driver->caps);
if (lxcProcessAutoDestroyInit(lxc_driver) < 0) goto cleanup;
ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> Move the cgroup setup code out of the lxc_controller.c file and into lxc_cgroup.{c,h}. This reduces the size of the lxc_controller.c file and paves the way to invoke cgroup setup from lxc_driver.c instead of lxc_controller.c in the future Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- po/POTFILES.in | 1 + src/Makefile.am | 2 + src/lxc/lxc_cgroup.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_cgroup.h | 29 +++++ src/lxc/lxc_controller.c | 232 +-------------------------------------- 5 files changed, 306 insertions(+), 230 deletions(-) create mode 100644 src/lxc/lxc_cgroup.c create mode 100644 src/lxc/lxc_cgroup.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 6ca40d9..2d5735a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -42,6 +42,7 @@ src/libvirt.c src/libvirt-qemu.c src/locking/lock_driver_sanlock.c src/locking/lock_manager.c +src/lxc/lxc_cgroup.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c diff --git a/src/Makefile.am b/src/Makefile.am index e18b0dc..9e16d06 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -350,12 +350,14 @@ endif LXC_DRIVER_SOURCES = \ lxc/lxc_conf.c lxc/lxc_conf.h \ lxc/lxc_container.c lxc/lxc_container.h \ + lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ lxc/lxc_domain.c lxc/lxc_domain.h \ lxc/lxc_driver.c lxc/lxc_driver.h LXC_CONTROLLER_SOURCES = \ lxc/lxc_conf.c lxc/lxc_conf.h \ lxc/lxc_container.c lxc/lxc_container.h \ + lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ lxc/lxc_controller.c SECURITY_DRIVER_APPARMOR_HELPER_SOURCES = \ diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c new file mode 100644 index 0000000..ddd4901 --- /dev/null +++ b/src/lxc/lxc_cgroup.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_cgroup.c: LXC cgroup helpers + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <config.h> + +#include "lxc_cgroup.h" +#include "lxc_container.h" +#include "virterror_internal.h" +#include "logging.h" +#include "memory.h" +#include "cgroup.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +static int virLXCCgroupSetupCpuTune(virDomainDefPtr def, + virCgroupPtr cgroup) +{ + int ret = -1; + if (def->cputune.shares != 0) { + int rc = virCgroupSetCpuShares(cgroup, def->cputune.shares); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set io cpu shares for domain %s"), + def->name); + goto cleanup; + } + } + if (def->cputune.quota != 0) { + int rc = virCgroupSetCpuCfsQuota(cgroup, def->cputune.quota); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set io cpu quota for domain %s"), + def->name); + goto cleanup; + } + } + if (def->cputune.period != 0) { + int rc = virCgroupSetCpuCfsPeriod(cgroup, def->cputune.period); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set io cpu period for domain %s"), + def->name); + goto cleanup; + } + } + ret = 0; +cleanup: + return ret; +} + + +static int virLXCCgroupSetupBlkioTune(virDomainDefPtr def, + virCgroupPtr cgroup) +{ + int ret = -1; + + if (def->blkio.weight) { + int rc = virCgroupSetBlkioWeight(cgroup, def->blkio.weight); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set Blkio weight for domain %s"), + def->name); + goto cleanup; + } + } + + ret = 0; +cleanup: + return ret; +} + + +static int virLXCCgroupSetupMemTune(virDomainDefPtr def, + virCgroupPtr cgroup) +{ + int ret = -1; + int rc; + + rc = virCgroupSetMemory(cgroup, def->mem.max_balloon); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory limit for domain %s"), + def->name); + goto cleanup; + } + + if (def->mem.hard_limit) { + rc = virCgroupSetMemoryHardLimit(cgroup, def->mem.hard_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory hard limit for domain %s"), + def->name); + goto cleanup; + } + } + + if (def->mem.soft_limit) { + rc = virCgroupSetMemorySoftLimit(cgroup, def->mem.soft_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory soft limit for domain %s"), + def->name); + goto cleanup; + } + } + + if (def->mem.swap_hard_limit) { + rc = virCgroupSetMemSwapHardLimit(cgroup, def->mem.swap_hard_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set swap hard limit for domain %s"), + def->name); + goto cleanup; + } + } + + ret = 0; +cleanup: + return ret; +} + + +typedef struct _virLXCCgroupDevicePolicy virLXCCgroupDevicePolicy; +typedef virLXCCgroupDevicePolicy *virLXCCgroupDevicePolicyPtr; + +struct _virLXCCgroupDevicePolicy { + char type; + int major; + int minor; +}; + + + +static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def, + virCgroupPtr cgroup) +{ + int ret = -1; + int rc; + size_t i; + static virLXCCgroupDevicePolicy devices[] = { + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL}, + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO}, + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL}, + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM}, + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM}, + {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_TTY}, + {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX}, + {0, 0, 0}}; + + rc = virCgroupDenyAllDevices(cgroup); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to deny devices for domain %s"), + def->name); + goto cleanup; + } + + for (i = 0; devices[i].type != 0; i++) { + virLXCCgroupDevicePolicyPtr dev = &devices[i]; + rc = virCgroupAllowDevice(cgroup, + dev->type, + dev->major, + dev->minor, + VIR_CGROUP_DEVICE_RWM); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to allow device %c:%d:%d for domain %s"), + dev->type, dev->major, dev->minor, def->name); + goto cleanup; + } + } + + for (i = 0 ; i < def->nfss ; i++) { + if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_BLOCK) + continue; + + rc = virCgroupAllowDevicePath(cgroup, + def->fss[i]->src, + def->fss[i]->readonly ? + VIR_CGROUP_DEVICE_READ : + VIR_CGROUP_DEVICE_RW); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to allow device %s for domain %s"), + def->fss[i]->src, def->name); + goto cleanup; + } + } + + rc = virCgroupAllowDeviceMajor(cgroup, 'c', LXC_DEV_MAJ_PTY, + VIR_CGROUP_DEVICE_RWM); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to allow PTY devices for domain %s"), + def->name); + goto cleanup; + } + + ret = 0; +cleanup: + return ret; +} + + +int virLXCCgroupSetup(virDomainDefPtr def) +{ + virCgroupPtr driver = NULL; + virCgroupPtr cgroup = NULL; + int rc = -1; + + rc = virCgroupForDriver("lxc", &driver, 1, 0); + if (rc != 0) { + /* Skip all if no driver cgroup is configured */ + if (rc == -ENXIO || rc == -ENOENT) + return 0; + + virReportSystemError(-rc, "%s", + _("Unable to get cgroup for driver")); + return rc; + } + + rc = virCgroupForDomain(driver, def->name, &cgroup, 1); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to create cgroup for domain %s"), + def->name); + goto cleanup; + } + + if (virLXCCgroupSetupCpuTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupBlkioTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupMemTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupDeviceACL(def, cgroup) < 0) + goto cleanup; + + rc = virCgroupAddTask(cgroup, getpid()); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to add task %d to cgroup for domain %s"), + getpid(), def->name); + } + +cleanup: + virCgroupFree(&cgroup); + virCgroupFree(&driver); + + return rc; +} diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h new file mode 100644 index 0000000..97bb12a --- /dev/null +++ b/src/lxc/lxc_cgroup.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_cgroup.c: LXC cgroup helpers + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __VIR_LXC_CGROUP_H__ +# define __VIR_LXC_CGROUP_H__ + +# include "domain_conf.h" + +int virLXCCgroupSetup(virDomainDefPtr def); + +#endif /* __VIR_LXC_CGROUP_H__ */ diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 7a1ce14..4777d51 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -58,6 +58,7 @@ #include "lxc_conf.h" #include "lxc_container.h" +#include "lxc_cgroup.h" #include "virnetdev.h" #include "virnetdevveth.h" #include "memory.h" @@ -72,13 +73,6 @@ #define VIR_FROM_THIS VIR_FROM_LXC -struct cgroup_device_policy { - char type; - int major; - int minor; -}; - - typedef struct _virLXCControllerConsole virLXCControllerConsole; typedef virLXCControllerConsole *virLXCControllerConsolePtr; struct _virLXCControllerConsole { @@ -127,8 +121,6 @@ struct _virLXCController { /* Server socket */ virNetServerPtr server; - - virCgroupPtr cgroup; }; static void virLXCControllerFree(virLXCControllerPtr ctrl); @@ -201,8 +193,6 @@ static void virLXCControllerStopInit(virLXCControllerPtr ctrl) virLXCControllerCloseLoopDevices(ctrl, true); virPidAbort(ctrl->initpid); ctrl->initpid = 0; - - virCgroupFree(&ctrl->cgroup); } @@ -527,181 +517,6 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) } -static int virLXCControllerSetupCgroupsCpuTune(virLXCControllerPtr ctrl) -{ - int ret = -1; - if (ctrl->def->cputune.shares != 0) { - int rc = virCgroupSetCpuShares(ctrl->cgroup, ctrl->def->cputune.shares); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set io cpu shares for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - if (ctrl->def->cputune.quota != 0) { - int rc = virCgroupSetCpuCfsQuota(ctrl->cgroup, ctrl->def->cputune.quota); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set io cpu quota for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - if (ctrl->def->cputune.period != 0) { - int rc = virCgroupSetCpuCfsPeriod(ctrl->cgroup, ctrl->def->cputune.period); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set io cpu period for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - ret = 0; -cleanup: - return ret; -} - - -static int virLXCControllerSetupCgroupsBlkioTune(virLXCControllerPtr ctrl) -{ - int ret = -1; - - if (ctrl->def->blkio.weight) { - int rc = virCgroupSetBlkioWeight(ctrl->cgroup, ctrl->def->blkio.weight); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set Blkio weight for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - - ret = 0; -cleanup: - return ret; -} - - -static int virLXCControllerSetupCgroupsMemTune(virLXCControllerPtr ctrl) -{ - int ret = -1; - int rc; - - rc = virCgroupSetMemory(ctrl->cgroup, ctrl->def->mem.max_balloon); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set memory limit for domain %s"), - ctrl->def->name); - goto cleanup; - } - - if (ctrl->def->mem.hard_limit) { - rc = virCgroupSetMemoryHardLimit(ctrl->cgroup, ctrl->def->mem.hard_limit); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set memory hard limit for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - - if (ctrl->def->mem.soft_limit) { - rc = virCgroupSetMemorySoftLimit(ctrl->cgroup, ctrl->def->mem.soft_limit); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set memory soft limit for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - - if (ctrl->def->mem.swap_hard_limit) { - rc = virCgroupSetMemSwapHardLimit(ctrl->cgroup, ctrl->def->mem.swap_hard_limit); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set swap hard limit for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - - ret = 0; -cleanup: - return ret; -} - - -static int virLXCControllerSetupCgroupsDeviceACL(virLXCControllerPtr ctrl) -{ - int ret = -1; - int rc; - size_t i; - static const struct cgroup_device_policy devices[] = { - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL}, - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO}, - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL}, - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM}, - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM}, - {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_TTY}, - {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX}, - {0, 0, 0}}; - - rc = virCgroupDenyAllDevices(ctrl->cgroup); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to deny devices for domain %s"), - ctrl->def->name); - goto cleanup; - } - - for (i = 0; devices[i].type != 0; i++) { - const struct cgroup_device_policy *dev = &devices[i]; - rc = virCgroupAllowDevice(ctrl->cgroup, - dev->type, - dev->major, - dev->minor, - VIR_CGROUP_DEVICE_RWM); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to allow device %c:%d:%d for domain %s"), - dev->type, dev->major, dev->minor, ctrl->def->name); - goto cleanup; - } - } - - for (i = 0 ; i < ctrl->def->nfss ; i++) { - if (ctrl->def->fss[i]->type != VIR_DOMAIN_FS_TYPE_BLOCK) - continue; - - rc = virCgroupAllowDevicePath(ctrl->cgroup, - ctrl->def->fss[i]->src, - ctrl->def->fss[i]->readonly ? - VIR_CGROUP_DEVICE_READ : - VIR_CGROUP_DEVICE_RW); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to allow device %s for domain %s"), - ctrl->def->fss[i]->src, ctrl->def->name); - goto cleanup; - } - } - - rc = virCgroupAllowDeviceMajor(ctrl->cgroup, 'c', LXC_DEV_MAJ_PTY, - VIR_CGROUP_DEVICE_RWM); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to allow PTY devices for domain %s"), - ctrl->def->name); - goto cleanup; - } - - ret = 0; -cleanup: - return ret; -} - - /** * virLXCControllerSetupResourceLimits * @ctrl: the controller state @@ -713,8 +528,6 @@ cleanup: */ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) { - virCgroupPtr driver; - int rc = -1; if (virLXCControllerSetupCpuAffinity(ctrl) < 0) return -1; @@ -722,48 +535,7 @@ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) if (virLXCControllerSetupNUMAPolicy(ctrl) < 0) return -1; - rc = virCgroupForDriver("lxc", &driver, 1, 0); - if (rc != 0) { - /* Skip all if no driver cgroup is configured */ - if (rc == -ENXIO || rc == -ENOENT) - return 0; - - virReportSystemError(-rc, "%s", - _("Unable to get cgroup for driver")); - return rc; - } - - rc = virCgroupForDomain(driver, ctrl->def->name, &ctrl->cgroup, 1); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to create cgroup for domain %s"), - ctrl->def->name); - goto cleanup; - } - - if (virLXCControllerSetupCgroupsCpuTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsBlkioTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsMemTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsDeviceACL(ctrl) < 0) - goto cleanup; - - rc = virCgroupAddTask(ctrl->cgroup, getpid()); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to add task %d to cgroup for domain %s"), - getpid(), ctrl->def->name); - } - -cleanup: - virCgroupFree(&driver); - - return rc; + return virLXCCgroupSetup(ctrl->def); } -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:30PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Move the cgroup setup code out of the lxc_controller.c file and into lxc_cgroup.{c,h}. This reduces the size of the lxc_controller.c file and paves the way to invoke cgroup setup from lxc_driver.c instead of lxc_controller.c in the future
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- po/POTFILES.in | 1 + src/Makefile.am | 2 + src/lxc/lxc_cgroup.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_cgroup.h | 29 +++++ src/lxc/lxc_controller.c | 232 +-------------------------------------- 5 files changed, 306 insertions(+), 230 deletions(-) create mode 100644 src/lxc/lxc_cgroup.c create mode 100644 src/lxc/lxc_cgroup.h
diff --git a/po/POTFILES.in b/po/POTFILES.in index 6ca40d9..2d5735a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -42,6 +42,7 @@ src/libvirt.c src/libvirt-qemu.c src/locking/lock_driver_sanlock.c src/locking/lock_manager.c +src/lxc/lxc_cgroup.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c diff --git a/src/Makefile.am b/src/Makefile.am index e18b0dc..9e16d06 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -350,12 +350,14 @@ endif LXC_DRIVER_SOURCES = \ lxc/lxc_conf.c lxc/lxc_conf.h \ lxc/lxc_container.c lxc/lxc_container.h \ + lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ lxc/lxc_domain.c lxc/lxc_domain.h \ lxc/lxc_driver.c lxc/lxc_driver.h
LXC_CONTROLLER_SOURCES = \ lxc/lxc_conf.c lxc/lxc_conf.h \ lxc/lxc_container.c lxc/lxc_container.h \ + lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ lxc/lxc_controller.c
SECURITY_DRIVER_APPARMOR_HELPER_SOURCES = \ diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c new file mode 100644 index 0000000..ddd4901 --- /dev/null +++ b/src/lxc/lxc_cgroup.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_cgroup.c: LXC cgroup helpers + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <config.h> + +#include "lxc_cgroup.h" +#include "lxc_container.h" +#include "virterror_internal.h" +#include "logging.h" +#include "memory.h" +#include "cgroup.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +static int virLXCCgroupSetupCpuTune(virDomainDefPtr def, + virCgroupPtr cgroup) +{ + int ret = -1; + if (def->cputune.shares != 0) { + int rc = virCgroupSetCpuShares(cgroup, def->cputune.shares); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set io cpu shares for domain %s"), + def->name); + goto cleanup; + } + } + if (def->cputune.quota != 0) { + int rc = virCgroupSetCpuCfsQuota(cgroup, def->cputune.quota); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set io cpu quota for domain %s"), + def->name); + goto cleanup; + } + } + if (def->cputune.period != 0) { + int rc = virCgroupSetCpuCfsPeriod(cgroup, def->cputune.period); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set io cpu period for domain %s"), + def->name); + goto cleanup; + } + } + ret = 0; +cleanup: + return ret; +} + + +static int virLXCCgroupSetupBlkioTune(virDomainDefPtr def, + virCgroupPtr cgroup) +{ + int ret = -1; + + if (def->blkio.weight) { + int rc = virCgroupSetBlkioWeight(cgroup, def->blkio.weight); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set Blkio weight for domain %s"), + def->name); + goto cleanup; + } + } + + ret = 0; +cleanup: + return ret; +} + + +static int virLXCCgroupSetupMemTune(virDomainDefPtr def, + virCgroupPtr cgroup) +{ + int ret = -1; + int rc; + + rc = virCgroupSetMemory(cgroup, def->mem.max_balloon); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory limit for domain %s"), + def->name); + goto cleanup; + } + + if (def->mem.hard_limit) { + rc = virCgroupSetMemoryHardLimit(cgroup, def->mem.hard_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory hard limit for domain %s"), + def->name); + goto cleanup; + } + } + + if (def->mem.soft_limit) { + rc = virCgroupSetMemorySoftLimit(cgroup, def->mem.soft_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set memory soft limit for domain %s"), + def->name); + goto cleanup; + } + } + + if (def->mem.swap_hard_limit) { + rc = virCgroupSetMemSwapHardLimit(cgroup, def->mem.swap_hard_limit); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to set swap hard limit for domain %s"), + def->name); + goto cleanup; + } + } + + ret = 0; +cleanup: + return ret; +} + + +typedef struct _virLXCCgroupDevicePolicy virLXCCgroupDevicePolicy; +typedef virLXCCgroupDevicePolicy *virLXCCgroupDevicePolicyPtr; + +struct _virLXCCgroupDevicePolicy { + char type; + int major; + int minor; +}; + + + +static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def, + virCgroupPtr cgroup) +{ + int ret = -1; + int rc; + size_t i; + static virLXCCgroupDevicePolicy devices[] = { + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL}, + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO}, + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL}, + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM}, + {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM}, + {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_TTY}, + {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX}, + {0, 0, 0}}; + + rc = virCgroupDenyAllDevices(cgroup); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to deny devices for domain %s"), + def->name); + goto cleanup; + } + + for (i = 0; devices[i].type != 0; i++) { + virLXCCgroupDevicePolicyPtr dev = &devices[i]; + rc = virCgroupAllowDevice(cgroup, + dev->type, + dev->major, + dev->minor, + VIR_CGROUP_DEVICE_RWM); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to allow device %c:%d:%d for domain %s"), + dev->type, dev->major, dev->minor, def->name); + goto cleanup; + } + } + + for (i = 0 ; i < def->nfss ; i++) { + if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_BLOCK) + continue; + + rc = virCgroupAllowDevicePath(cgroup, + def->fss[i]->src, + def->fss[i]->readonly ? + VIR_CGROUP_DEVICE_READ : + VIR_CGROUP_DEVICE_RW); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to allow device %s for domain %s"), + def->fss[i]->src, def->name); + goto cleanup; + } + } + + rc = virCgroupAllowDeviceMajor(cgroup, 'c', LXC_DEV_MAJ_PTY, + VIR_CGROUP_DEVICE_RWM); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to allow PTY devices for domain %s"), + def->name); + goto cleanup; + } + + ret = 0; +cleanup: + return ret; +} + + +int virLXCCgroupSetup(virDomainDefPtr def) +{ + virCgroupPtr driver = NULL; + virCgroupPtr cgroup = NULL; + int rc = -1; + + rc = virCgroupForDriver("lxc", &driver, 1, 0); + if (rc != 0) { + /* Skip all if no driver cgroup is configured */ + if (rc == -ENXIO || rc == -ENOENT) + return 0; + + virReportSystemError(-rc, "%s", + _("Unable to get cgroup for driver")); + return rc; + } + + rc = virCgroupForDomain(driver, def->name, &cgroup, 1); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to create cgroup for domain %s"), + def->name); + goto cleanup; + } + + if (virLXCCgroupSetupCpuTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupBlkioTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupMemTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupDeviceACL(def, cgroup) < 0) + goto cleanup; + + rc = virCgroupAddTask(cgroup, getpid()); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to add task %d to cgroup for domain %s"), + getpid(), def->name); + } + +cleanup: + virCgroupFree(&cgroup); + virCgroupFree(&driver); + + return rc; +} diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h new file mode 100644 index 0000000..97bb12a --- /dev/null +++ b/src/lxc/lxc_cgroup.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_cgroup.c: LXC cgroup helpers + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __VIR_LXC_CGROUP_H__ +# define __VIR_LXC_CGROUP_H__ + +# include "domain_conf.h" + +int virLXCCgroupSetup(virDomainDefPtr def); + +#endif /* __VIR_LXC_CGROUP_H__ */ diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 7a1ce14..4777d51 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -58,6 +58,7 @@
#include "lxc_conf.h" #include "lxc_container.h" +#include "lxc_cgroup.h" #include "virnetdev.h" #include "virnetdevveth.h" #include "memory.h" @@ -72,13 +73,6 @@
#define VIR_FROM_THIS VIR_FROM_LXC
-struct cgroup_device_policy { - char type; - int major; - int minor; -}; - - typedef struct _virLXCControllerConsole virLXCControllerConsole; typedef virLXCControllerConsole *virLXCControllerConsolePtr; struct _virLXCControllerConsole { @@ -127,8 +121,6 @@ struct _virLXCController {
/* Server socket */ virNetServerPtr server; - - virCgroupPtr cgroup; };
static void virLXCControllerFree(virLXCControllerPtr ctrl); @@ -201,8 +193,6 @@ static void virLXCControllerStopInit(virLXCControllerPtr ctrl) virLXCControllerCloseLoopDevices(ctrl, true); virPidAbort(ctrl->initpid); ctrl->initpid = 0; - - virCgroupFree(&ctrl->cgroup); }
I'm a bit surprized there. The cgroup is moved out of that structure so that's fine, but i would have expected to see somewhere in the patch another chunk of code outside of the 2 new modules calling the free of the new structure, but it's nowhere to be found in src/lxc/lxc_controller.c diff. Something escapes me, where do we free those now ?
@@ -527,181 +517,6 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) }
-static int virLXCControllerSetupCgroupsCpuTune(virLXCControllerPtr ctrl) -{ - int ret = -1; - if (ctrl->def->cputune.shares != 0) { - int rc = virCgroupSetCpuShares(ctrl->cgroup, ctrl->def->cputune.shares); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set io cpu shares for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - if (ctrl->def->cputune.quota != 0) { - int rc = virCgroupSetCpuCfsQuota(ctrl->cgroup, ctrl->def->cputune.quota); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set io cpu quota for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - if (ctrl->def->cputune.period != 0) { - int rc = virCgroupSetCpuCfsPeriod(ctrl->cgroup, ctrl->def->cputune.period); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set io cpu period for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - ret = 0; -cleanup: - return ret; -} - - -static int virLXCControllerSetupCgroupsBlkioTune(virLXCControllerPtr ctrl) -{ - int ret = -1; - - if (ctrl->def->blkio.weight) { - int rc = virCgroupSetBlkioWeight(ctrl->cgroup, ctrl->def->blkio.weight); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set Blkio weight for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - - ret = 0; -cleanup: - return ret; -} - - -static int virLXCControllerSetupCgroupsMemTune(virLXCControllerPtr ctrl) -{ - int ret = -1; - int rc; - - rc = virCgroupSetMemory(ctrl->cgroup, ctrl->def->mem.max_balloon); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set memory limit for domain %s"), - ctrl->def->name); - goto cleanup; - } - - if (ctrl->def->mem.hard_limit) { - rc = virCgroupSetMemoryHardLimit(ctrl->cgroup, ctrl->def->mem.hard_limit); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set memory hard limit for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - - if (ctrl->def->mem.soft_limit) { - rc = virCgroupSetMemorySoftLimit(ctrl->cgroup, ctrl->def->mem.soft_limit); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set memory soft limit for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - - if (ctrl->def->mem.swap_hard_limit) { - rc = virCgroupSetMemSwapHardLimit(ctrl->cgroup, ctrl->def->mem.swap_hard_limit); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to set swap hard limit for domain %s"), - ctrl->def->name); - goto cleanup; - } - } - - ret = 0; -cleanup: - return ret; -} - - -static int virLXCControllerSetupCgroupsDeviceACL(virLXCControllerPtr ctrl) -{ - int ret = -1; - int rc; - size_t i; - static const struct cgroup_device_policy devices[] = { - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL}, - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO}, - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL}, - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM}, - {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM}, - {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_TTY}, - {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX}, - {0, 0, 0}}; - - rc = virCgroupDenyAllDevices(ctrl->cgroup); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to deny devices for domain %s"), - ctrl->def->name); - goto cleanup; - } - - for (i = 0; devices[i].type != 0; i++) { - const struct cgroup_device_policy *dev = &devices[i]; - rc = virCgroupAllowDevice(ctrl->cgroup, - dev->type, - dev->major, - dev->minor, - VIR_CGROUP_DEVICE_RWM); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to allow device %c:%d:%d for domain %s"), - dev->type, dev->major, dev->minor, ctrl->def->name); - goto cleanup; - } - } - - for (i = 0 ; i < ctrl->def->nfss ; i++) { - if (ctrl->def->fss[i]->type != VIR_DOMAIN_FS_TYPE_BLOCK) - continue; - - rc = virCgroupAllowDevicePath(ctrl->cgroup, - ctrl->def->fss[i]->src, - ctrl->def->fss[i]->readonly ? - VIR_CGROUP_DEVICE_READ : - VIR_CGROUP_DEVICE_RW); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to allow device %s for domain %s"), - ctrl->def->fss[i]->src, ctrl->def->name); - goto cleanup; - } - } - - rc = virCgroupAllowDeviceMajor(ctrl->cgroup, 'c', LXC_DEV_MAJ_PTY, - VIR_CGROUP_DEVICE_RWM); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to allow PTY devices for domain %s"), - ctrl->def->name); - goto cleanup; - } - - ret = 0; -cleanup: - return ret; -} - - /** * virLXCControllerSetupResourceLimits * @ctrl: the controller state @@ -713,8 +528,6 @@ cleanup: */ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) { - virCgroupPtr driver; - int rc = -1;
if (virLXCControllerSetupCpuAffinity(ctrl) < 0) return -1; @@ -722,48 +535,7 @@ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) if (virLXCControllerSetupNUMAPolicy(ctrl) < 0) return -1;
- rc = virCgroupForDriver("lxc", &driver, 1, 0); - if (rc != 0) { - /* Skip all if no driver cgroup is configured */ - if (rc == -ENXIO || rc == -ENOENT) - return 0; - - virReportSystemError(-rc, "%s", - _("Unable to get cgroup for driver")); - return rc; - } - - rc = virCgroupForDomain(driver, ctrl->def->name, &ctrl->cgroup, 1); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to create cgroup for domain %s"), - ctrl->def->name); - goto cleanup; - } - - if (virLXCControllerSetupCgroupsCpuTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsBlkioTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsMemTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsDeviceACL(ctrl) < 0) - goto cleanup; - - rc = virCgroupAddTask(ctrl->cgroup, getpid()); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to add task %d to cgroup for domain %s"), - getpid(), ctrl->def->name); - } - -cleanup: - virCgroupFree(&driver); - - return rc; + return virLXCCgroupSetup(ctrl->def); }
So we do call the Setup() but never the free ... I'm missing something :-) ACK pending on clarification ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Jul 19, 2012 at 04:37:14PM +0800, Daniel Veillard wrote:
On Wed, Jul 18, 2012 at 05:32:30PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Move the cgroup setup code out of the lxc_controller.c file and into lxc_cgroup.{c,h}. This reduces the size of the lxc_controller.c file and paves the way to invoke cgroup setup from lxc_driver.c instead of lxc_controller.c in the future
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- po/POTFILES.in | 1 + src/Makefile.am | 2 + src/lxc/lxc_cgroup.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_cgroup.h | 29 +++++ src/lxc/lxc_controller.c | 232 +-------------------------------------- 5 files changed, 306 insertions(+), 230 deletions(-) create mode 100644 src/lxc/lxc_cgroup.c create mode 100644 src/lxc/lxc_cgroup.h
+int virLXCCgroupSetup(virDomainDefPtr def) +{ + virCgroupPtr driver = NULL; + virCgroupPtr cgroup = NULL; + int rc = -1; + + rc = virCgroupForDriver("lxc", &driver, 1, 0); + if (rc != 0) { + /* Skip all if no driver cgroup is configured */ + if (rc == -ENXIO || rc == -ENOENT) + return 0; + + virReportSystemError(-rc, "%s", + _("Unable to get cgroup for driver")); + return rc; + } + + rc = virCgroupForDomain(driver, def->name, &cgroup, 1); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to create cgroup for domain %s"), + def->name); + goto cleanup; + } + + if (virLXCCgroupSetupCpuTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupBlkioTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupMemTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupDeviceACL(def, cgroup) < 0) + goto cleanup; + + rc = virCgroupAddTask(cgroup, getpid()); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to add task %d to cgroup for domain %s"), + getpid(), def->name); + } + +cleanup: + virCgroupFree(&cgroup); + virCgroupFree(&driver); + + return rc; +}
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 7a1ce14..4777d51 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -58,6 +58,7 @@
#include "lxc_conf.h" #include "lxc_container.h" +#include "lxc_cgroup.h" #include "virnetdev.h" #include "virnetdevveth.h" #include "memory.h" @@ -72,13 +73,6 @@
#define VIR_FROM_THIS VIR_FROM_LXC
-struct cgroup_device_policy { - char type; - int major; - int minor; -}; - - typedef struct _virLXCControllerConsole virLXCControllerConsole; typedef virLXCControllerConsole *virLXCControllerConsolePtr; struct _virLXCControllerConsole { @@ -127,8 +121,6 @@ struct _virLXCController {
/* Server socket */ virNetServerPtr server; - - virCgroupPtr cgroup; };
static void virLXCControllerFree(virLXCControllerPtr ctrl); @@ -201,8 +193,6 @@ static void virLXCControllerStopInit(virLXCControllerPtr ctrl) virLXCControllerCloseLoopDevices(ctrl, true); virPidAbort(ctrl->initpid); ctrl->initpid = 0; - - virCgroupFree(&ctrl->cgroup); }
I'm a bit surprized there. The cgroup is moved out of that structure so that's fine, but i would have expected to see somewhere in the patch another chunk of code outside of the 2 new modules calling the free of the new structure, but it's nowhere to be found in src/lxc/lxc_controller.c diff. Something escapes me, where do we free those now ?
If you look at the virLXCControllerSetupResourceLimits() method below, you'll see we call virCgroupForDomain in the old code to create 'ctrl->cgroup', and free it in virLXCControllerStopInit(). In the new virLXCCgroupSetup() method above, we create & free the cgroup object within the scope of that method. So we don't need final cleanup when stopping the controler anymore.
static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) { - virCgroupPtr driver; - int rc = -1;
if (virLXCControllerSetupCpuAffinity(ctrl) < 0) return -1; @@ -722,48 +535,7 @@ static int virLXCControllerSetupResourceLimits(virLXCControllerPtr ctrl) if (virLXCControllerSetupNUMAPolicy(ctrl) < 0) return -1;
- rc = virCgroupForDriver("lxc", &driver, 1, 0); - if (rc != 0) { - /* Skip all if no driver cgroup is configured */ - if (rc == -ENXIO || rc == -ENOENT) - return 0; - - virReportSystemError(-rc, "%s", - _("Unable to get cgroup for driver")); - return rc; - } - - rc = virCgroupForDomain(driver, ctrl->def->name, &ctrl->cgroup, 1); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to create cgroup for domain %s"), - ctrl->def->name); - goto cleanup; - } - - if (virLXCControllerSetupCgroupsCpuTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsBlkioTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsMemTune(ctrl) < 0) - goto cleanup; - - if (virLXCControllerSetupCgroupsDeviceACL(ctrl) < 0) - goto cleanup; - - rc = virCgroupAddTask(ctrl->cgroup, getpid()); - if (rc != 0) { - virReportSystemError(-rc, - _("Unable to add task %d to cgroup for domain %s"), - getpid(), ctrl->def->name); - } - -cleanup: - virCgroupFree(&driver); - - return rc; + return virLXCCgroupSetup(ctrl->def); }
So we do call the Setup() but never the free ... I'm missing something :-) ACK pending on clarification !
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Thu, Jul 19, 2012 at 09:54:31AM +0100, Daniel P. Berrange wrote:
On Thu, Jul 19, 2012 at 04:37:14PM +0800, Daniel Veillard wrote:
On Wed, Jul 18, 2012 at 05:32:30PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Move the cgroup setup code out of the lxc_controller.c file and into lxc_cgroup.{c,h}. This reduces the size of the lxc_controller.c file and paves the way to invoke cgroup setup from lxc_driver.c instead of lxc_controller.c in the future
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- po/POTFILES.in | 1 + src/Makefile.am | 2 + src/lxc/lxc_cgroup.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_cgroup.h | 29 +++++ src/lxc/lxc_controller.c | 232 +-------------------------------------- 5 files changed, 306 insertions(+), 230 deletions(-) create mode 100644 src/lxc/lxc_cgroup.c create mode 100644 src/lxc/lxc_cgroup.h
+int virLXCCgroupSetup(virDomainDefPtr def) +{ + virCgroupPtr driver = NULL; + virCgroupPtr cgroup = NULL; + int rc = -1; + + rc = virCgroupForDriver("lxc", &driver, 1, 0); + if (rc != 0) { + /* Skip all if no driver cgroup is configured */ + if (rc == -ENXIO || rc == -ENOENT) + return 0; + + virReportSystemError(-rc, "%s", + _("Unable to get cgroup for driver")); + return rc; + } + + rc = virCgroupForDomain(driver, def->name, &cgroup, 1); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to create cgroup for domain %s"), + def->name); + goto cleanup; + } + + if (virLXCCgroupSetupCpuTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupBlkioTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupMemTune(def, cgroup) < 0) + goto cleanup; + + if (virLXCCgroupSetupDeviceACL(def, cgroup) < 0) + goto cleanup; + + rc = virCgroupAddTask(cgroup, getpid()); + if (rc != 0) { + virReportSystemError(-rc, + _("Unable to add task %d to cgroup for domain %s"), + getpid(), def->name); + } + +cleanup: + virCgroupFree(&cgroup); + virCgroupFree(&driver); + + return rc; +}
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 7a1ce14..4777d51 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -58,6 +58,7 @@
#include "lxc_conf.h" #include "lxc_container.h" +#include "lxc_cgroup.h" #include "virnetdev.h" #include "virnetdevveth.h" #include "memory.h" @@ -72,13 +73,6 @@
#define VIR_FROM_THIS VIR_FROM_LXC
-struct cgroup_device_policy { - char type; - int major; - int minor; -}; - - typedef struct _virLXCControllerConsole virLXCControllerConsole; typedef virLXCControllerConsole *virLXCControllerConsolePtr; struct _virLXCControllerConsole { @@ -127,8 +121,6 @@ struct _virLXCController {
/* Server socket */ virNetServerPtr server; - - virCgroupPtr cgroup; };
static void virLXCControllerFree(virLXCControllerPtr ctrl); @@ -201,8 +193,6 @@ static void virLXCControllerStopInit(virLXCControllerPtr ctrl) virLXCControllerCloseLoopDevices(ctrl, true); virPidAbort(ctrl->initpid); ctrl->initpid = 0; - - virCgroupFree(&ctrl->cgroup); }
I'm a bit surprized there. The cgroup is moved out of that structure so that's fine, but i would have expected to see somewhere in the patch another chunk of code outside of the 2 new modules calling the free of the new structure, but it's nowhere to be found in src/lxc/lxc_controller.c diff. Something escapes me, where do we free those now ?
If you look at the virLXCControllerSetupResourceLimits() method below, you'll see we call virCgroupForDomain in the old code to create 'ctrl->cgroup', and free it in virLXCControllerStopInit().
In the new virLXCCgroupSetup() method above, we create & free the cgroup object within the scope of that method. So we don't need final cleanup when stopping the controler anymore.
okidoc, ACK :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> Move all the code that manages stop/start of LXC processes into separate lxc_process.{c,h} file to make the lxc_driver.c file smaller Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/lxc/lxc_conf.h | 10 + src/lxc/lxc_driver.c | 1236 +----------------------------------------------- src/lxc/lxc_process.c | 1242 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_process.h | 49 ++ 6 files changed, 1313 insertions(+), 1226 deletions(-) create mode 100644 src/lxc/lxc_process.c create mode 100644 src/lxc/lxc_process.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 2d5735a..dc46941 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -47,6 +47,7 @@ src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c src/lxc/lxc_driver.c +src/lxc/lxc_process.c src/libxl/libxl_driver.c src/libxl/libxl_conf.c src/network/bridge_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index 9e16d06..59f1ac8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -352,6 +352,7 @@ LXC_DRIVER_SOURCES = \ lxc/lxc_container.c lxc/lxc_container.h \ lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ lxc/lxc_domain.c lxc/lxc_domain.h \ + lxc/lxc_process.c lxc/lxc_process.h \ lxc/lxc_driver.c lxc/lxc_driver.h LXC_CONTROLLER_SOURCES = \ diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index cc279b2..937da16 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -78,4 +78,14 @@ virCapsPtr lxcCapsInit(lxc_driver_t *driver); virReportErrorHelper(VIR_FROM_LXC, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) +static inline void lxcDriverLock(lxc_driver_t *driver) +{ + virMutexLock(&driver->lock); +} +static inline void lxcDriverUnlock(lxc_driver_t *driver) +{ + virMutexUnlock(&driver->lock); +} + + #endif /* LXC_CONF_H */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index d3895d5..d7f052f 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -42,6 +42,7 @@ #include "lxc_container.h" #include "lxc_domain.h" #include "lxc_driver.h" +#include "lxc_process.h" #include "memory.h" #include "util.h" #include "virnetdevbridge.h" @@ -66,7 +67,6 @@ #define VIR_FROM_THIS VIR_FROM_LXC -#define START_POSTFIX ": starting up\n" #define LXC_NB_MEM_PARAM 3 @@ -76,31 +76,6 @@ static lxc_driver_t *lxc_driver = NULL; /* Functions */ -static void lxcDriverLock(lxc_driver_t *driver) -{ - virMutexLock(&driver->lock); -} -static void lxcDriverUnlock(lxc_driver_t *driver) -{ - virMutexUnlock(&driver->lock); -} - -static void lxcDomainEventQueue(lxc_driver_t *driver, - virDomainEventPtr event); - -static int lxcVmTerminate(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason); -static int lxcProcessAutoDestroyInit(lxc_driver_t *driver); -static void lxcProcessAutoDestroyRun(lxc_driver_t *driver, - virConnectPtr conn); -static void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver); -static int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, - virDomainObjPtr vm, - virConnectPtr conn); -static int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, - virDomainObjPtr vm); - static virDrvOpenStatus lxcOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, @@ -451,7 +426,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return dom; } @@ -504,7 +479,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return ret; } @@ -963,1075 +938,6 @@ cleanup: } -static int lxcProcessAutoDestroyInit(lxc_driver_t *driver) -{ - if (!(driver->autodestroy = virHashCreate(5, NULL))) - return -1; - - return 0; -} - -struct lxcProcessAutoDestroyData { - lxc_driver_t *driver; - virConnectPtr conn; -}; - -static void lxcProcessAutoDestroyDom(void *payload, - const void *name, - void *opaque) -{ - struct lxcProcessAutoDestroyData *data = opaque; - virConnectPtr conn = payload; - const char *uuidstr = name; - unsigned char uuid[VIR_UUID_BUFLEN]; - virDomainObjPtr dom; - virDomainEventPtr event = NULL; - - VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn); - - if (data->conn != conn) - return; - - if (virUUIDParse(uuidstr, uuid) < 0) { - VIR_WARN("Failed to parse %s", uuidstr); - return; - } - - if (!(dom = virDomainFindByUUID(&data->driver->domains, - uuid))) { - VIR_DEBUG("No domain object to kill"); - return; - } - - VIR_DEBUG("Killing domain"); - lxcVmTerminate(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED); - virDomainAuditStop(dom, "destroyed"); - event = virDomainEventNewFromObj(dom, - VIR_DOMAIN_EVENT_STOPPED, - VIR_DOMAIN_EVENT_STOPPED_DESTROYED); - - if (dom && !dom->persistent) - virDomainRemoveInactive(&data->driver->domains, dom); - - if (dom) - virDomainObjUnlock(dom); - if (event) - lxcDomainEventQueue(data->driver, event); - virHashRemoveEntry(data->driver->autodestroy, uuidstr); -} - -/* - * Precondition: driver is locked - */ -static void lxcProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn) -{ - struct lxcProcessAutoDestroyData data = { - driver, conn - }; - VIR_DEBUG("conn=%p", conn); - virHashForEach(driver->autodestroy, lxcProcessAutoDestroyDom, &data); -} - -static void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver) -{ - virHashFree(driver->autodestroy); -} - -static int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, - virDomainObjPtr vm, - virConnectPtr conn) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(vm->def->uuid, uuidstr); - VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn); - if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0) - return -1; - return 0; -} - -static int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, - virDomainObjPtr vm) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(vm->def->uuid, uuidstr); - VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr); - if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0) - return -1; - return 0; -} - - -/** - * lxcVmCleanup: - * @driver: pointer to driver structure - * @vm: pointer to VM to clean up - * @reason: reason for switching the VM to shutoff state - * - * Cleanout resources associated with the now dead VM - * - */ -static void lxcVmCleanup(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason) -{ - virCgroupPtr cgroup; - int i; - lxcDomainObjPrivatePtr priv = vm->privateData; - virNetDevVPortProfilePtr vport = NULL; - - /* now that we know it's stopped call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - - /* we can't stop the operation even if the script raised an error */ - virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_STOPPED, VIR_HOOK_SUBOP_END, - NULL, xml, NULL); - VIR_FREE(xml); - } - - /* Stop autodestroy in case guest is restarted */ - lxcProcessAutoDestroyRemove(driver, vm); - - virEventRemoveHandle(priv->monitorWatch); - VIR_FORCE_CLOSE(priv->monitor); - - virPidFileDelete(driver->stateDir, vm->def->name); - virDomainDeleteConfig(driver->stateDir, NULL, vm); - - virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason); - vm->pid = -1; - vm->def->id = -1; - priv->monitor = -1; - priv->monitorWatch = -1; - - for (i = 0 ; i < vm->def->nnets ; i++) { - virDomainNetDefPtr iface = vm->def->nets[i]; - vport = virDomainNetGetActualVirtPortProfile(iface); - ignore_value(virNetDevSetOnline(iface->ifname, false)); - if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) - ignore_value(virNetDevOpenvswitchRemovePort( - virDomainNetGetActualBridgeName(iface), - iface->ifname)); - ignore_value(virNetDevVethDelete(iface->ifname)); - networkReleaseActualDevice(iface); - } - - virDomainConfVMNWFilterTeardown(vm); - - if (driver->cgroup && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) { - virCgroupRemove(cgroup); - virCgroupFree(&cgroup); - } - - /* now that we know it's stopped call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - - /* we can't stop the operation even if the script raised an error */ - virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_RELEASE, VIR_HOOK_SUBOP_END, - NULL, xml, NULL); - VIR_FREE(xml); - } - - if (vm->newDef) { - virDomainDefFree(vm->def); - vm->def = vm->newDef; - vm->def->id = -1; - vm->newDef = NULL; - } -} - - -static int lxcSetupInterfaceBridged(virConnectPtr conn, - virDomainDefPtr vm, - virDomainNetDefPtr net, - const char *brname, - unsigned int *nveths, - char ***veths) -{ - int ret = -1; - char *parentVeth; - char *containerVeth = NULL; - const virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net); - - VIR_DEBUG("calling vethCreate()"); - parentVeth = net->ifname; - if (virNetDevVethCreate(&parentVeth, &containerVeth) < 0) - goto cleanup; - VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth); - - if (net->ifname == NULL) - net->ifname = parentVeth; - - if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { - virReportOOMError(); - VIR_FREE(containerVeth); - goto cleanup; - } - (*veths)[(*nveths)] = containerVeth; - (*nveths)++; - - if (virNetDevSetMAC(containerVeth, &net->mac) < 0) - goto cleanup; - - if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) - ret = virNetDevOpenvswitchAddPort(brname, parentVeth, &net->mac, - vm->uuid, vport); - else - ret = virNetDevBridgeAddPort(brname, parentVeth); - if (ret < 0) - goto cleanup; - - if (virNetDevSetOnline(parentVeth, true) < 0) - goto cleanup; - - if (virNetDevBandwidthSet(net->ifname, - virDomainNetGetActualBandwidth(net)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot set bandwidth limits on %s"), - net->ifname); - goto cleanup; - } - - if (net->filter && - virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0) - goto cleanup; - - ret = 0; - -cleanup: - return ret; -} - - -static int lxcSetupInterfaceDirect(virConnectPtr conn, - virDomainDefPtr def, - virDomainNetDefPtr net, - unsigned int *nveths, - char ***veths) -{ - int ret = 0; - char *res_ifname = NULL; - lxc_driver_t *driver = conn->privateData; - virNetDevBandwidthPtr bw; - virNetDevVPortProfilePtr prof; - - /* XXX how todo bandwidth controls ? - * Since the 'net-ifname' is about to be moved to a different - * namespace & renamed, there will be no host side visible - * interface for the container to attach rules to - */ - bw = virDomainNetGetActualBandwidth(net); - if (bw) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unable to set network bandwidth on direct interfaces")); - return -1; - } - - /* XXX how todo port profiles ? - * Although we can do the association during container - * startup, at shutdown we are unable to disassociate - * because the macvlan device was moved to the container - * and automagically dies when the container dies. So - * we have no dev to perform disassociation with. - */ - prof = virDomainNetGetActualVirtPortProfile(net); - if (prof) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unable to set port profile on direct interfaces")); - return -1; - } - - if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { - virReportOOMError(); - return -1; - } - (*veths)[(*nveths)] = NULL; - - if (virNetDevMacVLanCreateWithVPortProfile( - net->ifname, &net->mac, - virDomainNetGetActualDirectDev(net), - virDomainNetGetActualDirectMode(net), - false, false, def->uuid, - virDomainNetGetActualVirtPortProfile(net), - &res_ifname, - VIR_NETDEV_VPORT_PROFILE_OP_CREATE, - driver->stateDir, - virDomainNetGetActualBandwidth(net)) < 0) - goto cleanup; - - (*veths)[(*nveths)] = res_ifname; - (*nveths)++; - - ret = 0; - -cleanup: - return ret; -} - - -/** - * lxcSetupInterfaces: - * @conn: pointer to connection - * @def: pointer to virtual machine structure - * @nveths: number of interfaces - * @veths: interface names - * - * Sets up the container interfaces by creating the veth device pairs and - * attaching the parent end to the appropriate bridge. The container end - * will moved into the container namespace later after clone has been called. - * - * Returns 0 on success or -1 in case of error - */ -static int lxcSetupInterfaces(virConnectPtr conn, - virDomainDefPtr def, - unsigned int *nveths, - char ***veths) -{ - int ret = -1; - size_t i; - - for (i = 0 ; i < def->nnets ; i++) { - /* If appropriate, grab a physical device from the configured - * network's pool of devices, or resolve bridge device name - * to the one defined in the network definition. - */ - if (networkAllocateActualDevice(def->nets[i]) < 0) - goto cleanup; - - switch (virDomainNetGetActualType(def->nets[i])) { - case VIR_DOMAIN_NET_TYPE_NETWORK: { - virNetworkPtr network; - char *brname = NULL; - - if (!(network = virNetworkLookupByName(conn, - def->nets[i]->data.network.name))) - goto cleanup; - - brname = virNetworkGetBridgeName(network); - virNetworkFree(network); - if (!brname) - goto cleanup; - - if (lxcSetupInterfaceBridged(conn, - def, - def->nets[i], - brname, - nveths, - veths) < 0) { - VIR_FREE(brname); - goto cleanup; - } - VIR_FREE(brname); - break; - } - case VIR_DOMAIN_NET_TYPE_BRIDGE: { - const char *brname = virDomainNetGetActualBridgeName(def->nets[i]); - if (!brname) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("No bridge name specified")); - goto cleanup; - } - if (lxcSetupInterfaceBridged(conn, - def, - def->nets[i], - brname, - nveths, - veths) < 0) - goto cleanup; - } break; - - case VIR_DOMAIN_NET_TYPE_DIRECT: - if (lxcSetupInterfaceDirect(conn, - def, - def->nets[i], - nveths, - veths) < 0) - goto cleanup; - break; - - case VIR_DOMAIN_NET_TYPE_USER: - case VIR_DOMAIN_NET_TYPE_ETHERNET: - case VIR_DOMAIN_NET_TYPE_SERVER: - case VIR_DOMAIN_NET_TYPE_CLIENT: - case VIR_DOMAIN_NET_TYPE_MCAST: - case VIR_DOMAIN_NET_TYPE_INTERNAL: - case VIR_DOMAIN_NET_TYPE_LAST: - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unsupported network type %s"), - virDomainNetTypeToString( - virDomainNetGetActualType(def->nets[i]) - )); - goto cleanup; - } - } - - ret= 0; - -cleanup: - if (ret != 0) { - for (i = 0 ; i < def->nnets ; i++) { - virDomainNetDefPtr iface = def->nets[i]; - virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(iface); - if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) - ignore_value(virNetDevOpenvswitchRemovePort( - virDomainNetGetActualBridgeName(iface), - iface->ifname)); - networkReleaseActualDevice(iface); - } - } - return ret; -} - - -static int lxcMonitorClient(lxc_driver_t * driver, - virDomainObjPtr vm) -{ - char *sockpath = NULL; - int fd = -1; - struct sockaddr_un addr; - - if (virAsprintf(&sockpath, "%s/%s.sock", - driver->stateDir, vm->def->name) < 0) { - virReportOOMError(); - return -1; - } - - if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0) { - VIR_ERROR(_("Failed to set security context for monitor for %s"), - vm->def->name); - goto error; - } - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - - if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0) { - VIR_ERROR(_("Failed to clear security context for monitor for %s"), - vm->def->name); - goto error; - } - - if (fd < 0) { - virReportSystemError(errno, "%s", - _("Failed to create client socket")); - goto error; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Socket path %s too big for destination"), sockpath); - goto error; - } - - if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - virReportSystemError(errno, "%s", - _("Failed to connect to client socket")); - goto error; - } - - VIR_FREE(sockpath); - return fd; - -error: - VIR_FREE(sockpath); - VIR_FORCE_CLOSE(fd); - return -1; -} - - -static int lxcVmTerminate(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason) -{ - virCgroupPtr group = NULL; - int rc; - - if (vm->pid <= 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Invalid PID %d for container"), vm->pid); - return -1; - } - - virSecurityManagerRestoreAllLabel(driver->securityManager, - vm->def, false); - virSecurityManagerReleaseLabel(driver->securityManager, vm->def); - /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); - } - - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) == 0) { - rc = virCgroupKillPainfully(group); - if (rc < 0) { - virReportSystemError(-rc, "%s", - _("Failed to kill container PIDs")); - rc = -1; - goto cleanup; - } - if (rc == 1) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Some container PIDs refused to die")); - rc = -1; - goto cleanup; - } - } else { - /* If cgroup doesn't exist, the VM pids must have already - * died and so we're just cleaning up stale state - */ - } - - lxcVmCleanup(driver, vm, reason); - - rc = 0; - -cleanup: - virCgroupFree(&group); - return rc; -} - -static void lxcMonitorEvent(int watch, - int fd, - int events ATTRIBUTE_UNUSED, - void *data) -{ - lxc_driver_t *driver = lxc_driver; - virDomainObjPtr vm = data; - virDomainEventPtr event = NULL; - lxcDomainObjPrivatePtr priv; - - lxcDriverLock(driver); - virDomainObjLock(vm); - lxcDriverUnlock(driver); - - priv = vm->privateData; - - if (priv->monitor != fd || priv->monitorWatch != watch) { - virEventRemoveHandle(watch); - goto cleanup; - } - - if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) { - virEventRemoveHandle(watch); - } else { - event = virDomainEventNewFromObj(vm, - VIR_DOMAIN_EVENT_STOPPED, - VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); - virDomainAuditStop(vm, "shutdown"); - } - if (!vm->persistent) { - virDomainRemoveInactive(&driver->domains, vm); - vm = NULL; - } - -cleanup: - if (vm) - virDomainObjUnlock(vm); - if (event) { - lxcDriverLock(driver); - lxcDomainEventQueue(driver, event); - lxcDriverUnlock(driver); - } -} - - -static virCommandPtr -lxcBuildControllerCmd(lxc_driver_t *driver, - virDomainObjPtr vm, - int nveths, - char **veths, - int *ttyFDs, - size_t nttyFDs, - int handshakefd) -{ - size_t i; - char *filterstr; - char *outputstr; - virCommandPtr cmd; - - cmd = virCommandNew(vm->def->emulator); - - /* The controller may call ip command, so we have to retain PATH. */ - virCommandAddEnvPass(cmd, "PATH"); - - virCommandAddEnvFormat(cmd, "LIBVIRT_DEBUG=%d", - virLogGetDefaultPriority()); - - if (virLogGetNbFilters() > 0) { - filterstr = virLogGetFilters(); - if (!filterstr) { - virReportOOMError(); - goto cleanup; - } - - virCommandAddEnvPair(cmd, "LIBVIRT_LOG_FILTERS", filterstr); - VIR_FREE(filterstr); - } - - if (driver->log_libvirtd) { - if (virLogGetNbOutputs() > 0) { - outputstr = virLogGetOutputs(); - if (!outputstr) { - virReportOOMError(); - goto cleanup; - } - - virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr); - VIR_FREE(outputstr); - } - } else { - virCommandAddEnvFormat(cmd, - "LIBVIRT_LOG_OUTPUTS=%d:stderr", - virLogGetDefaultPriority()); - } - - virCommandAddArgList(cmd, "--name", vm->def->name, NULL); - for (i = 0 ; i < nttyFDs ; i++) { - virCommandAddArg(cmd, "--console"); - virCommandAddArgFormat(cmd, "%d", ttyFDs[i]); - virCommandPreserveFD(cmd, ttyFDs[i]); - } - - virCommandAddArgPair(cmd, "--security", - virSecurityManagerGetModel(driver->securityManager)); - - virCommandAddArg(cmd, "--handshake"); - virCommandAddArgFormat(cmd, "%d", handshakefd); - virCommandAddArg(cmd, "--background"); - - for (i = 0 ; i < nveths ; i++) { - virCommandAddArgList(cmd, "--veth", veths[i], NULL); - } - - virCommandPreserveFD(cmd, handshakefd); - - return cmd; -cleanup: - virCommandFree(cmd); - return NULL; -} - -static int -lxcReadLogOutput(virDomainObjPtr vm, - char *logfile, - off_t pos, - char *buf, - size_t buflen) -{ - int fd; - off_t off; - int whence; - int got = 0, ret = -1; - int retries = 10; - - if ((fd = open(logfile, O_RDONLY)) < 0) { - virReportSystemError(errno, _("failed to open logfile %s"), - logfile); - goto cleanup; - } - - if (pos < 0) { - off = 0; - whence = SEEK_END; - } else { - off = pos; - whence = SEEK_SET; - } - - if (lseek(fd, off, whence) < 0) { - if (whence == SEEK_END) - virReportSystemError(errno, - _("unable to seek to end of log for %s"), - logfile); - else - virReportSystemError(errno, - _("unable to seek to %lld from start for %s"), - (long long)off, logfile); - goto cleanup; - } - - while (retries) { - ssize_t bytes; - int isdead = 0; - - if (kill(vm->pid, 0) == -1 && errno == ESRCH) - isdead = 1; - - /* Any failures should be detected before we read the log, so we - * always have something useful to report on failure. */ - bytes = saferead(fd, buf+got, buflen-got-1); - if (bytes < 0) { - virReportSystemError(errno, "%s", - _("Failure while reading guest log output")); - goto cleanup; - } - - got += bytes; - buf[got] = '\0'; - - if ((got == buflen-1) || isdead) { - break; - } - - usleep(100*1000); - retries--; - } - - - ret = got; -cleanup: - VIR_FORCE_CLOSE(fd); - return ret; -} - -/** - * lxcVmStart: - * @conn: pointer to connection - * @driver: pointer to driver structure - * @vm: pointer to virtual machine structure - * @autoDestroy: mark the domain for auto destruction - * @reason: reason for switching vm to running state - * - * Starts a vm - * - * Returns 0 on success or -1 in case of error - */ -static int lxcVmStart(virConnectPtr conn, - lxc_driver_t * driver, - virDomainObjPtr vm, - bool autoDestroy, - virDomainRunningReason reason) -{ - int rc = -1, r; - size_t nttyFDs = 0; - int *ttyFDs = NULL; - size_t i; - char *logfile = NULL; - int logfd = -1; - unsigned int nveths = 0; - char **veths = NULL; - int handshakefds[2] = { -1, -1 }; - off_t pos = -1; - char ebuf[1024]; - char *timestamp; - virCommandPtr cmd = NULL; - lxcDomainObjPrivatePtr priv = vm->privateData; - virErrorPtr err = NULL; - - if (!lxc_driver->cgroup) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("The 'cpuacct', 'devices' & 'memory' cgroups controllers must be mounted")); - return -1; - } - - if (!virCgroupMounted(lxc_driver->cgroup, - VIR_CGROUP_CONTROLLER_CPUACCT)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'cpuacct' cgroups controller mount")); - return -1; - } - if (!virCgroupMounted(lxc_driver->cgroup, - VIR_CGROUP_CONTROLLER_DEVICES)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'devices' cgroups controller mount")); - return -1; - } - if (!virCgroupMounted(lxc_driver->cgroup, - VIR_CGROUP_CONTROLLER_MEMORY)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'memory' cgroups controller mount")); - return -1; - } - - if (virFileMakePath(driver->logDir) < 0) { - virReportSystemError(errno, - _("Cannot create log directory '%s'"), - driver->logDir); - return -1; - } - - if (virAsprintf(&logfile, "%s/%s.log", - driver->logDir, vm->def->name) < 0) { - virReportOOMError(); - return -1; - } - - /* Do this up front, so any part of the startup process can add - * runtime state to vm->def that won't be persisted. This let's us - * report implicit runtime defaults in the XML, like vnc listen/socket - */ - VIR_DEBUG("Setting current domain def as transient"); - if (virDomainObjSetDefTransient(driver->caps, vm, true) < 0) - goto cleanup; - - /* Run an early hook to set-up missing devices */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - - /* - * If the script raised an error abort the launch - */ - if (hookret < 0) - goto cleanup; - } - - /* Here we open all the PTYs we need on the host OS side. - * The LXC controller will open the guest OS side PTYs - * and forward I/O between them. - */ - nttyFDs = vm->def->nconsoles; - if (VIR_ALLOC_N(ttyFDs, nttyFDs) < 0) { - virReportOOMError(); - goto cleanup; - } - - /* If you are using a SecurityDriver with dynamic labelling, - then generate a security label for isolation */ - VIR_DEBUG("Generating domain security label (if required)"); - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DEFAULT) - vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_NONE; - - if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { - virDomainAuditSecurityLabel(vm, false); - goto cleanup; - } - virDomainAuditSecurityLabel(vm, true); - - VIR_DEBUG("Setting domain security labels"); - if (virSecurityManagerSetAllLabel(driver->securityManager, - vm->def, NULL) < 0) - goto cleanup; - - for (i = 0 ; i < vm->def->nconsoles ; i++) - ttyFDs[i] = -1; - - for (i = 0 ; i < vm->def->nconsoles ; i++) { - char *ttyPath; - if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only PTY console types are supported")); - goto cleanup; - } - - if (virFileOpenTty(&ttyFDs[i], &ttyPath, 1) < 0) { - virReportSystemError(errno, "%s", - _("Failed to allocate tty")); - goto cleanup; - } - - VIR_FREE(vm->def->consoles[i]->source.data.file.path); - vm->def->consoles[i]->source.data.file.path = ttyPath; - - VIR_FREE(vm->def->consoles[i]->info.alias); - if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) { - virReportOOMError(); - goto cleanup; - } - } - - if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0) - goto cleanup; - - /* Save the configuration for the controller */ - if (virDomainSaveConfig(driver->stateDir, vm->def) < 0) - goto cleanup; - - if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, - S_IRUSR|S_IWUSR)) < 0) { - virReportSystemError(errno, - _("Failed to open '%s'"), - logfile); - goto cleanup; - } - - if (pipe(handshakefds) < 0) { - virReportSystemError(errno, "%s", - _("Unable to create pipe")); - goto cleanup; - } - - if (!(cmd = lxcBuildControllerCmd(driver, - vm, - nveths, veths, - ttyFDs, nttyFDs, - handshakefds[1]))) - goto cleanup; - virCommandSetOutputFD(cmd, &logfd); - virCommandSetErrorFD(cmd, &logfd); - - /* now that we know it is about to start call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - - /* - * If the script raised an error abort the launch - */ - if (hookret < 0) - goto cleanup; - } - - /* Log timestamp */ - if ((timestamp = virTimeStringNow()) == NULL) { - virReportOOMError(); - goto cleanup; - } - if (safewrite(logfd, timestamp, strlen(timestamp)) < 0 || - safewrite(logfd, START_POSTFIX, strlen(START_POSTFIX)) < 0) { - VIR_WARN("Unable to write timestamp to logfile: %s", - virStrerror(errno, ebuf, sizeof(ebuf))); - } - VIR_FREE(timestamp); - - /* Log generated command line */ - virCommandWriteArgLog(cmd, logfd); - if ((pos = lseek(logfd, 0, SEEK_END)) < 0) - VIR_WARN("Unable to seek to end of logfile: %s", - virStrerror(errno, ebuf, sizeof(ebuf))); - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - if (VIR_CLOSE(handshakefds[1]) < 0) { - virReportSystemError(errno, "%s", _("could not close handshake fd")); - goto cleanup; - } - - /* Connect to the controller as a client *first* because - * this will block until the child has written their - * pid file out to disk */ - if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) - goto cleanup; - - /* And get its pid */ - if ((r = virPidFileRead(driver->stateDir, vm->def->name, &vm->pid)) < 0) { - virReportSystemError(-r, - _("Failed to read pid file %s/%s.pid"), - driver->stateDir, vm->def->name); - goto cleanup; - } - - vm->def->id = vm->pid; - virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); - - if (lxcContainerWaitForContinue(handshakefds[0]) < 0) { - char out[1024]; - - if (!(lxcReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("guest failed to start: %s"), out); - } - - goto error; - } - - if ((priv->monitorWatch = virEventAddHandle( - priv->monitor, - VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, - lxcMonitorEvent, - vm, NULL)) < 0) { - goto error; - } - - if (autoDestroy && - lxcProcessAutoDestroyAdd(driver, vm, conn) < 0) - goto error; - - if (virDomainObjSetDefTransient(driver->caps, vm, false) < 0) - goto error; - - /* Write domain status to disk. - * - * XXX: Earlier we wrote the plain "live" domain XML to this - * location for the benefit of libvirt_lxc. We're now overwriting - * it with the live status XML instead. This is a (currently - * harmless) inconsistency we should fix one day */ - if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) - goto error; - - /* finally we can call the 'started' hook script if any */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_STARTED, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - - /* - * If the script raised an error abort the launch - */ - if (hookret < 0) - goto error; - } - - rc = 0; - -cleanup: - if (rc != 0 && !err) - err = virSaveLastError(); - virCommandFree(cmd); - if (VIR_CLOSE(logfd) < 0) { - virReportSystemError(errno, "%s", _("could not close logfile")); - rc = -1; - } - for (i = 0 ; i < nveths ; i++) { - if (rc != 0) - ignore_value(virNetDevVethDelete(veths[i])); - VIR_FREE(veths[i]); - } - if (rc != 0) { - VIR_FORCE_CLOSE(priv->monitor); - virDomainConfVMNWFilterTeardown(vm); - - virSecurityManagerRestoreAllLabel(driver->securityManager, - vm->def, false); - virSecurityManagerReleaseLabel(driver->securityManager, vm->def); - /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); - } - } - for (i = 0 ; i < nttyFDs ; i++) - VIR_FORCE_CLOSE(ttyFDs[i]); - VIR_FREE(ttyFDs); - VIR_FORCE_CLOSE(handshakefds[0]); - VIR_FORCE_CLOSE(handshakefds[1]); - VIR_FREE(logfile); - - if (err) { - virSetError(err); - virFreeError(err); - } - - return rc; - -error: - err = virSaveLastError(); - lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); - goto cleanup; -} - /** * lxcDomainStartWithFlags: * @dom: domain to start @@ -2089,7 +995,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return ret; } @@ -2176,7 +1082,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return dom; } @@ -2354,13 +1260,6 @@ lxcDomainEventDeregisterAny(virConnectPtr conn, } -/* driver must be locked before calling */ -static void lxcDomainEventQueue(lxc_driver_t *driver, - virDomainEventPtr event) -{ - virDomainEventStateQueue(driver->domainEventState, event); -} - /** * lxcDomainDestroyFlags: * @dom: pointer to domain to destroy @@ -2411,7 +1310,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return ret; } @@ -2446,121 +1345,6 @@ static int lxcCheckNetNsSupport(void) } -struct lxcAutostartData { - lxc_driver_t *driver; - virConnectPtr conn; -}; - -static void -lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) -{ - virDomainObjPtr vm = payload; - const struct lxcAutostartData *data = opaque; - - virDomainObjLock(vm); - if (vm->autostart && - !virDomainObjIsActive(vm)) { - int ret = lxcVmStart(data->conn, data->driver, vm, false, - VIR_DOMAIN_RUNNING_BOOTED); - virDomainAuditStart(vm, "booted", ret >= 0); - if (ret < 0) { - virErrorPtr err = virGetLastError(); - VIR_ERROR(_("Failed to autostart VM '%s': %s"), - vm->def->name, - err ? err->message : ""); - } else { - virDomainEventPtr event = - virDomainEventNewFromObj(vm, - VIR_DOMAIN_EVENT_STARTED, - VIR_DOMAIN_EVENT_STARTED_BOOTED); - if (event) - lxcDomainEventQueue(data->driver, event); - } - } - virDomainObjUnlock(vm); -} - -static void -lxcAutostartConfigs(lxc_driver_t *driver) { - /* XXX: Figure out a better way todo this. The domain - * startup code needs a connection handle in order - * to lookup the bridge associated with a virtual - * network - */ - virConnectPtr conn = virConnectOpen("lxc:///"); - /* Ignoring NULL conn which is mostly harmless here */ - - struct lxcAutostartData data = { driver, conn }; - - lxcDriverLock(driver); - virHashForEach(driver->domains.objs, lxcAutostartDomain, &data); - lxcDriverUnlock(driver); - - if (conn) - virConnectClose(conn); -} - -static void -lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) -{ - virDomainObjPtr vm = payload; - lxc_driver_t *driver = opaque; - lxcDomainObjPrivatePtr priv; - - virDomainObjLock(vm); - VIR_DEBUG("Reconnect %d %d %d\n", vm->def->id, vm->pid, vm->state.state); - - priv = vm->privateData; - - if (vm->pid != 0) { - vm->def->id = vm->pid; - virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, - VIR_DOMAIN_RUNNING_UNKNOWN); - - if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) - goto error; - - if ((priv->monitorWatch = virEventAddHandle( - priv->monitor, - VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, - lxcMonitorEvent, - vm, NULL)) < 0) - goto error; - - if (virSecurityManagerReserveLabel(driver->securityManager, - vm->def, vm->pid) < 0) - goto error; - - /* now that we know it's reconnected call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - /* we can't stop the operation even if the script raised an error */ - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - if (hookret < 0) - goto error; - } - - } else { - vm->def->id = -1; - VIR_FORCE_CLOSE(priv->monitor); - } - -cleanup: - virDomainObjUnlock(vm); - return; - -error: - lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); - virDomainAuditStop(vm, "failed"); - goto cleanup; -} - - static int lxcSecurityInit(lxc_driver_t *driver) { @@ -2664,7 +1448,7 @@ static int lxcStartup(int privileged) NULL, NULL) < 0) goto cleanup; - virHashForEach(lxc_driver->domains.objs, lxcReconnectVM, lxc_driver); + lxcReconnectAll(lxc_driver, &lxc_driver->domains); /* Then inactive persistent configs */ if (virDomainLoadAllConfigs(lxc_driver->caps, @@ -2697,7 +1481,7 @@ static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque) VIR_DOMAIN_EVENT_DEFINED, VIR_DOMAIN_EVENT_DEFINED_ADDED); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); } } @@ -3706,7 +2490,7 @@ static int lxcDomainSuspend(virDomainPtr dom) cleanup: if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); if (vm) virDomainObjUnlock(vm); lxcDriverUnlock(driver); @@ -3772,7 +2556,7 @@ static int lxcDomainResume(virDomainPtr dom) cleanup: if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); if (vm) virDomainObjUnlock(vm); lxcDriverUnlock(driver); diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c new file mode 100644 index 0000000..12f6ae6 --- /dev/null +++ b/src/lxc/lxc_process.c @@ -0,0 +1,1242 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_process.c: LXC process lifecycle management + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <config.h> + +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> + +#include "lxc_process.h" +#include "lxc_domain.h" +#include "lxc_container.h" +#include "datatypes.h" +#include "virfile.h" +#include "virpidfile.h" +#include "virnetdev.h" +#include "virnetdevveth.h" +#include "virnetdevbridge.h" +#include "virtime.h" +#include "domain_nwfilter.h" +#include "network/bridge_driver.h" +#include "memory.h" +#include "domain_audit.h" +#include "virterror_internal.h" +#include "logging.h" +#include "command.h" +#include "hooks.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +#define START_POSTFIX ": starting up\n" + +int lxcProcessAutoDestroyInit(lxc_driver_t *driver) +{ + if (!(driver->autodestroy = virHashCreate(5, NULL))) + return -1; + + return 0; +} + +struct lxcProcessAutoDestroyData { + lxc_driver_t *driver; + virConnectPtr conn; +}; + +static void lxcProcessAutoDestroyDom(void *payload, + const void *name, + void *opaque) +{ + struct lxcProcessAutoDestroyData *data = opaque; + virConnectPtr conn = payload; + const char *uuidstr = name; + unsigned char uuid[VIR_UUID_BUFLEN]; + virDomainObjPtr dom; + virDomainEventPtr event = NULL; + + VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn); + + if (data->conn != conn) + return; + + if (virUUIDParse(uuidstr, uuid) < 0) { + VIR_WARN("Failed to parse %s", uuidstr); + return; + } + + if (!(dom = virDomainFindByUUID(&data->driver->domains, + uuid))) { + VIR_DEBUG("No domain object to kill"); + return; + } + + VIR_DEBUG("Killing domain"); + lxcVmTerminate(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED); + virDomainAuditStop(dom, "destroyed"); + event = virDomainEventNewFromObj(dom, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_DESTROYED); + + if (dom && !dom->persistent) + virDomainRemoveInactive(&data->driver->domains, dom); + + if (dom) + virDomainObjUnlock(dom); + if (event) + virDomainEventStateQueue(data->driver->domainEventState, event); + virHashRemoveEntry(data->driver->autodestroy, uuidstr); +} + +/* + * Precondition: driver is locked + */ +void lxcProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn) +{ + struct lxcProcessAutoDestroyData data = { + driver, conn + }; + VIR_DEBUG("conn=%p", conn); + virHashForEach(driver->autodestroy, lxcProcessAutoDestroyDom, &data); +} + +void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver) +{ + virHashFree(driver->autodestroy); +} + +int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, + virDomainObjPtr vm, + virConnectPtr conn) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(vm->def->uuid, uuidstr); + VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn); + if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0) + return -1; + return 0; +} + +int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, + virDomainObjPtr vm) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(vm->def->uuid, uuidstr); + VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr); + if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0) + return -1; + return 0; +} + + +/** + * lxcVmCleanup: + * @driver: pointer to driver structure + * @vm: pointer to VM to clean up + * @reason: reason for switching the VM to shutoff state + * + * Cleanout resources associated with the now dead VM + * + */ +static void lxcVmCleanup(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason) +{ + virCgroupPtr cgroup; + int i; + lxcDomainObjPrivatePtr priv = vm->privateData; + virNetDevVPortProfilePtr vport = NULL; + + /* now that we know it's stopped call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + + /* we can't stop the operation even if the script raised an error */ + virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_STOPPED, VIR_HOOK_SUBOP_END, + NULL, xml, NULL); + VIR_FREE(xml); + } + + /* Stop autodestroy in case guest is restarted */ + lxcProcessAutoDestroyRemove(driver, vm); + + virEventRemoveHandle(priv->monitorWatch); + VIR_FORCE_CLOSE(priv->monitor); + + virPidFileDelete(driver->stateDir, vm->def->name); + virDomainDeleteConfig(driver->stateDir, NULL, vm); + + virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason); + vm->pid = -1; + vm->def->id = -1; + priv->monitor = -1; + priv->monitorWatch = -1; + + for (i = 0 ; i < vm->def->nnets ; i++) { + virDomainNetDefPtr iface = vm->def->nets[i]; + vport = virDomainNetGetActualVirtPortProfile(iface); + ignore_value(virNetDevSetOnline(iface->ifname, false)); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(iface), + iface->ifname)); + ignore_value(virNetDevVethDelete(iface->ifname)); + networkReleaseActualDevice(iface); + } + + virDomainConfVMNWFilterTeardown(vm); + + if (driver->cgroup && + virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) { + virCgroupRemove(cgroup); + virCgroupFree(&cgroup); + } + + /* now that we know it's stopped call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + + /* we can't stop the operation even if the script raised an error */ + virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_RELEASE, VIR_HOOK_SUBOP_END, + NULL, xml, NULL); + VIR_FREE(xml); + } + + if (vm->newDef) { + virDomainDefFree(vm->def); + vm->def = vm->newDef; + vm->def->id = -1; + vm->newDef = NULL; + } +} + + +static int lxcSetupInterfaceBridged(virConnectPtr conn, + virDomainDefPtr vm, + virDomainNetDefPtr net, + const char *brname, + unsigned int *nveths, + char ***veths) +{ + int ret = -1; + char *parentVeth; + char *containerVeth = NULL; + const virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net); + + VIR_DEBUG("calling vethCreate()"); + parentVeth = net->ifname; + if (virNetDevVethCreate(&parentVeth, &containerVeth) < 0) + goto cleanup; + VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth); + + if (net->ifname == NULL) + net->ifname = parentVeth; + + if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { + virReportOOMError(); + VIR_FREE(containerVeth); + goto cleanup; + } + (*veths)[(*nveths)] = containerVeth; + (*nveths)++; + + if (virNetDevSetMAC(containerVeth, &net->mac) < 0) + goto cleanup; + + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ret = virNetDevOpenvswitchAddPort(brname, parentVeth, &net->mac, + vm->uuid, vport); + else + ret = virNetDevBridgeAddPort(brname, parentVeth); + if (ret < 0) + goto cleanup; + + if (virNetDevSetOnline(parentVeth, true) < 0) + goto cleanup; + + if (virNetDevBandwidthSet(net->ifname, + virDomainNetGetActualBandwidth(net)) < 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("cannot set bandwidth limits on %s"), + net->ifname); + goto cleanup; + } + + if (net->filter && + virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0) + goto cleanup; + + ret = 0; + +cleanup: + return ret; +} + + +static int lxcSetupInterfaceDirect(virConnectPtr conn, + virDomainDefPtr def, + virDomainNetDefPtr net, + unsigned int *nveths, + char ***veths) +{ + int ret = 0; + char *res_ifname = NULL; + lxc_driver_t *driver = conn->privateData; + virNetDevBandwidthPtr bw; + virNetDevVPortProfilePtr prof; + + /* XXX how todo bandwidth controls ? + * Since the 'net-ifname' is about to be moved to a different + * namespace & renamed, there will be no host side visible + * interface for the container to attach rules to + */ + bw = virDomainNetGetActualBandwidth(net); + if (bw) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set network bandwidth on direct interfaces")); + return -1; + } + + /* XXX how todo port profiles ? + * Although we can do the association during container + * startup, at shutdown we are unable to disassociate + * because the macvlan device was moved to the container + * and automagically dies when the container dies. So + * we have no dev to perform disassociation with. + */ + prof = virDomainNetGetActualVirtPortProfile(net); + if (prof) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set port profile on direct interfaces")); + return -1; + } + + if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { + virReportOOMError(); + return -1; + } + (*veths)[(*nveths)] = NULL; + + if (virNetDevMacVLanCreateWithVPortProfile( + net->ifname, &net->mac, + virDomainNetGetActualDirectDev(net), + virDomainNetGetActualDirectMode(net), + false, false, def->uuid, + virDomainNetGetActualVirtPortProfile(net), + &res_ifname, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, + driver->stateDir, + virDomainNetGetActualBandwidth(net)) < 0) + goto cleanup; + + (*veths)[(*nveths)] = res_ifname; + (*nveths)++; + + ret = 0; + +cleanup: + return ret; +} + + +/** + * lxcSetupInterfaces: + * @conn: pointer to connection + * @def: pointer to virtual machine structure + * @nveths: number of interfaces + * @veths: interface names + * + * Sets up the container interfaces by creating the veth device pairs and + * attaching the parent end to the appropriate bridge. The container end + * will moved into the container namespace later after clone has been called. + * + * Returns 0 on success or -1 in case of error + */ +static int lxcSetupInterfaces(virConnectPtr conn, + virDomainDefPtr def, + unsigned int *nveths, + char ***veths) +{ + int ret = -1; + size_t i; + + for (i = 0 ; i < def->nnets ; i++) { + /* If appropriate, grab a physical device from the configured + * network's pool of devices, or resolve bridge device name + * to the one defined in the network definition. + */ + if (networkAllocateActualDevice(def->nets[i]) < 0) + goto cleanup; + + switch (virDomainNetGetActualType(def->nets[i])) { + case VIR_DOMAIN_NET_TYPE_NETWORK: { + virNetworkPtr network; + char *brname = NULL; + + if (!(network = virNetworkLookupByName(conn, + def->nets[i]->data.network.name))) + goto cleanup; + + brname = virNetworkGetBridgeName(network); + virNetworkFree(network); + if (!brname) + goto cleanup; + + if (lxcSetupInterfaceBridged(conn, + def, + def->nets[i], + brname, + nveths, + veths) < 0) { + VIR_FREE(brname); + goto cleanup; + } + VIR_FREE(brname); + break; + } + case VIR_DOMAIN_NET_TYPE_BRIDGE: { + const char *brname = virDomainNetGetActualBridgeName(def->nets[i]); + if (!brname) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No bridge name specified")); + goto cleanup; + } + if (lxcSetupInterfaceBridged(conn, + def, + def->nets[i], + brname, + nveths, + veths) < 0) + goto cleanup; + } break; + + case VIR_DOMAIN_NET_TYPE_DIRECT: + if (lxcSetupInterfaceDirect(conn, + def, + def->nets[i], + nveths, + veths) < 0) + goto cleanup; + break; + + case VIR_DOMAIN_NET_TYPE_USER: + case VIR_DOMAIN_NET_TYPE_ETHERNET: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_CLIENT: + case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_INTERNAL: + case VIR_DOMAIN_NET_TYPE_LAST: + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Unsupported network type %s"), + virDomainNetTypeToString( + virDomainNetGetActualType(def->nets[i]) + )); + goto cleanup; + } + } + + ret= 0; + +cleanup: + if (ret != 0) { + for (i = 0 ; i < def->nnets ; i++) { + virDomainNetDefPtr iface = def->nets[i]; + virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(iface); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(iface), + iface->ifname)); + networkReleaseActualDevice(iface); + } + } + return ret; +} + + +static int lxcMonitorClient(lxc_driver_t * driver, + virDomainObjPtr vm) +{ + char *sockpath = NULL; + int fd = -1; + struct sockaddr_un addr; + + if (virAsprintf(&sockpath, "%s/%s.sock", + driver->stateDir, vm->def->name) < 0) { + virReportOOMError(); + return -1; + } + + if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0) { + VIR_ERROR(_("Failed to set security context for monitor for %s"), + vm->def->name); + goto error; + } + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + + if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0) { + VIR_ERROR(_("Failed to clear security context for monitor for %s"), + vm->def->name); + goto error; + } + + if (fd < 0) { + virReportSystemError(errno, "%s", + _("Failed to create client socket")); + goto error; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Socket path %s too big for destination"), sockpath); + goto error; + } + + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + virReportSystemError(errno, "%s", + _("Failed to connect to client socket")); + goto error; + } + + VIR_FREE(sockpath); + return fd; + +error: + VIR_FREE(sockpath); + VIR_FORCE_CLOSE(fd); + return -1; +} + + +int lxcVmTerminate(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason) +{ + virCgroupPtr group = NULL; + int rc; + + if (vm->pid <= 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Invalid PID %d for container"), vm->pid); + return -1; + } + + virSecurityManagerRestoreAllLabel(driver->securityManager, + vm->def, false); + virSecurityManagerReleaseLabel(driver->securityManager, vm->def); + /* Clear out dynamically assigned labels */ + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabel.model); + VIR_FREE(vm->def->seclabel.label); + VIR_FREE(vm->def->seclabel.imagelabel); + } + + if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) == 0) { + rc = virCgroupKillPainfully(group); + if (rc < 0) { + virReportSystemError(-rc, "%s", + _("Failed to kill container PIDs")); + rc = -1; + goto cleanup; + } + if (rc == 1) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Some container PIDs refused to die")); + rc = -1; + goto cleanup; + } + } else { + /* If cgroup doesn't exist, the VM pids must have already + * died and so we're just cleaning up stale state + */ + } + + lxcVmCleanup(driver, vm, reason); + + rc = 0; + +cleanup: + virCgroupFree(&group); + return rc; +} + +extern lxc_driver_t *lxc_driver; +static void lxcMonitorEvent(int watch, + int fd, + int events ATTRIBUTE_UNUSED, + void *data) +{ + lxc_driver_t *driver = lxc_driver; + virDomainObjPtr vm = data; + virDomainEventPtr event = NULL; + lxcDomainObjPrivatePtr priv; + + lxcDriverLock(driver); + virDomainObjLock(vm); + lxcDriverUnlock(driver); + + priv = vm->privateData; + + if (priv->monitor != fd || priv->monitorWatch != watch) { + virEventRemoveHandle(watch); + goto cleanup; + } + + if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) { + virEventRemoveHandle(watch); + } else { + event = virDomainEventNewFromObj(vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); + virDomainAuditStop(vm, "shutdown"); + } + if (!vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + if (event) { + lxcDriverLock(driver); + virDomainEventStateQueue(driver->domainEventState, event); + lxcDriverUnlock(driver); + } +} + + +static virCommandPtr +lxcBuildControllerCmd(lxc_driver_t *driver, + virDomainObjPtr vm, + int nveths, + char **veths, + int *ttyFDs, + size_t nttyFDs, + int handshakefd) +{ + size_t i; + char *filterstr; + char *outputstr; + virCommandPtr cmd; + + cmd = virCommandNew(vm->def->emulator); + + /* The controller may call ip command, so we have to retain PATH. */ + virCommandAddEnvPass(cmd, "PATH"); + + virCommandAddEnvFormat(cmd, "LIBVIRT_DEBUG=%d", + virLogGetDefaultPriority()); + + if (virLogGetNbFilters() > 0) { + filterstr = virLogGetFilters(); + if (!filterstr) { + virReportOOMError(); + goto cleanup; + } + + virCommandAddEnvPair(cmd, "LIBVIRT_LOG_FILTERS", filterstr); + VIR_FREE(filterstr); + } + + if (driver->log_libvirtd) { + if (virLogGetNbOutputs() > 0) { + outputstr = virLogGetOutputs(); + if (!outputstr) { + virReportOOMError(); + goto cleanup; + } + + virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr); + VIR_FREE(outputstr); + } + } else { + virCommandAddEnvFormat(cmd, + "LIBVIRT_LOG_OUTPUTS=%d:stderr", + virLogGetDefaultPriority()); + } + + virCommandAddArgList(cmd, "--name", vm->def->name, NULL); + for (i = 0 ; i < nttyFDs ; i++) { + virCommandAddArg(cmd, "--console"); + virCommandAddArgFormat(cmd, "%d", ttyFDs[i]); + virCommandPreserveFD(cmd, ttyFDs[i]); + } + + virCommandAddArgPair(cmd, "--security", + virSecurityManagerGetModel(driver->securityManager)); + + virCommandAddArg(cmd, "--handshake"); + virCommandAddArgFormat(cmd, "%d", handshakefd); + virCommandAddArg(cmd, "--background"); + + for (i = 0 ; i < nveths ; i++) { + virCommandAddArgList(cmd, "--veth", veths[i], NULL); + } + + virCommandPreserveFD(cmd, handshakefd); + + return cmd; +cleanup: + virCommandFree(cmd); + return NULL; +} + +static int +lxcReadLogOutput(virDomainObjPtr vm, + char *logfile, + off_t pos, + char *buf, + size_t buflen) +{ + int fd; + off_t off; + int whence; + int got = 0, ret = -1; + int retries = 10; + + if ((fd = open(logfile, O_RDONLY)) < 0) { + virReportSystemError(errno, _("failed to open logfile %s"), + logfile); + goto cleanup; + } + + if (pos < 0) { + off = 0; + whence = SEEK_END; + } else { + off = pos; + whence = SEEK_SET; + } + + if (lseek(fd, off, whence) < 0) { + if (whence == SEEK_END) + virReportSystemError(errno, + _("unable to seek to end of log for %s"), + logfile); + else + virReportSystemError(errno, + _("unable to seek to %lld from start for %s"), + (long long)off, logfile); + goto cleanup; + } + + while (retries) { + ssize_t bytes; + int isdead = 0; + + if (kill(vm->pid, 0) == -1 && errno == ESRCH) + isdead = 1; + + /* Any failures should be detected before we read the log, so we + * always have something useful to report on failure. */ + bytes = saferead(fd, buf+got, buflen-got-1); + if (bytes < 0) { + virReportSystemError(errno, "%s", + _("Failure while reading guest log output")); + goto cleanup; + } + + got += bytes; + buf[got] = '\0'; + + if ((got == buflen-1) || isdead) { + break; + } + + usleep(100*1000); + retries--; + } + + + ret = got; +cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} + +/** + * lxcVmStart: + * @conn: pointer to connection + * @driver: pointer to driver structure + * @vm: pointer to virtual machine structure + * @autoDestroy: mark the domain for auto destruction + * @reason: reason for switching vm to running state + * + * Starts a vm + * + * Returns 0 on success or -1 in case of error + */ +int lxcVmStart(virConnectPtr conn, + lxc_driver_t * driver, + virDomainObjPtr vm, + bool autoDestroy, + virDomainRunningReason reason) +{ + int rc = -1, r; + size_t nttyFDs = 0; + int *ttyFDs = NULL; + size_t i; + char *logfile = NULL; + int logfd = -1; + unsigned int nveths = 0; + char **veths = NULL; + int handshakefds[2] = { -1, -1 }; + off_t pos = -1; + char ebuf[1024]; + char *timestamp; + virCommandPtr cmd = NULL; + lxcDomainObjPrivatePtr priv = vm->privateData; + virErrorPtr err = NULL; + + if (!lxc_driver->cgroup) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("The 'cpuacct', 'devices' & 'memory' cgroups controllers must be mounted")); + return -1; + } + + if (!virCgroupMounted(lxc_driver->cgroup, + VIR_CGROUP_CONTROLLER_CPUACCT)) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'cpuacct' cgroups controller mount")); + return -1; + } + if (!virCgroupMounted(lxc_driver->cgroup, + VIR_CGROUP_CONTROLLER_DEVICES)) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'devices' cgroups controller mount")); + return -1; + } + if (!virCgroupMounted(lxc_driver->cgroup, + VIR_CGROUP_CONTROLLER_MEMORY)) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'memory' cgroups controller mount")); + return -1; + } + + if (virFileMakePath(driver->logDir) < 0) { + virReportSystemError(errno, + _("Cannot create log directory '%s'"), + driver->logDir); + return -1; + } + + if (virAsprintf(&logfile, "%s/%s.log", + driver->logDir, vm->def->name) < 0) { + virReportOOMError(); + return -1; + } + + /* Do this up front, so any part of the startup process can add + * runtime state to vm->def that won't be persisted. This let's us + * report implicit runtime defaults in the XML, like vnc listen/socket + */ + VIR_DEBUG("Setting current domain def as transient"); + if (virDomainObjSetDefTransient(driver->caps, vm, true) < 0) + goto cleanup; + + /* Run an early hook to set-up missing devices */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto cleanup; + } + + /* Here we open all the PTYs we need on the host OS side. + * The LXC controller will open the guest OS side PTYs + * and forward I/O between them. + */ + nttyFDs = vm->def->nconsoles; + if (VIR_ALLOC_N(ttyFDs, nttyFDs) < 0) { + virReportOOMError(); + goto cleanup; + } + + /* If you are using a SecurityDriver with dynamic labelling, + then generate a security label for isolation */ + VIR_DEBUG("Generating domain security label (if required)"); + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DEFAULT) + vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_NONE; + + if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { + virDomainAuditSecurityLabel(vm, false); + goto cleanup; + } + virDomainAuditSecurityLabel(vm, true); + + VIR_DEBUG("Setting domain security labels"); + if (virSecurityManagerSetAllLabel(driver->securityManager, + vm->def, NULL) < 0) + goto cleanup; + + for (i = 0 ; i < vm->def->nconsoles ; i++) + ttyFDs[i] = -1; + + for (i = 0 ; i < vm->def->nconsoles ; i++) { + char *ttyPath; + if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only PTY console types are supported")); + goto cleanup; + } + + if (virFileOpenTty(&ttyFDs[i], &ttyPath, 1) < 0) { + virReportSystemError(errno, "%s", + _("Failed to allocate tty")); + goto cleanup; + } + + VIR_FREE(vm->def->consoles[i]->source.data.file.path); + vm->def->consoles[i]->source.data.file.path = ttyPath; + + VIR_FREE(vm->def->consoles[i]->info.alias); + if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0) + goto cleanup; + + /* Save the configuration for the controller */ + if (virDomainSaveConfig(driver->stateDir, vm->def) < 0) + goto cleanup; + + if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, + S_IRUSR|S_IWUSR)) < 0) { + virReportSystemError(errno, + _("Failed to open '%s'"), + logfile); + goto cleanup; + } + + if (pipe(handshakefds) < 0) { + virReportSystemError(errno, "%s", + _("Unable to create pipe")); + goto cleanup; + } + + if (!(cmd = lxcBuildControllerCmd(driver, + vm, + nveths, veths, + ttyFDs, nttyFDs, + handshakefds[1]))) + goto cleanup; + virCommandSetOutputFD(cmd, &logfd); + virCommandSetErrorFD(cmd, &logfd); + + /* now that we know it is about to start call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto cleanup; + } + + /* Log timestamp */ + if ((timestamp = virTimeStringNow()) == NULL) { + virReportOOMError(); + goto cleanup; + } + if (safewrite(logfd, timestamp, strlen(timestamp)) < 0 || + safewrite(logfd, START_POSTFIX, strlen(START_POSTFIX)) < 0) { + VIR_WARN("Unable to write timestamp to logfile: %s", + virStrerror(errno, ebuf, sizeof(ebuf))); + } + VIR_FREE(timestamp); + + /* Log generated command line */ + virCommandWriteArgLog(cmd, logfd); + if ((pos = lseek(logfd, 0, SEEK_END)) < 0) + VIR_WARN("Unable to seek to end of logfile: %s", + virStrerror(errno, ebuf, sizeof(ebuf))); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + if (VIR_CLOSE(handshakefds[1]) < 0) { + virReportSystemError(errno, "%s", _("could not close handshake fd")); + goto cleanup; + } + + /* Connect to the controller as a client *first* because + * this will block until the child has written their + * pid file out to disk */ + if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) + goto cleanup; + + /* And get its pid */ + if ((r = virPidFileRead(driver->stateDir, vm->def->name, &vm->pid)) < 0) { + virReportSystemError(-r, + _("Failed to read pid file %s/%s.pid"), + driver->stateDir, vm->def->name); + goto cleanup; + } + + vm->def->id = vm->pid; + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); + + if (lxcContainerWaitForContinue(handshakefds[0]) < 0) { + char out[1024]; + + if (!(lxcReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("guest failed to start: %s"), out); + } + + goto error; + } + + if ((priv->monitorWatch = virEventAddHandle( + priv->monitor, + VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, + lxcMonitorEvent, + vm, NULL)) < 0) { + goto error; + } + + if (autoDestroy && + lxcProcessAutoDestroyAdd(driver, vm, conn) < 0) + goto error; + + if (virDomainObjSetDefTransient(driver->caps, vm, false) < 0) + goto error; + + /* Write domain status to disk. + * + * XXX: Earlier we wrote the plain "live" domain XML to this + * location for the benefit of libvirt_lxc. We're now overwriting + * it with the live status XML instead. This is a (currently + * harmless) inconsistency we should fix one day */ + if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) + goto error; + + /* finally we can call the 'started' hook script if any */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_STARTED, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto error; + } + + rc = 0; + +cleanup: + if (rc != 0 && !err) + err = virSaveLastError(); + virCommandFree(cmd); + if (VIR_CLOSE(logfd) < 0) { + virReportSystemError(errno, "%s", _("could not close logfile")); + rc = -1; + } + for (i = 0 ; i < nveths ; i++) { + if (rc != 0) + ignore_value(virNetDevVethDelete(veths[i])); + VIR_FREE(veths[i]); + } + if (rc != 0) { + VIR_FORCE_CLOSE(priv->monitor); + virDomainConfVMNWFilterTeardown(vm); + + virSecurityManagerRestoreAllLabel(driver->securityManager, + vm->def, false); + virSecurityManagerReleaseLabel(driver->securityManager, vm->def); + /* Clear out dynamically assigned labels */ + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabel.model); + VIR_FREE(vm->def->seclabel.label); + VIR_FREE(vm->def->seclabel.imagelabel); + } + } + for (i = 0 ; i < nttyFDs ; i++) + VIR_FORCE_CLOSE(ttyFDs[i]); + VIR_FREE(ttyFDs); + VIR_FORCE_CLOSE(handshakefds[0]); + VIR_FORCE_CLOSE(handshakefds[1]); + VIR_FREE(logfile); + + if (err) { + virSetError(err); + virFreeError(err); + } + + return rc; + +error: + err = virSaveLastError(); + lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + goto cleanup; +} + +struct lxcAutostartData { + lxc_driver_t *driver; + virConnectPtr conn; +}; + +static void +lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) +{ + virDomainObjPtr vm = payload; + const struct lxcAutostartData *data = opaque; + + virDomainObjLock(vm); + if (vm->autostart && + !virDomainObjIsActive(vm)) { + int ret = lxcVmStart(data->conn, data->driver, vm, false, + VIR_DOMAIN_RUNNING_BOOTED); + virDomainAuditStart(vm, "booted", ret >= 0); + if (ret < 0) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to autostart VM '%s': %s"), + vm->def->name, + err ? err->message : ""); + } else { + virDomainEventPtr event = + virDomainEventNewFromObj(vm, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_BOOTED); + if (event) + virDomainEventStateQueue(data->driver->domainEventState, event); + } + } + virDomainObjUnlock(vm); +} + + +void +lxcAutostartConfigs(lxc_driver_t *driver) { + /* XXX: Figure out a better way todo this. The domain + * startup code needs a connection handle in order + * to lookup the bridge associated with a virtual + * network + */ + virConnectPtr conn = virConnectOpen("lxc:///"); + /* Ignoring NULL conn which is mostly harmless here */ + + struct lxcAutostartData data = { driver, conn }; + + lxcDriverLock(driver); + virHashForEach(driver->domains.objs, lxcAutostartDomain, &data); + lxcDriverUnlock(driver); + + if (conn) + virConnectClose(conn); +} + +static void +lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) +{ + virDomainObjPtr vm = payload; + lxc_driver_t *driver = opaque; + lxcDomainObjPrivatePtr priv; + + virDomainObjLock(vm); + VIR_DEBUG("Reconnect %d %d %d\n", vm->def->id, vm->pid, vm->state.state); + + priv = vm->privateData; + + if (vm->pid != 0) { + vm->def->id = vm->pid; + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_UNKNOWN); + + if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) + goto error; + + if ((priv->monitorWatch = virEventAddHandle( + priv->monitor, + VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, + lxcMonitorEvent, + vm, NULL)) < 0) + goto error; + + if (virSecurityManagerReserveLabel(driver->securityManager, + vm->def, vm->pid) < 0) + goto error; + + /* now that we know it's reconnected call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + /* we can't stop the operation even if the script raised an error */ + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + if (hookret < 0) + goto error; + } + + } else { + vm->def->id = -1; + VIR_FORCE_CLOSE(priv->monitor); + } + +cleanup: + virDomainObjUnlock(vm); + return; + +error: + lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + virDomainAuditStop(vm, "failed"); + goto cleanup; +} + + +int lxcReconnectAll(lxc_driver_t *driver, + virDomainObjListPtr doms) +{ + virHashForEach(doms->objs, lxcReconnectVM, driver); + return 0; +} diff --git a/src/lxc/lxc_process.h b/src/lxc/lxc_process.h new file mode 100644 index 0000000..b4b707b --- /dev/null +++ b/src/lxc/lxc_process.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_process.h: LXC process lifecycle management + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LXC_PROCESS_H__ +# define __LXC_PROCESS_H__ + +# include "lxc_conf.h" + +int lxcVmStart(virConnectPtr conn, + lxc_driver_t * driver, + virDomainObjPtr vm, + bool autoDestroy, + virDomainRunningReason reason); +int lxcVmTerminate(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason); +int lxcProcessAutoDestroyInit(lxc_driver_t *driver); +void lxcProcessAutoDestroyRun(lxc_driver_t *driver, + virConnectPtr conn); +void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver); +int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, + virDomainObjPtr vm, + virConnectPtr conn); +int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, + virDomainObjPtr vm); + +void lxcAutostartConfigs(lxc_driver_t *driver); +int lxcReconnectAll(lxc_driver_t *driver, + virDomainObjListPtr doms); + +#endif /* __LXC_PROCESS_H__ */ -- 1.7.10.4

On Wed, Jul 18, 2012 at 05:32:31PM +0100, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Move all the code that manages stop/start of LXC processes into separate lxc_process.{c,h} file to make the lxc_driver.c file smaller
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/lxc/lxc_conf.h | 10 + src/lxc/lxc_driver.c | 1236 +----------------------------------------------- src/lxc/lxc_process.c | 1242 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_process.h | 49 ++ 6 files changed, 1313 insertions(+), 1226 deletions(-) create mode 100644 src/lxc/lxc_process.c create mode 100644 src/lxc/lxc_process.h
diff --git a/po/POTFILES.in b/po/POTFILES.in index 2d5735a..dc46941 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -47,6 +47,7 @@ src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c src/lxc/lxc_driver.c +src/lxc/lxc_process.c src/libxl/libxl_driver.c src/libxl/libxl_conf.c src/network/bridge_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index 9e16d06..59f1ac8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -352,6 +352,7 @@ LXC_DRIVER_SOURCES = \ lxc/lxc_container.c lxc/lxc_container.h \ lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ lxc/lxc_domain.c lxc/lxc_domain.h \ + lxc/lxc_process.c lxc/lxc_process.h \ lxc/lxc_driver.c lxc/lxc_driver.h
LXC_CONTROLLER_SOURCES = \ diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index cc279b2..937da16 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -78,4 +78,14 @@ virCapsPtr lxcCapsInit(lxc_driver_t *driver); virReportErrorHelper(VIR_FROM_LXC, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__)
+static inline void lxcDriverLock(lxc_driver_t *driver) +{ + virMutexLock(&driver->lock); +} +static inline void lxcDriverUnlock(lxc_driver_t *driver) +{ + virMutexUnlock(&driver->lock); +} + + #endif /* LXC_CONF_H */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index d3895d5..d7f052f 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -42,6 +42,7 @@ #include "lxc_container.h" #include "lxc_domain.h" #include "lxc_driver.h" +#include "lxc_process.h" #include "memory.h" #include "util.h" #include "virnetdevbridge.h" @@ -66,7 +67,6 @@
#define VIR_FROM_THIS VIR_FROM_LXC
-#define START_POSTFIX ": starting up\n"
#define LXC_NB_MEM_PARAM 3
@@ -76,31 +76,6 @@ static lxc_driver_t *lxc_driver = NULL;
/* Functions */
-static void lxcDriverLock(lxc_driver_t *driver) -{ - virMutexLock(&driver->lock); -} -static void lxcDriverUnlock(lxc_driver_t *driver) -{ - virMutexUnlock(&driver->lock); -} - -static void lxcDomainEventQueue(lxc_driver_t *driver, - virDomainEventPtr event); - -static int lxcVmTerminate(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason); -static int lxcProcessAutoDestroyInit(lxc_driver_t *driver); -static void lxcProcessAutoDestroyRun(lxc_driver_t *driver, - virConnectPtr conn); -static void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver); -static int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, - virDomainObjPtr vm, - virConnectPtr conn); -static int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, - virDomainObjPtr vm); -
static virDrvOpenStatus lxcOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, @@ -451,7 +426,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return dom; } @@ -504,7 +479,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return ret; } @@ -963,1075 +938,6 @@ cleanup: }
-static int lxcProcessAutoDestroyInit(lxc_driver_t *driver) -{ - if (!(driver->autodestroy = virHashCreate(5, NULL))) - return -1; - - return 0; -} - -struct lxcProcessAutoDestroyData { - lxc_driver_t *driver; - virConnectPtr conn; -}; - -static void lxcProcessAutoDestroyDom(void *payload, - const void *name, - void *opaque) -{ - struct lxcProcessAutoDestroyData *data = opaque; - virConnectPtr conn = payload; - const char *uuidstr = name; - unsigned char uuid[VIR_UUID_BUFLEN]; - virDomainObjPtr dom; - virDomainEventPtr event = NULL; - - VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn); - - if (data->conn != conn) - return; - - if (virUUIDParse(uuidstr, uuid) < 0) { - VIR_WARN("Failed to parse %s", uuidstr); - return; - } - - if (!(dom = virDomainFindByUUID(&data->driver->domains, - uuid))) { - VIR_DEBUG("No domain object to kill"); - return; - } - - VIR_DEBUG("Killing domain"); - lxcVmTerminate(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED); - virDomainAuditStop(dom, "destroyed"); - event = virDomainEventNewFromObj(dom, - VIR_DOMAIN_EVENT_STOPPED, - VIR_DOMAIN_EVENT_STOPPED_DESTROYED); - - if (dom && !dom->persistent) - virDomainRemoveInactive(&data->driver->domains, dom); - - if (dom) - virDomainObjUnlock(dom); - if (event) - lxcDomainEventQueue(data->driver, event); - virHashRemoveEntry(data->driver->autodestroy, uuidstr); -} - -/* - * Precondition: driver is locked - */ -static void lxcProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn) -{ - struct lxcProcessAutoDestroyData data = { - driver, conn - }; - VIR_DEBUG("conn=%p", conn); - virHashForEach(driver->autodestroy, lxcProcessAutoDestroyDom, &data); -} - -static void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver) -{ - virHashFree(driver->autodestroy); -} - -static int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, - virDomainObjPtr vm, - virConnectPtr conn) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(vm->def->uuid, uuidstr); - VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn); - if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0) - return -1; - return 0; -} - -static int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, - virDomainObjPtr vm) -{ - char uuidstr[VIR_UUID_STRING_BUFLEN]; - virUUIDFormat(vm->def->uuid, uuidstr); - VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr); - if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0) - return -1; - return 0; -} - - -/** - * lxcVmCleanup: - * @driver: pointer to driver structure - * @vm: pointer to VM to clean up - * @reason: reason for switching the VM to shutoff state - * - * Cleanout resources associated with the now dead VM - * - */ -static void lxcVmCleanup(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason) -{ - virCgroupPtr cgroup; - int i; - lxcDomainObjPrivatePtr priv = vm->privateData; - virNetDevVPortProfilePtr vport = NULL; - - /* now that we know it's stopped call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - - /* we can't stop the operation even if the script raised an error */ - virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_STOPPED, VIR_HOOK_SUBOP_END, - NULL, xml, NULL); - VIR_FREE(xml); - } - - /* Stop autodestroy in case guest is restarted */ - lxcProcessAutoDestroyRemove(driver, vm); - - virEventRemoveHandle(priv->monitorWatch); - VIR_FORCE_CLOSE(priv->monitor); - - virPidFileDelete(driver->stateDir, vm->def->name); - virDomainDeleteConfig(driver->stateDir, NULL, vm); - - virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason); - vm->pid = -1; - vm->def->id = -1; - priv->monitor = -1; - priv->monitorWatch = -1; - - for (i = 0 ; i < vm->def->nnets ; i++) { - virDomainNetDefPtr iface = vm->def->nets[i]; - vport = virDomainNetGetActualVirtPortProfile(iface); - ignore_value(virNetDevSetOnline(iface->ifname, false)); - if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) - ignore_value(virNetDevOpenvswitchRemovePort( - virDomainNetGetActualBridgeName(iface), - iface->ifname)); - ignore_value(virNetDevVethDelete(iface->ifname)); - networkReleaseActualDevice(iface); - } - - virDomainConfVMNWFilterTeardown(vm); - - if (driver->cgroup && - virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) { - virCgroupRemove(cgroup); - virCgroupFree(&cgroup); - } - - /* now that we know it's stopped call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - - /* we can't stop the operation even if the script raised an error */ - virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_RELEASE, VIR_HOOK_SUBOP_END, - NULL, xml, NULL); - VIR_FREE(xml); - } - - if (vm->newDef) { - virDomainDefFree(vm->def); - vm->def = vm->newDef; - vm->def->id = -1; - vm->newDef = NULL; - } -} - - -static int lxcSetupInterfaceBridged(virConnectPtr conn, - virDomainDefPtr vm, - virDomainNetDefPtr net, - const char *brname, - unsigned int *nveths, - char ***veths) -{ - int ret = -1; - char *parentVeth; - char *containerVeth = NULL; - const virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net); - - VIR_DEBUG("calling vethCreate()"); - parentVeth = net->ifname; - if (virNetDevVethCreate(&parentVeth, &containerVeth) < 0) - goto cleanup; - VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth); - - if (net->ifname == NULL) - net->ifname = parentVeth; - - if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { - virReportOOMError(); - VIR_FREE(containerVeth); - goto cleanup; - } - (*veths)[(*nveths)] = containerVeth; - (*nveths)++; - - if (virNetDevSetMAC(containerVeth, &net->mac) < 0) - goto cleanup; - - if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) - ret = virNetDevOpenvswitchAddPort(brname, parentVeth, &net->mac, - vm->uuid, vport); - else - ret = virNetDevBridgeAddPort(brname, parentVeth); - if (ret < 0) - goto cleanup; - - if (virNetDevSetOnline(parentVeth, true) < 0) - goto cleanup; - - if (virNetDevBandwidthSet(net->ifname, - virDomainNetGetActualBandwidth(net)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot set bandwidth limits on %s"), - net->ifname); - goto cleanup; - } - - if (net->filter && - virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0) - goto cleanup; - - ret = 0; - -cleanup: - return ret; -} - - -static int lxcSetupInterfaceDirect(virConnectPtr conn, - virDomainDefPtr def, - virDomainNetDefPtr net, - unsigned int *nveths, - char ***veths) -{ - int ret = 0; - char *res_ifname = NULL; - lxc_driver_t *driver = conn->privateData; - virNetDevBandwidthPtr bw; - virNetDevVPortProfilePtr prof; - - /* XXX how todo bandwidth controls ? - * Since the 'net-ifname' is about to be moved to a different - * namespace & renamed, there will be no host side visible - * interface for the container to attach rules to - */ - bw = virDomainNetGetActualBandwidth(net); - if (bw) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unable to set network bandwidth on direct interfaces")); - return -1; - } - - /* XXX how todo port profiles ? - * Although we can do the association during container - * startup, at shutdown we are unable to disassociate - * because the macvlan device was moved to the container - * and automagically dies when the container dies. So - * we have no dev to perform disassociation with. - */ - prof = virDomainNetGetActualVirtPortProfile(net); - if (prof) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unable to set port profile on direct interfaces")); - return -1; - } - - if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { - virReportOOMError(); - return -1; - } - (*veths)[(*nveths)] = NULL; - - if (virNetDevMacVLanCreateWithVPortProfile( - net->ifname, &net->mac, - virDomainNetGetActualDirectDev(net), - virDomainNetGetActualDirectMode(net), - false, false, def->uuid, - virDomainNetGetActualVirtPortProfile(net), - &res_ifname, - VIR_NETDEV_VPORT_PROFILE_OP_CREATE, - driver->stateDir, - virDomainNetGetActualBandwidth(net)) < 0) - goto cleanup; - - (*veths)[(*nveths)] = res_ifname; - (*nveths)++; - - ret = 0; - -cleanup: - return ret; -} - - -/** - * lxcSetupInterfaces: - * @conn: pointer to connection - * @def: pointer to virtual machine structure - * @nveths: number of interfaces - * @veths: interface names - * - * Sets up the container interfaces by creating the veth device pairs and - * attaching the parent end to the appropriate bridge. The container end - * will moved into the container namespace later after clone has been called. - * - * Returns 0 on success or -1 in case of error - */ -static int lxcSetupInterfaces(virConnectPtr conn, - virDomainDefPtr def, - unsigned int *nveths, - char ***veths) -{ - int ret = -1; - size_t i; - - for (i = 0 ; i < def->nnets ; i++) { - /* If appropriate, grab a physical device from the configured - * network's pool of devices, or resolve bridge device name - * to the one defined in the network definition. - */ - if (networkAllocateActualDevice(def->nets[i]) < 0) - goto cleanup; - - switch (virDomainNetGetActualType(def->nets[i])) { - case VIR_DOMAIN_NET_TYPE_NETWORK: { - virNetworkPtr network; - char *brname = NULL; - - if (!(network = virNetworkLookupByName(conn, - def->nets[i]->data.network.name))) - goto cleanup; - - brname = virNetworkGetBridgeName(network); - virNetworkFree(network); - if (!brname) - goto cleanup; - - if (lxcSetupInterfaceBridged(conn, - def, - def->nets[i], - brname, - nveths, - veths) < 0) { - VIR_FREE(brname); - goto cleanup; - } - VIR_FREE(brname); - break; - } - case VIR_DOMAIN_NET_TYPE_BRIDGE: { - const char *brname = virDomainNetGetActualBridgeName(def->nets[i]); - if (!brname) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("No bridge name specified")); - goto cleanup; - } - if (lxcSetupInterfaceBridged(conn, - def, - def->nets[i], - brname, - nveths, - veths) < 0) - goto cleanup; - } break; - - case VIR_DOMAIN_NET_TYPE_DIRECT: - if (lxcSetupInterfaceDirect(conn, - def, - def->nets[i], - nveths, - veths) < 0) - goto cleanup; - break; - - case VIR_DOMAIN_NET_TYPE_USER: - case VIR_DOMAIN_NET_TYPE_ETHERNET: - case VIR_DOMAIN_NET_TYPE_SERVER: - case VIR_DOMAIN_NET_TYPE_CLIENT: - case VIR_DOMAIN_NET_TYPE_MCAST: - case VIR_DOMAIN_NET_TYPE_INTERNAL: - case VIR_DOMAIN_NET_TYPE_LAST: - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unsupported network type %s"), - virDomainNetTypeToString( - virDomainNetGetActualType(def->nets[i]) - )); - goto cleanup; - } - } - - ret= 0; - -cleanup: - if (ret != 0) { - for (i = 0 ; i < def->nnets ; i++) { - virDomainNetDefPtr iface = def->nets[i]; - virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(iface); - if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) - ignore_value(virNetDevOpenvswitchRemovePort( - virDomainNetGetActualBridgeName(iface), - iface->ifname)); - networkReleaseActualDevice(iface); - } - } - return ret; -} - - -static int lxcMonitorClient(lxc_driver_t * driver, - virDomainObjPtr vm) -{ - char *sockpath = NULL; - int fd = -1; - struct sockaddr_un addr; - - if (virAsprintf(&sockpath, "%s/%s.sock", - driver->stateDir, vm->def->name) < 0) { - virReportOOMError(); - return -1; - } - - if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0) { - VIR_ERROR(_("Failed to set security context for monitor for %s"), - vm->def->name); - goto error; - } - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - - if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0) { - VIR_ERROR(_("Failed to clear security context for monitor for %s"), - vm->def->name); - goto error; - } - - if (fd < 0) { - virReportSystemError(errno, "%s", - _("Failed to create client socket")); - goto error; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Socket path %s too big for destination"), sockpath); - goto error; - } - - if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - virReportSystemError(errno, "%s", - _("Failed to connect to client socket")); - goto error; - } - - VIR_FREE(sockpath); - return fd; - -error: - VIR_FREE(sockpath); - VIR_FORCE_CLOSE(fd); - return -1; -} - - -static int lxcVmTerminate(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason) -{ - virCgroupPtr group = NULL; - int rc; - - if (vm->pid <= 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Invalid PID %d for container"), vm->pid); - return -1; - } - - virSecurityManagerRestoreAllLabel(driver->securityManager, - vm->def, false); - virSecurityManagerReleaseLabel(driver->securityManager, vm->def); - /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); - } - - if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) == 0) { - rc = virCgroupKillPainfully(group); - if (rc < 0) { - virReportSystemError(-rc, "%s", - _("Failed to kill container PIDs")); - rc = -1; - goto cleanup; - } - if (rc == 1) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Some container PIDs refused to die")); - rc = -1; - goto cleanup; - } - } else { - /* If cgroup doesn't exist, the VM pids must have already - * died and so we're just cleaning up stale state - */ - } - - lxcVmCleanup(driver, vm, reason); - - rc = 0; - -cleanup: - virCgroupFree(&group); - return rc; -} - -static void lxcMonitorEvent(int watch, - int fd, - int events ATTRIBUTE_UNUSED, - void *data) -{ - lxc_driver_t *driver = lxc_driver; - virDomainObjPtr vm = data; - virDomainEventPtr event = NULL; - lxcDomainObjPrivatePtr priv; - - lxcDriverLock(driver); - virDomainObjLock(vm); - lxcDriverUnlock(driver); - - priv = vm->privateData; - - if (priv->monitor != fd || priv->monitorWatch != watch) { - virEventRemoveHandle(watch); - goto cleanup; - } - - if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) { - virEventRemoveHandle(watch); - } else { - event = virDomainEventNewFromObj(vm, - VIR_DOMAIN_EVENT_STOPPED, - VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); - virDomainAuditStop(vm, "shutdown"); - } - if (!vm->persistent) { - virDomainRemoveInactive(&driver->domains, vm); - vm = NULL; - } - -cleanup: - if (vm) - virDomainObjUnlock(vm); - if (event) { - lxcDriverLock(driver); - lxcDomainEventQueue(driver, event); - lxcDriverUnlock(driver); - } -} - - -static virCommandPtr -lxcBuildControllerCmd(lxc_driver_t *driver, - virDomainObjPtr vm, - int nveths, - char **veths, - int *ttyFDs, - size_t nttyFDs, - int handshakefd) -{ - size_t i; - char *filterstr; - char *outputstr; - virCommandPtr cmd; - - cmd = virCommandNew(vm->def->emulator); - - /* The controller may call ip command, so we have to retain PATH. */ - virCommandAddEnvPass(cmd, "PATH"); - - virCommandAddEnvFormat(cmd, "LIBVIRT_DEBUG=%d", - virLogGetDefaultPriority()); - - if (virLogGetNbFilters() > 0) { - filterstr = virLogGetFilters(); - if (!filterstr) { - virReportOOMError(); - goto cleanup; - } - - virCommandAddEnvPair(cmd, "LIBVIRT_LOG_FILTERS", filterstr); - VIR_FREE(filterstr); - } - - if (driver->log_libvirtd) { - if (virLogGetNbOutputs() > 0) { - outputstr = virLogGetOutputs(); - if (!outputstr) { - virReportOOMError(); - goto cleanup; - } - - virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr); - VIR_FREE(outputstr); - } - } else { - virCommandAddEnvFormat(cmd, - "LIBVIRT_LOG_OUTPUTS=%d:stderr", - virLogGetDefaultPriority()); - } - - virCommandAddArgList(cmd, "--name", vm->def->name, NULL); - for (i = 0 ; i < nttyFDs ; i++) { - virCommandAddArg(cmd, "--console"); - virCommandAddArgFormat(cmd, "%d", ttyFDs[i]); - virCommandPreserveFD(cmd, ttyFDs[i]); - } - - virCommandAddArgPair(cmd, "--security", - virSecurityManagerGetModel(driver->securityManager)); - - virCommandAddArg(cmd, "--handshake"); - virCommandAddArgFormat(cmd, "%d", handshakefd); - virCommandAddArg(cmd, "--background"); - - for (i = 0 ; i < nveths ; i++) { - virCommandAddArgList(cmd, "--veth", veths[i], NULL); - } - - virCommandPreserveFD(cmd, handshakefd); - - return cmd; -cleanup: - virCommandFree(cmd); - return NULL; -} - -static int -lxcReadLogOutput(virDomainObjPtr vm, - char *logfile, - off_t pos, - char *buf, - size_t buflen) -{ - int fd; - off_t off; - int whence; - int got = 0, ret = -1; - int retries = 10; - - if ((fd = open(logfile, O_RDONLY)) < 0) { - virReportSystemError(errno, _("failed to open logfile %s"), - logfile); - goto cleanup; - } - - if (pos < 0) { - off = 0; - whence = SEEK_END; - } else { - off = pos; - whence = SEEK_SET; - } - - if (lseek(fd, off, whence) < 0) { - if (whence == SEEK_END) - virReportSystemError(errno, - _("unable to seek to end of log for %s"), - logfile); - else - virReportSystemError(errno, - _("unable to seek to %lld from start for %s"), - (long long)off, logfile); - goto cleanup; - } - - while (retries) { - ssize_t bytes; - int isdead = 0; - - if (kill(vm->pid, 0) == -1 && errno == ESRCH) - isdead = 1; - - /* Any failures should be detected before we read the log, so we - * always have something useful to report on failure. */ - bytes = saferead(fd, buf+got, buflen-got-1); - if (bytes < 0) { - virReportSystemError(errno, "%s", - _("Failure while reading guest log output")); - goto cleanup; - } - - got += bytes; - buf[got] = '\0'; - - if ((got == buflen-1) || isdead) { - break; - } - - usleep(100*1000); - retries--; - } - - - ret = got; -cleanup: - VIR_FORCE_CLOSE(fd); - return ret; -} - -/** - * lxcVmStart: - * @conn: pointer to connection - * @driver: pointer to driver structure - * @vm: pointer to virtual machine structure - * @autoDestroy: mark the domain for auto destruction - * @reason: reason for switching vm to running state - * - * Starts a vm - * - * Returns 0 on success or -1 in case of error - */ -static int lxcVmStart(virConnectPtr conn, - lxc_driver_t * driver, - virDomainObjPtr vm, - bool autoDestroy, - virDomainRunningReason reason) -{ - int rc = -1, r; - size_t nttyFDs = 0; - int *ttyFDs = NULL; - size_t i; - char *logfile = NULL; - int logfd = -1; - unsigned int nveths = 0; - char **veths = NULL; - int handshakefds[2] = { -1, -1 }; - off_t pos = -1; - char ebuf[1024]; - char *timestamp; - virCommandPtr cmd = NULL; - lxcDomainObjPrivatePtr priv = vm->privateData; - virErrorPtr err = NULL; - - if (!lxc_driver->cgroup) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("The 'cpuacct', 'devices' & 'memory' cgroups controllers must be mounted")); - return -1; - } - - if (!virCgroupMounted(lxc_driver->cgroup, - VIR_CGROUP_CONTROLLER_CPUACCT)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'cpuacct' cgroups controller mount")); - return -1; - } - if (!virCgroupMounted(lxc_driver->cgroup, - VIR_CGROUP_CONTROLLER_DEVICES)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'devices' cgroups controller mount")); - return -1; - } - if (!virCgroupMounted(lxc_driver->cgroup, - VIR_CGROUP_CONTROLLER_MEMORY)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'memory' cgroups controller mount")); - return -1; - } - - if (virFileMakePath(driver->logDir) < 0) { - virReportSystemError(errno, - _("Cannot create log directory '%s'"), - driver->logDir); - return -1; - } - - if (virAsprintf(&logfile, "%s/%s.log", - driver->logDir, vm->def->name) < 0) { - virReportOOMError(); - return -1; - } - - /* Do this up front, so any part of the startup process can add - * runtime state to vm->def that won't be persisted. This let's us - * report implicit runtime defaults in the XML, like vnc listen/socket - */ - VIR_DEBUG("Setting current domain def as transient"); - if (virDomainObjSetDefTransient(driver->caps, vm, true) < 0) - goto cleanup; - - /* Run an early hook to set-up missing devices */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - - /* - * If the script raised an error abort the launch - */ - if (hookret < 0) - goto cleanup; - } - - /* Here we open all the PTYs we need on the host OS side. - * The LXC controller will open the guest OS side PTYs - * and forward I/O between them. - */ - nttyFDs = vm->def->nconsoles; - if (VIR_ALLOC_N(ttyFDs, nttyFDs) < 0) { - virReportOOMError(); - goto cleanup; - } - - /* If you are using a SecurityDriver with dynamic labelling, - then generate a security label for isolation */ - VIR_DEBUG("Generating domain security label (if required)"); - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DEFAULT) - vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_NONE; - - if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { - virDomainAuditSecurityLabel(vm, false); - goto cleanup; - } - virDomainAuditSecurityLabel(vm, true); - - VIR_DEBUG("Setting domain security labels"); - if (virSecurityManagerSetAllLabel(driver->securityManager, - vm->def, NULL) < 0) - goto cleanup; - - for (i = 0 ; i < vm->def->nconsoles ; i++) - ttyFDs[i] = -1; - - for (i = 0 ; i < vm->def->nconsoles ; i++) { - char *ttyPath; - if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only PTY console types are supported")); - goto cleanup; - } - - if (virFileOpenTty(&ttyFDs[i], &ttyPath, 1) < 0) { - virReportSystemError(errno, "%s", - _("Failed to allocate tty")); - goto cleanup; - } - - VIR_FREE(vm->def->consoles[i]->source.data.file.path); - vm->def->consoles[i]->source.data.file.path = ttyPath; - - VIR_FREE(vm->def->consoles[i]->info.alias); - if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) { - virReportOOMError(); - goto cleanup; - } - } - - if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0) - goto cleanup; - - /* Save the configuration for the controller */ - if (virDomainSaveConfig(driver->stateDir, vm->def) < 0) - goto cleanup; - - if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, - S_IRUSR|S_IWUSR)) < 0) { - virReportSystemError(errno, - _("Failed to open '%s'"), - logfile); - goto cleanup; - } - - if (pipe(handshakefds) < 0) { - virReportSystemError(errno, "%s", - _("Unable to create pipe")); - goto cleanup; - } - - if (!(cmd = lxcBuildControllerCmd(driver, - vm, - nveths, veths, - ttyFDs, nttyFDs, - handshakefds[1]))) - goto cleanup; - virCommandSetOutputFD(cmd, &logfd); - virCommandSetErrorFD(cmd, &logfd); - - /* now that we know it is about to start call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - - /* - * If the script raised an error abort the launch - */ - if (hookret < 0) - goto cleanup; - } - - /* Log timestamp */ - if ((timestamp = virTimeStringNow()) == NULL) { - virReportOOMError(); - goto cleanup; - } - if (safewrite(logfd, timestamp, strlen(timestamp)) < 0 || - safewrite(logfd, START_POSTFIX, strlen(START_POSTFIX)) < 0) { - VIR_WARN("Unable to write timestamp to logfile: %s", - virStrerror(errno, ebuf, sizeof(ebuf))); - } - VIR_FREE(timestamp); - - /* Log generated command line */ - virCommandWriteArgLog(cmd, logfd); - if ((pos = lseek(logfd, 0, SEEK_END)) < 0) - VIR_WARN("Unable to seek to end of logfile: %s", - virStrerror(errno, ebuf, sizeof(ebuf))); - - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - if (VIR_CLOSE(handshakefds[1]) < 0) { - virReportSystemError(errno, "%s", _("could not close handshake fd")); - goto cleanup; - } - - /* Connect to the controller as a client *first* because - * this will block until the child has written their - * pid file out to disk */ - if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) - goto cleanup; - - /* And get its pid */ - if ((r = virPidFileRead(driver->stateDir, vm->def->name, &vm->pid)) < 0) { - virReportSystemError(-r, - _("Failed to read pid file %s/%s.pid"), - driver->stateDir, vm->def->name); - goto cleanup; - } - - vm->def->id = vm->pid; - virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); - - if (lxcContainerWaitForContinue(handshakefds[0]) < 0) { - char out[1024]; - - if (!(lxcReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("guest failed to start: %s"), out); - } - - goto error; - } - - if ((priv->monitorWatch = virEventAddHandle( - priv->monitor, - VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, - lxcMonitorEvent, - vm, NULL)) < 0) { - goto error; - } - - if (autoDestroy && - lxcProcessAutoDestroyAdd(driver, vm, conn) < 0) - goto error; - - if (virDomainObjSetDefTransient(driver->caps, vm, false) < 0) - goto error; - - /* Write domain status to disk. - * - * XXX: Earlier we wrote the plain "live" domain XML to this - * location for the benefit of libvirt_lxc. We're now overwriting - * it with the live status XML instead. This is a (currently - * harmless) inconsistency we should fix one day */ - if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) - goto error; - - /* finally we can call the 'started' hook script if any */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_STARTED, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - - /* - * If the script raised an error abort the launch - */ - if (hookret < 0) - goto error; - } - - rc = 0; - -cleanup: - if (rc != 0 && !err) - err = virSaveLastError(); - virCommandFree(cmd); - if (VIR_CLOSE(logfd) < 0) { - virReportSystemError(errno, "%s", _("could not close logfile")); - rc = -1; - } - for (i = 0 ; i < nveths ; i++) { - if (rc != 0) - ignore_value(virNetDevVethDelete(veths[i])); - VIR_FREE(veths[i]); - } - if (rc != 0) { - VIR_FORCE_CLOSE(priv->monitor); - virDomainConfVMNWFilterTeardown(vm); - - virSecurityManagerRestoreAllLabel(driver->securityManager, - vm->def, false); - virSecurityManagerReleaseLabel(driver->securityManager, vm->def); - /* Clear out dynamically assigned labels */ - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); - } - } - for (i = 0 ; i < nttyFDs ; i++) - VIR_FORCE_CLOSE(ttyFDs[i]); - VIR_FREE(ttyFDs); - VIR_FORCE_CLOSE(handshakefds[0]); - VIR_FORCE_CLOSE(handshakefds[1]); - VIR_FREE(logfile); - - if (err) { - virSetError(err); - virFreeError(err); - } - - return rc; - -error: - err = virSaveLastError(); - lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); - goto cleanup; -} - /** * lxcDomainStartWithFlags: * @dom: domain to start @@ -2089,7 +995,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return ret; } @@ -2176,7 +1082,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return dom; } @@ -2354,13 +1260,6 @@ lxcDomainEventDeregisterAny(virConnectPtr conn, }
-/* driver must be locked before calling */ -static void lxcDomainEventQueue(lxc_driver_t *driver, - virDomainEventPtr event) -{ - virDomainEventStateQueue(driver->domainEventState, event); -} - /** * lxcDomainDestroyFlags: * @dom: pointer to domain to destroy @@ -2411,7 +1310,7 @@ cleanup: if (vm) virDomainObjUnlock(vm); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); lxcDriverUnlock(driver); return ret; } @@ -2446,121 +1345,6 @@ static int lxcCheckNetNsSupport(void) }
-struct lxcAutostartData { - lxc_driver_t *driver; - virConnectPtr conn; -}; - -static void -lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) -{ - virDomainObjPtr vm = payload; - const struct lxcAutostartData *data = opaque; - - virDomainObjLock(vm); - if (vm->autostart && - !virDomainObjIsActive(vm)) { - int ret = lxcVmStart(data->conn, data->driver, vm, false, - VIR_DOMAIN_RUNNING_BOOTED); - virDomainAuditStart(vm, "booted", ret >= 0); - if (ret < 0) { - virErrorPtr err = virGetLastError(); - VIR_ERROR(_("Failed to autostart VM '%s': %s"), - vm->def->name, - err ? err->message : ""); - } else { - virDomainEventPtr event = - virDomainEventNewFromObj(vm, - VIR_DOMAIN_EVENT_STARTED, - VIR_DOMAIN_EVENT_STARTED_BOOTED); - if (event) - lxcDomainEventQueue(data->driver, event); - } - } - virDomainObjUnlock(vm); -} - -static void -lxcAutostartConfigs(lxc_driver_t *driver) { - /* XXX: Figure out a better way todo this. The domain - * startup code needs a connection handle in order - * to lookup the bridge associated with a virtual - * network - */ - virConnectPtr conn = virConnectOpen("lxc:///"); - /* Ignoring NULL conn which is mostly harmless here */ - - struct lxcAutostartData data = { driver, conn }; - - lxcDriverLock(driver); - virHashForEach(driver->domains.objs, lxcAutostartDomain, &data); - lxcDriverUnlock(driver); - - if (conn) - virConnectClose(conn); -} - -static void -lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) -{ - virDomainObjPtr vm = payload; - lxc_driver_t *driver = opaque; - lxcDomainObjPrivatePtr priv; - - virDomainObjLock(vm); - VIR_DEBUG("Reconnect %d %d %d\n", vm->def->id, vm->pid, vm->state.state); - - priv = vm->privateData; - - if (vm->pid != 0) { - vm->def->id = vm->pid; - virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, - VIR_DOMAIN_RUNNING_UNKNOWN); - - if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) - goto error; - - if ((priv->monitorWatch = virEventAddHandle( - priv->monitor, - VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, - lxcMonitorEvent, - vm, NULL)) < 0) - goto error; - - if (virSecurityManagerReserveLabel(driver->securityManager, - vm->def, vm->pid) < 0) - goto error; - - /* now that we know it's reconnected call the hook if present */ - if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { - char *xml = virDomainDefFormat(vm->def, 0); - int hookret; - - /* we can't stop the operation even if the script raised an error */ - hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, - VIR_HOOK_LXC_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN, - NULL, xml, NULL); - VIR_FREE(xml); - if (hookret < 0) - goto error; - } - - } else { - vm->def->id = -1; - VIR_FORCE_CLOSE(priv->monitor); - } - -cleanup: - virDomainObjUnlock(vm); - return; - -error: - lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); - virDomainAuditStop(vm, "failed"); - goto cleanup; -} - - static int lxcSecurityInit(lxc_driver_t *driver) { @@ -2664,7 +1448,7 @@ static int lxcStartup(int privileged) NULL, NULL) < 0) goto cleanup;
- virHashForEach(lxc_driver->domains.objs, lxcReconnectVM, lxc_driver); + lxcReconnectAll(lxc_driver, &lxc_driver->domains);
/* Then inactive persistent configs */ if (virDomainLoadAllConfigs(lxc_driver->caps, @@ -2697,7 +1481,7 @@ static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque) VIR_DOMAIN_EVENT_DEFINED, VIR_DOMAIN_EVENT_DEFINED_ADDED); if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); } }
@@ -3706,7 +2490,7 @@ static int lxcDomainSuspend(virDomainPtr dom)
cleanup: if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); if (vm) virDomainObjUnlock(vm); lxcDriverUnlock(driver); @@ -3772,7 +2556,7 @@ static int lxcDomainResume(virDomainPtr dom)
cleanup: if (event) - lxcDomainEventQueue(driver, event); + virDomainEventStateQueue(driver->domainEventState, event); if (vm) virDomainObjUnlock(vm); lxcDriverUnlock(driver); diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c new file mode 100644 index 0000000..12f6ae6 --- /dev/null +++ b/src/lxc/lxc_process.c @@ -0,0 +1,1242 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_process.c: LXC process lifecycle management + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <config.h> + +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> + +#include "lxc_process.h" +#include "lxc_domain.h" +#include "lxc_container.h" +#include "datatypes.h" +#include "virfile.h" +#include "virpidfile.h" +#include "virnetdev.h" +#include "virnetdevveth.h" +#include "virnetdevbridge.h" +#include "virtime.h" +#include "domain_nwfilter.h" +#include "network/bridge_driver.h" +#include "memory.h" +#include "domain_audit.h" +#include "virterror_internal.h" +#include "logging.h" +#include "command.h" +#include "hooks.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +#define START_POSTFIX ": starting up\n" + +int lxcProcessAutoDestroyInit(lxc_driver_t *driver) +{ + if (!(driver->autodestroy = virHashCreate(5, NULL))) + return -1; + + return 0; +} + +struct lxcProcessAutoDestroyData { + lxc_driver_t *driver; + virConnectPtr conn; +}; + +static void lxcProcessAutoDestroyDom(void *payload, + const void *name, + void *opaque) +{ + struct lxcProcessAutoDestroyData *data = opaque; + virConnectPtr conn = payload; + const char *uuidstr = name; + unsigned char uuid[VIR_UUID_BUFLEN]; + virDomainObjPtr dom; + virDomainEventPtr event = NULL; + + VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn); + + if (data->conn != conn) + return; + + if (virUUIDParse(uuidstr, uuid) < 0) { + VIR_WARN("Failed to parse %s", uuidstr); + return; + } + + if (!(dom = virDomainFindByUUID(&data->driver->domains, + uuid))) { + VIR_DEBUG("No domain object to kill"); + return; + } + + VIR_DEBUG("Killing domain"); + lxcVmTerminate(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED); + virDomainAuditStop(dom, "destroyed"); + event = virDomainEventNewFromObj(dom, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_DESTROYED); + + if (dom && !dom->persistent) + virDomainRemoveInactive(&data->driver->domains, dom); + + if (dom) + virDomainObjUnlock(dom); + if (event) + virDomainEventStateQueue(data->driver->domainEventState, event); + virHashRemoveEntry(data->driver->autodestroy, uuidstr); +} + +/* + * Precondition: driver is locked + */ +void lxcProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn) +{ + struct lxcProcessAutoDestroyData data = { + driver, conn + }; + VIR_DEBUG("conn=%p", conn); + virHashForEach(driver->autodestroy, lxcProcessAutoDestroyDom, &data); +} + +void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver) +{ + virHashFree(driver->autodestroy); +} + +int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, + virDomainObjPtr vm, + virConnectPtr conn) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(vm->def->uuid, uuidstr); + VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn); + if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0) + return -1; + return 0; +} + +int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, + virDomainObjPtr vm) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(vm->def->uuid, uuidstr); + VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr); + if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0) + return -1; + return 0; +} + + +/** + * lxcVmCleanup: + * @driver: pointer to driver structure + * @vm: pointer to VM to clean up + * @reason: reason for switching the VM to shutoff state + * + * Cleanout resources associated with the now dead VM + * + */ +static void lxcVmCleanup(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason) +{ + virCgroupPtr cgroup; + int i; + lxcDomainObjPrivatePtr priv = vm->privateData; + virNetDevVPortProfilePtr vport = NULL; + + /* now that we know it's stopped call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + + /* we can't stop the operation even if the script raised an error */ + virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_STOPPED, VIR_HOOK_SUBOP_END, + NULL, xml, NULL); + VIR_FREE(xml); + } + + /* Stop autodestroy in case guest is restarted */ + lxcProcessAutoDestroyRemove(driver, vm); + + virEventRemoveHandle(priv->monitorWatch); + VIR_FORCE_CLOSE(priv->monitor); + + virPidFileDelete(driver->stateDir, vm->def->name); + virDomainDeleteConfig(driver->stateDir, NULL, vm); + + virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason); + vm->pid = -1; + vm->def->id = -1; + priv->monitor = -1; + priv->monitorWatch = -1; + + for (i = 0 ; i < vm->def->nnets ; i++) { + virDomainNetDefPtr iface = vm->def->nets[i]; + vport = virDomainNetGetActualVirtPortProfile(iface); + ignore_value(virNetDevSetOnline(iface->ifname, false)); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(iface), + iface->ifname)); + ignore_value(virNetDevVethDelete(iface->ifname)); + networkReleaseActualDevice(iface); + } + + virDomainConfVMNWFilterTeardown(vm); + + if (driver->cgroup && + virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) { + virCgroupRemove(cgroup); + virCgroupFree(&cgroup); + } + + /* now that we know it's stopped call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + + /* we can't stop the operation even if the script raised an error */ + virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_RELEASE, VIR_HOOK_SUBOP_END, + NULL, xml, NULL); + VIR_FREE(xml); + } + + if (vm->newDef) { + virDomainDefFree(vm->def); + vm->def = vm->newDef; + vm->def->id = -1; + vm->newDef = NULL; + } +} + + +static int lxcSetupInterfaceBridged(virConnectPtr conn, + virDomainDefPtr vm, + virDomainNetDefPtr net, + const char *brname, + unsigned int *nveths, + char ***veths) +{ + int ret = -1; + char *parentVeth; + char *containerVeth = NULL; + const virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net); + + VIR_DEBUG("calling vethCreate()"); + parentVeth = net->ifname; + if (virNetDevVethCreate(&parentVeth, &containerVeth) < 0) + goto cleanup; + VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth); + + if (net->ifname == NULL) + net->ifname = parentVeth; + + if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { + virReportOOMError(); + VIR_FREE(containerVeth); + goto cleanup; + } + (*veths)[(*nveths)] = containerVeth; + (*nveths)++; + + if (virNetDevSetMAC(containerVeth, &net->mac) < 0) + goto cleanup; + + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ret = virNetDevOpenvswitchAddPort(brname, parentVeth, &net->mac, + vm->uuid, vport); + else + ret = virNetDevBridgeAddPort(brname, parentVeth); + if (ret < 0) + goto cleanup; + + if (virNetDevSetOnline(parentVeth, true) < 0) + goto cleanup; + + if (virNetDevBandwidthSet(net->ifname, + virDomainNetGetActualBandwidth(net)) < 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("cannot set bandwidth limits on %s"), + net->ifname); + goto cleanup; + } + + if (net->filter && + virDomainConfNWFilterInstantiate(conn, vm->uuid, net) < 0) + goto cleanup; + + ret = 0; + +cleanup: + return ret; +} + + +static int lxcSetupInterfaceDirect(virConnectPtr conn, + virDomainDefPtr def, + virDomainNetDefPtr net, + unsigned int *nveths, + char ***veths) +{ + int ret = 0; + char *res_ifname = NULL; + lxc_driver_t *driver = conn->privateData; + virNetDevBandwidthPtr bw; + virNetDevVPortProfilePtr prof; + + /* XXX how todo bandwidth controls ? + * Since the 'net-ifname' is about to be moved to a different + * namespace & renamed, there will be no host side visible + * interface for the container to attach rules to + */ + bw = virDomainNetGetActualBandwidth(net); + if (bw) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set network bandwidth on direct interfaces")); + return -1; + } + + /* XXX how todo port profiles ? + * Although we can do the association during container + * startup, at shutdown we are unable to disassociate + * because the macvlan device was moved to the container + * and automagically dies when the container dies. So + * we have no dev to perform disassociation with. + */ + prof = virDomainNetGetActualVirtPortProfile(net); + if (prof) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set port profile on direct interfaces")); + return -1; + } + + if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) { + virReportOOMError(); + return -1; + } + (*veths)[(*nveths)] = NULL; + + if (virNetDevMacVLanCreateWithVPortProfile( + net->ifname, &net->mac, + virDomainNetGetActualDirectDev(net), + virDomainNetGetActualDirectMode(net), + false, false, def->uuid, + virDomainNetGetActualVirtPortProfile(net), + &res_ifname, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, + driver->stateDir, + virDomainNetGetActualBandwidth(net)) < 0) + goto cleanup; + + (*veths)[(*nveths)] = res_ifname; + (*nveths)++; + + ret = 0; + +cleanup: + return ret; +} + + +/** + * lxcSetupInterfaces: + * @conn: pointer to connection + * @def: pointer to virtual machine structure + * @nveths: number of interfaces + * @veths: interface names + * + * Sets up the container interfaces by creating the veth device pairs and + * attaching the parent end to the appropriate bridge. The container end + * will moved into the container namespace later after clone has been called. + * + * Returns 0 on success or -1 in case of error + */ +static int lxcSetupInterfaces(virConnectPtr conn, + virDomainDefPtr def, + unsigned int *nveths, + char ***veths) +{ + int ret = -1; + size_t i; + + for (i = 0 ; i < def->nnets ; i++) { + /* If appropriate, grab a physical device from the configured + * network's pool of devices, or resolve bridge device name + * to the one defined in the network definition. + */ + if (networkAllocateActualDevice(def->nets[i]) < 0) + goto cleanup; + + switch (virDomainNetGetActualType(def->nets[i])) { + case VIR_DOMAIN_NET_TYPE_NETWORK: { + virNetworkPtr network; + char *brname = NULL; + + if (!(network = virNetworkLookupByName(conn, + def->nets[i]->data.network.name))) + goto cleanup; + + brname = virNetworkGetBridgeName(network); + virNetworkFree(network); + if (!brname) + goto cleanup; + + if (lxcSetupInterfaceBridged(conn, + def, + def->nets[i], + brname, + nveths, + veths) < 0) { + VIR_FREE(brname); + goto cleanup; + } + VIR_FREE(brname); + break; + } + case VIR_DOMAIN_NET_TYPE_BRIDGE: { + const char *brname = virDomainNetGetActualBridgeName(def->nets[i]); + if (!brname) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No bridge name specified")); + goto cleanup; + } + if (lxcSetupInterfaceBridged(conn, + def, + def->nets[i], + brname, + nveths, + veths) < 0) + goto cleanup; + } break; + + case VIR_DOMAIN_NET_TYPE_DIRECT: + if (lxcSetupInterfaceDirect(conn, + def, + def->nets[i], + nveths, + veths) < 0) + goto cleanup; + break; + + case VIR_DOMAIN_NET_TYPE_USER: + case VIR_DOMAIN_NET_TYPE_ETHERNET: + case VIR_DOMAIN_NET_TYPE_SERVER: + case VIR_DOMAIN_NET_TYPE_CLIENT: + case VIR_DOMAIN_NET_TYPE_MCAST: + case VIR_DOMAIN_NET_TYPE_INTERNAL: + case VIR_DOMAIN_NET_TYPE_LAST: + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Unsupported network type %s"), + virDomainNetTypeToString( + virDomainNetGetActualType(def->nets[i]) + )); + goto cleanup; + } + } + + ret= 0; + +cleanup: + if (ret != 0) { + for (i = 0 ; i < def->nnets ; i++) { + virDomainNetDefPtr iface = def->nets[i]; + virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(iface); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(iface), + iface->ifname)); + networkReleaseActualDevice(iface); + } + } + return ret; +} + + +static int lxcMonitorClient(lxc_driver_t * driver, + virDomainObjPtr vm) +{ + char *sockpath = NULL; + int fd = -1; + struct sockaddr_un addr; + + if (virAsprintf(&sockpath, "%s/%s.sock", + driver->stateDir, vm->def->name) < 0) { + virReportOOMError(); + return -1; + } + + if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0) { + VIR_ERROR(_("Failed to set security context for monitor for %s"), + vm->def->name); + goto error; + } + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + + if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0) { + VIR_ERROR(_("Failed to clear security context for monitor for %s"), + vm->def->name); + goto error; + } + + if (fd < 0) { + virReportSystemError(errno, "%s", + _("Failed to create client socket")); + goto error; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Socket path %s too big for destination"), sockpath); + goto error; + } + + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + virReportSystemError(errno, "%s", + _("Failed to connect to client socket")); + goto error; + } + + VIR_FREE(sockpath); + return fd; + +error: + VIR_FREE(sockpath); + VIR_FORCE_CLOSE(fd); + return -1; +} + + +int lxcVmTerminate(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason) +{ + virCgroupPtr group = NULL; + int rc; + + if (vm->pid <= 0) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("Invalid PID %d for container"), vm->pid); + return -1; + } + + virSecurityManagerRestoreAllLabel(driver->securityManager, + vm->def, false); + virSecurityManagerReleaseLabel(driver->securityManager, vm->def); + /* Clear out dynamically assigned labels */ + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabel.model); + VIR_FREE(vm->def->seclabel.label); + VIR_FREE(vm->def->seclabel.imagelabel); + } + + if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) == 0) { + rc = virCgroupKillPainfully(group); + if (rc < 0) { + virReportSystemError(-rc, "%s", + _("Failed to kill container PIDs")); + rc = -1; + goto cleanup; + } + if (rc == 1) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Some container PIDs refused to die")); + rc = -1; + goto cleanup; + } + } else { + /* If cgroup doesn't exist, the VM pids must have already + * died and so we're just cleaning up stale state + */ + } + + lxcVmCleanup(driver, vm, reason); + + rc = 0; + +cleanup: + virCgroupFree(&group); + return rc; +} + +extern lxc_driver_t *lxc_driver; +static void lxcMonitorEvent(int watch, + int fd, + int events ATTRIBUTE_UNUSED, + void *data) +{ + lxc_driver_t *driver = lxc_driver; + virDomainObjPtr vm = data; + virDomainEventPtr event = NULL; + lxcDomainObjPrivatePtr priv; + + lxcDriverLock(driver); + virDomainObjLock(vm); + lxcDriverUnlock(driver); + + priv = vm->privateData; + + if (priv->monitor != fd || priv->monitorWatch != watch) { + virEventRemoveHandle(watch); + goto cleanup; + } + + if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) { + virEventRemoveHandle(watch); + } else { + event = virDomainEventNewFromObj(vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); + virDomainAuditStop(vm, "shutdown"); + } + if (!vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + if (event) { + lxcDriverLock(driver); + virDomainEventStateQueue(driver->domainEventState, event); + lxcDriverUnlock(driver); + } +} + + +static virCommandPtr +lxcBuildControllerCmd(lxc_driver_t *driver, + virDomainObjPtr vm, + int nveths, + char **veths, + int *ttyFDs, + size_t nttyFDs, + int handshakefd) +{ + size_t i; + char *filterstr; + char *outputstr; + virCommandPtr cmd; + + cmd = virCommandNew(vm->def->emulator); + + /* The controller may call ip command, so we have to retain PATH. */ + virCommandAddEnvPass(cmd, "PATH"); + + virCommandAddEnvFormat(cmd, "LIBVIRT_DEBUG=%d", + virLogGetDefaultPriority()); + + if (virLogGetNbFilters() > 0) { + filterstr = virLogGetFilters(); + if (!filterstr) { + virReportOOMError(); + goto cleanup; + } + + virCommandAddEnvPair(cmd, "LIBVIRT_LOG_FILTERS", filterstr); + VIR_FREE(filterstr); + } + + if (driver->log_libvirtd) { + if (virLogGetNbOutputs() > 0) { + outputstr = virLogGetOutputs(); + if (!outputstr) { + virReportOOMError(); + goto cleanup; + } + + virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr); + VIR_FREE(outputstr); + } + } else { + virCommandAddEnvFormat(cmd, + "LIBVIRT_LOG_OUTPUTS=%d:stderr", + virLogGetDefaultPriority()); + } + + virCommandAddArgList(cmd, "--name", vm->def->name, NULL); + for (i = 0 ; i < nttyFDs ; i++) { + virCommandAddArg(cmd, "--console"); + virCommandAddArgFormat(cmd, "%d", ttyFDs[i]); + virCommandPreserveFD(cmd, ttyFDs[i]); + } + + virCommandAddArgPair(cmd, "--security", + virSecurityManagerGetModel(driver->securityManager)); + + virCommandAddArg(cmd, "--handshake"); + virCommandAddArgFormat(cmd, "%d", handshakefd); + virCommandAddArg(cmd, "--background"); + + for (i = 0 ; i < nveths ; i++) { + virCommandAddArgList(cmd, "--veth", veths[i], NULL); + } + + virCommandPreserveFD(cmd, handshakefd); + + return cmd; +cleanup: + virCommandFree(cmd); + return NULL; +} + +static int +lxcReadLogOutput(virDomainObjPtr vm, + char *logfile, + off_t pos, + char *buf, + size_t buflen) +{ + int fd; + off_t off; + int whence; + int got = 0, ret = -1; + int retries = 10; + + if ((fd = open(logfile, O_RDONLY)) < 0) { + virReportSystemError(errno, _("failed to open logfile %s"), + logfile); + goto cleanup; + } + + if (pos < 0) { + off = 0; + whence = SEEK_END; + } else { + off = pos; + whence = SEEK_SET; + } + + if (lseek(fd, off, whence) < 0) { + if (whence == SEEK_END) + virReportSystemError(errno, + _("unable to seek to end of log for %s"), + logfile); + else + virReportSystemError(errno, + _("unable to seek to %lld from start for %s"), + (long long)off, logfile); + goto cleanup; + } + + while (retries) { + ssize_t bytes; + int isdead = 0; + + if (kill(vm->pid, 0) == -1 && errno == ESRCH) + isdead = 1; + + /* Any failures should be detected before we read the log, so we + * always have something useful to report on failure. */ + bytes = saferead(fd, buf+got, buflen-got-1); + if (bytes < 0) { + virReportSystemError(errno, "%s", + _("Failure while reading guest log output")); + goto cleanup; + } + + got += bytes; + buf[got] = '\0'; + + if ((got == buflen-1) || isdead) { + break; + } + + usleep(100*1000); + retries--; + } + + + ret = got; +cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} + +/** + * lxcVmStart: + * @conn: pointer to connection + * @driver: pointer to driver structure + * @vm: pointer to virtual machine structure + * @autoDestroy: mark the domain for auto destruction + * @reason: reason for switching vm to running state + * + * Starts a vm + * + * Returns 0 on success or -1 in case of error + */ +int lxcVmStart(virConnectPtr conn, + lxc_driver_t * driver, + virDomainObjPtr vm, + bool autoDestroy, + virDomainRunningReason reason) +{ + int rc = -1, r; + size_t nttyFDs = 0; + int *ttyFDs = NULL; + size_t i; + char *logfile = NULL; + int logfd = -1; + unsigned int nveths = 0; + char **veths = NULL; + int handshakefds[2] = { -1, -1 }; + off_t pos = -1; + char ebuf[1024]; + char *timestamp; + virCommandPtr cmd = NULL; + lxcDomainObjPrivatePtr priv = vm->privateData; + virErrorPtr err = NULL; + + if (!lxc_driver->cgroup) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("The 'cpuacct', 'devices' & 'memory' cgroups controllers must be mounted")); + return -1; + } + + if (!virCgroupMounted(lxc_driver->cgroup, + VIR_CGROUP_CONTROLLER_CPUACCT)) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'cpuacct' cgroups controller mount")); + return -1; + } + if (!virCgroupMounted(lxc_driver->cgroup, + VIR_CGROUP_CONTROLLER_DEVICES)) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'devices' cgroups controller mount")); + return -1; + } + if (!virCgroupMounted(lxc_driver->cgroup, + VIR_CGROUP_CONTROLLER_MEMORY)) { + lxcError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'memory' cgroups controller mount")); + return -1; + } + + if (virFileMakePath(driver->logDir) < 0) { + virReportSystemError(errno, + _("Cannot create log directory '%s'"), + driver->logDir); + return -1; + } + + if (virAsprintf(&logfile, "%s/%s.log", + driver->logDir, vm->def->name) < 0) { + virReportOOMError(); + return -1; + } + + /* Do this up front, so any part of the startup process can add + * runtime state to vm->def that won't be persisted. This let's us + * report implicit runtime defaults in the XML, like vnc listen/socket + */ + VIR_DEBUG("Setting current domain def as transient"); + if (virDomainObjSetDefTransient(driver->caps, vm, true) < 0) + goto cleanup; + + /* Run an early hook to set-up missing devices */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto cleanup; + } + + /* Here we open all the PTYs we need on the host OS side. + * The LXC controller will open the guest OS side PTYs + * and forward I/O between them. + */ + nttyFDs = vm->def->nconsoles; + if (VIR_ALLOC_N(ttyFDs, nttyFDs) < 0) { + virReportOOMError(); + goto cleanup; + } + + /* If you are using a SecurityDriver with dynamic labelling, + then generate a security label for isolation */ + VIR_DEBUG("Generating domain security label (if required)"); + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DEFAULT) + vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_NONE; + + if (virSecurityManagerGenLabel(driver->securityManager, vm->def) < 0) { + virDomainAuditSecurityLabel(vm, false); + goto cleanup; + } + virDomainAuditSecurityLabel(vm, true); + + VIR_DEBUG("Setting domain security labels"); + if (virSecurityManagerSetAllLabel(driver->securityManager, + vm->def, NULL) < 0) + goto cleanup; + + for (i = 0 ; i < vm->def->nconsoles ; i++) + ttyFDs[i] = -1; + + for (i = 0 ; i < vm->def->nconsoles ; i++) { + char *ttyPath; + if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { + lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only PTY console types are supported")); + goto cleanup; + } + + if (virFileOpenTty(&ttyFDs[i], &ttyPath, 1) < 0) { + virReportSystemError(errno, "%s", + _("Failed to allocate tty")); + goto cleanup; + } + + VIR_FREE(vm->def->consoles[i]->source.data.file.path); + vm->def->consoles[i]->source.data.file.path = ttyPath; + + VIR_FREE(vm->def->consoles[i]->info.alias); + if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0) + goto cleanup; + + /* Save the configuration for the controller */ + if (virDomainSaveConfig(driver->stateDir, vm->def) < 0) + goto cleanup; + + if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, + S_IRUSR|S_IWUSR)) < 0) { + virReportSystemError(errno, + _("Failed to open '%s'"), + logfile); + goto cleanup; + } + + if (pipe(handshakefds) < 0) { + virReportSystemError(errno, "%s", + _("Unable to create pipe")); + goto cleanup; + } + + if (!(cmd = lxcBuildControllerCmd(driver, + vm, + nveths, veths, + ttyFDs, nttyFDs, + handshakefds[1]))) + goto cleanup; + virCommandSetOutputFD(cmd, &logfd); + virCommandSetErrorFD(cmd, &logfd); + + /* now that we know it is about to start call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto cleanup; + } + + /* Log timestamp */ + if ((timestamp = virTimeStringNow()) == NULL) { + virReportOOMError(); + goto cleanup; + } + if (safewrite(logfd, timestamp, strlen(timestamp)) < 0 || + safewrite(logfd, START_POSTFIX, strlen(START_POSTFIX)) < 0) { + VIR_WARN("Unable to write timestamp to logfile: %s", + virStrerror(errno, ebuf, sizeof(ebuf))); + } + VIR_FREE(timestamp); + + /* Log generated command line */ + virCommandWriteArgLog(cmd, logfd); + if ((pos = lseek(logfd, 0, SEEK_END)) < 0) + VIR_WARN("Unable to seek to end of logfile: %s", + virStrerror(errno, ebuf, sizeof(ebuf))); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + if (VIR_CLOSE(handshakefds[1]) < 0) { + virReportSystemError(errno, "%s", _("could not close handshake fd")); + goto cleanup; + } + + /* Connect to the controller as a client *first* because + * this will block until the child has written their + * pid file out to disk */ + if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) + goto cleanup; + + /* And get its pid */ + if ((r = virPidFileRead(driver->stateDir, vm->def->name, &vm->pid)) < 0) { + virReportSystemError(-r, + _("Failed to read pid file %s/%s.pid"), + driver->stateDir, vm->def->name); + goto cleanup; + } + + vm->def->id = vm->pid; + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason); + + if (lxcContainerWaitForContinue(handshakefds[0]) < 0) { + char out[1024]; + + if (!(lxcReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { + lxcError(VIR_ERR_INTERNAL_ERROR, + _("guest failed to start: %s"), out); + } + + goto error; + } + + if ((priv->monitorWatch = virEventAddHandle( + priv->monitor, + VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, + lxcMonitorEvent, + vm, NULL)) < 0) { + goto error; + } + + if (autoDestroy && + lxcProcessAutoDestroyAdd(driver, vm, conn) < 0) + goto error; + + if (virDomainObjSetDefTransient(driver->caps, vm, false) < 0) + goto error; + + /* Write domain status to disk. + * + * XXX: Earlier we wrote the plain "live" domain XML to this + * location for the benefit of libvirt_lxc. We're now overwriting + * it with the live status XML instead. This is a (currently + * harmless) inconsistency we should fix one day */ + if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) + goto error; + + /* finally we can call the 'started' hook script if any */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_STARTED, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + + /* + * If the script raised an error abort the launch + */ + if (hookret < 0) + goto error; + } + + rc = 0; + +cleanup: + if (rc != 0 && !err) + err = virSaveLastError(); + virCommandFree(cmd); + if (VIR_CLOSE(logfd) < 0) { + virReportSystemError(errno, "%s", _("could not close logfile")); + rc = -1; + } + for (i = 0 ; i < nveths ; i++) { + if (rc != 0) + ignore_value(virNetDevVethDelete(veths[i])); + VIR_FREE(veths[i]); + } + if (rc != 0) { + VIR_FORCE_CLOSE(priv->monitor); + virDomainConfVMNWFilterTeardown(vm); + + virSecurityManagerRestoreAllLabel(driver->securityManager, + vm->def, false); + virSecurityManagerReleaseLabel(driver->securityManager, vm->def); + /* Clear out dynamically assigned labels */ + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + VIR_FREE(vm->def->seclabel.model); + VIR_FREE(vm->def->seclabel.label); + VIR_FREE(vm->def->seclabel.imagelabel); + } + } + for (i = 0 ; i < nttyFDs ; i++) + VIR_FORCE_CLOSE(ttyFDs[i]); + VIR_FREE(ttyFDs); + VIR_FORCE_CLOSE(handshakefds[0]); + VIR_FORCE_CLOSE(handshakefds[1]); + VIR_FREE(logfile); + + if (err) { + virSetError(err); + virFreeError(err); + } + + return rc; + +error: + err = virSaveLastError(); + lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + goto cleanup; +} + +struct lxcAutostartData { + lxc_driver_t *driver; + virConnectPtr conn; +}; + +static void +lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) +{ + virDomainObjPtr vm = payload; + const struct lxcAutostartData *data = opaque; + + virDomainObjLock(vm); + if (vm->autostart && + !virDomainObjIsActive(vm)) { + int ret = lxcVmStart(data->conn, data->driver, vm, false, + VIR_DOMAIN_RUNNING_BOOTED); + virDomainAuditStart(vm, "booted", ret >= 0); + if (ret < 0) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to autostart VM '%s': %s"), + vm->def->name, + err ? err->message : ""); + } else { + virDomainEventPtr event = + virDomainEventNewFromObj(vm, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_STARTED_BOOTED); + if (event) + virDomainEventStateQueue(data->driver->domainEventState, event); + } + } + virDomainObjUnlock(vm); +} + + +void +lxcAutostartConfigs(lxc_driver_t *driver) { + /* XXX: Figure out a better way todo this. The domain + * startup code needs a connection handle in order + * to lookup the bridge associated with a virtual + * network + */ + virConnectPtr conn = virConnectOpen("lxc:///"); + /* Ignoring NULL conn which is mostly harmless here */ + + struct lxcAutostartData data = { driver, conn }; + + lxcDriverLock(driver); + virHashForEach(driver->domains.objs, lxcAutostartDomain, &data); + lxcDriverUnlock(driver); + + if (conn) + virConnectClose(conn); +} + +static void +lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) +{ + virDomainObjPtr vm = payload; + lxc_driver_t *driver = opaque; + lxcDomainObjPrivatePtr priv; + + virDomainObjLock(vm); + VIR_DEBUG("Reconnect %d %d %d\n", vm->def->id, vm->pid, vm->state.state); + + priv = vm->privateData; + + if (vm->pid != 0) { + vm->def->id = vm->pid; + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, + VIR_DOMAIN_RUNNING_UNKNOWN); + + if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) + goto error; + + if ((priv->monitorWatch = virEventAddHandle( + priv->monitor, + VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, + lxcMonitorEvent, + vm, NULL)) < 0) + goto error; + + if (virSecurityManagerReserveLabel(driver->securityManager, + vm->def, vm->pid) < 0) + goto error; + + /* now that we know it's reconnected call the hook if present */ + if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { + char *xml = virDomainDefFormat(vm->def, 0); + int hookret; + + /* we can't stop the operation even if the script raised an error */ + hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name, + VIR_HOOK_LXC_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN, + NULL, xml, NULL); + VIR_FREE(xml); + if (hookret < 0) + goto error; + } + + } else { + vm->def->id = -1; + VIR_FORCE_CLOSE(priv->monitor); + } + +cleanup: + virDomainObjUnlock(vm); + return; + +error: + lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + virDomainAuditStop(vm, "failed"); + goto cleanup; +} + + +int lxcReconnectAll(lxc_driver_t *driver, + virDomainObjListPtr doms) +{ + virHashForEach(doms->objs, lxcReconnectVM, driver); + return 0; +} diff --git a/src/lxc/lxc_process.h b/src/lxc/lxc_process.h new file mode 100644 index 0000000..b4b707b --- /dev/null +++ b/src/lxc/lxc_process.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * lxc_process.h: LXC process lifecycle management + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LXC_PROCESS_H__ +# define __LXC_PROCESS_H__ + +# include "lxc_conf.h" + +int lxcVmStart(virConnectPtr conn, + lxc_driver_t * driver, + virDomainObjPtr vm, + bool autoDestroy, + virDomainRunningReason reason); +int lxcVmTerminate(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason); +int lxcProcessAutoDestroyInit(lxc_driver_t *driver); +void lxcProcessAutoDestroyRun(lxc_driver_t *driver, + virConnectPtr conn); +void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver); +int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, + virDomainObjPtr vm, + virConnectPtr conn); +int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, + virDomainObjPtr vm); + +void lxcAutostartConfigs(lxc_driver_t *driver); +int lxcReconnectAll(lxc_driver_t *driver, + virDomainObjListPtr doms); + +#endif /* __LXC_PROCESS_H__ */
Looks okay, ACK, but diff really ain't our friend for those. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

From: "Daniel P. Berrange" <berrange@redhat.com> For consistency all the APIs in the lxc_process.c file should have a virLXCProcess prefix in their name Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/lxc/lxc_driver.c | 24 +++--- src/lxc/lxc_process.c | 216 ++++++++++++++++++++++++------------------------- src/lxc/lxc_process.h | 41 +++++----- 3 files changed, 141 insertions(+), 140 deletions(-) diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index d7f052f..dcb9737 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -126,7 +126,7 @@ static int lxcClose(virConnectPtr conn) lxc_driver_t *driver = conn->privateData; lxcDriverLock(driver); - lxcProcessAutoDestroyRun(driver, conn); + virLXCProcessAutoDestroyRun(driver, conn); lxcDriverUnlock(driver); conn->privateData = NULL; @@ -978,9 +978,9 @@ static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags) goto cleanup; } - ret = lxcVmStart(dom->conn, driver, vm, - (flags & VIR_DOMAIN_START_AUTODESTROY), - VIR_DOMAIN_RUNNING_BOOTED); + ret = virLXCProcessStart(dom->conn, driver, vm, + (flags & VIR_DOMAIN_START_AUTODESTROY), + VIR_DOMAIN_RUNNING_BOOTED); if (ret == 0) { event = virDomainEventNewFromObj(vm, @@ -1059,9 +1059,9 @@ lxcDomainCreateAndStart(virConnectPtr conn, goto cleanup; def = NULL; - if (lxcVmStart(conn, driver, vm, - (flags & VIR_DOMAIN_START_AUTODESTROY), - VIR_DOMAIN_RUNNING_BOOTED) < 0) { + if (virLXCProcessStart(conn, driver, vm, + (flags & VIR_DOMAIN_START_AUTODESTROY), + VIR_DOMAIN_RUNNING_BOOTED) < 0) { virDomainAuditStart(vm, "booted", false); virDomainRemoveInactive(&driver->domains, vm); vm = NULL; @@ -1296,7 +1296,7 @@ lxcDomainDestroyFlags(virDomainPtr dom, goto cleanup; } - ret = lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED); + ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED); event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, VIR_DOMAIN_EVENT_STOPPED_DESTROYED); @@ -1436,7 +1436,7 @@ static int lxcStartup(int privileged) lxcDomainSetPrivateDataHooks(lxc_driver->caps); - if (lxcProcessAutoDestroyInit(lxc_driver) < 0) + if (virLXCProcessAutoDestroyInit(lxc_driver) < 0) goto cleanup; /* Get all the running persistent or transient configs first */ @@ -1448,7 +1448,7 @@ static int lxcStartup(int privileged) NULL, NULL) < 0) goto cleanup; - lxcReconnectAll(lxc_driver, &lxc_driver->domains); + virLXCProcessReconnectAll(lxc_driver, &lxc_driver->domains); /* Then inactive persistent configs */ if (virDomainLoadAllConfigs(lxc_driver->caps, @@ -1461,7 +1461,7 @@ static int lxcStartup(int privileged) lxcDriverUnlock(lxc_driver); - lxcAutostartConfigs(lxc_driver); + virLXCProcessAutostartAll(lxc_driver); return 0; @@ -1517,7 +1517,7 @@ static int lxcShutdown(void) virDomainObjListDeinit(&lxc_driver->domains); virDomainEventStateFree(lxc_driver->domainEventState); - lxcProcessAutoDestroyShutdown(lxc_driver); + virLXCProcessAutoDestroyShutdown(lxc_driver); virCapabilitiesFree(lxc_driver->caps); virSecurityManagerFree(lxc_driver->securityManager); diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 12f6ae6..86895a4 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -48,7 +48,7 @@ #define START_POSTFIX ": starting up\n" -int lxcProcessAutoDestroyInit(lxc_driver_t *driver) +int virLXCProcessAutoDestroyInit(lxc_driver_t *driver) { if (!(driver->autodestroy = virHashCreate(5, NULL))) return -1; @@ -56,16 +56,16 @@ int lxcProcessAutoDestroyInit(lxc_driver_t *driver) return 0; } -struct lxcProcessAutoDestroyData { +struct virLXCProcessAutoDestroyData { lxc_driver_t *driver; virConnectPtr conn; }; -static void lxcProcessAutoDestroyDom(void *payload, - const void *name, - void *opaque) +static void virLXCProcessAutoDestroyDom(void *payload, + const void *name, + void *opaque) { - struct lxcProcessAutoDestroyData *data = opaque; + struct virLXCProcessAutoDestroyData *data = opaque; virConnectPtr conn = payload; const char *uuidstr = name; unsigned char uuid[VIR_UUID_BUFLEN]; @@ -89,7 +89,7 @@ static void lxcProcessAutoDestroyDom(void *payload, } VIR_DEBUG("Killing domain"); - lxcVmTerminate(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED); + virLXCProcessStop(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED); virDomainAuditStop(dom, "destroyed"); event = virDomainEventNewFromObj(dom, VIR_DOMAIN_EVENT_STOPPED, @@ -108,23 +108,23 @@ static void lxcProcessAutoDestroyDom(void *payload, /* * Precondition: driver is locked */ -void lxcProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn) +void virLXCProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn) { - struct lxcProcessAutoDestroyData data = { + struct virLXCProcessAutoDestroyData data = { driver, conn }; VIR_DEBUG("conn=%p", conn); - virHashForEach(driver->autodestroy, lxcProcessAutoDestroyDom, &data); + virHashForEach(driver->autodestroy, virLXCProcessAutoDestroyDom, &data); } -void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver) +void virLXCProcessAutoDestroyShutdown(lxc_driver_t *driver) { virHashFree(driver->autodestroy); } -int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, - virDomainObjPtr vm, - virConnectPtr conn) +int virLXCProcessAutoDestroyAdd(lxc_driver_t *driver, + virDomainObjPtr vm, + virConnectPtr conn) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(vm->def->uuid, uuidstr); @@ -134,8 +134,8 @@ int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, return 0; } -int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, - virDomainObjPtr vm) +int virLXCProcessAutoDestroyRemove(lxc_driver_t *driver, + virDomainObjPtr vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(vm->def->uuid, uuidstr); @@ -147,7 +147,7 @@ int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, /** - * lxcVmCleanup: + * virLXCProcessCleanup: * @driver: pointer to driver structure * @vm: pointer to VM to clean up * @reason: reason for switching the VM to shutoff state @@ -155,9 +155,9 @@ int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, * Cleanout resources associated with the now dead VM * */ -static void lxcVmCleanup(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason) +static void virLXCProcessCleanup(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason) { virCgroupPtr cgroup; int i; @@ -176,7 +176,7 @@ static void lxcVmCleanup(lxc_driver_t *driver, } /* Stop autodestroy in case guest is restarted */ - lxcProcessAutoDestroyRemove(driver, vm); + virLXCProcessAutoDestroyRemove(driver, vm); virEventRemoveHandle(priv->monitorWatch); VIR_FORCE_CLOSE(priv->monitor); @@ -230,12 +230,12 @@ static void lxcVmCleanup(lxc_driver_t *driver, } -static int lxcSetupInterfaceBridged(virConnectPtr conn, - virDomainDefPtr vm, - virDomainNetDefPtr net, - const char *brname, - unsigned int *nveths, - char ***veths) +static int virLXCProcessSetupInterfaceBridged(virConnectPtr conn, + virDomainDefPtr vm, + virDomainNetDefPtr net, + const char *brname, + unsigned int *nveths, + char ***veths) { int ret = -1; char *parentVeth; @@ -292,11 +292,11 @@ cleanup: } -static int lxcSetupInterfaceDirect(virConnectPtr conn, - virDomainDefPtr def, - virDomainNetDefPtr net, - unsigned int *nveths, - char ***veths) +static int virLXCProcessSetupInterfaceDirect(virConnectPtr conn, + virDomainDefPtr def, + virDomainNetDefPtr net, + unsigned int *nveths, + char ***veths) { int ret = 0; char *res_ifname = NULL; @@ -359,7 +359,7 @@ cleanup: /** - * lxcSetupInterfaces: + * virLXCProcessSetupInterfaces: * @conn: pointer to connection * @def: pointer to virtual machine structure * @nveths: number of interfaces @@ -371,10 +371,10 @@ cleanup: * * Returns 0 on success or -1 in case of error */ -static int lxcSetupInterfaces(virConnectPtr conn, - virDomainDefPtr def, - unsigned int *nveths, - char ***veths) +static int virLXCProcessSetupInterfaces(virConnectPtr conn, + virDomainDefPtr def, + unsigned int *nveths, + char ***veths) { int ret = -1; size_t i; @@ -401,12 +401,12 @@ static int lxcSetupInterfaces(virConnectPtr conn, if (!brname) goto cleanup; - if (lxcSetupInterfaceBridged(conn, - def, - def->nets[i], - brname, - nveths, - veths) < 0) { + if (virLXCProcessSetupInterfaceBridged(conn, + def, + def->nets[i], + brname, + nveths, + veths) < 0) { VIR_FREE(brname); goto cleanup; } @@ -420,21 +420,21 @@ static int lxcSetupInterfaces(virConnectPtr conn, _("No bridge name specified")); goto cleanup; } - if (lxcSetupInterfaceBridged(conn, - def, - def->nets[i], - brname, - nveths, - veths) < 0) + if (virLXCProcessSetupInterfaceBridged(conn, + def, + def->nets[i], + brname, + nveths, + veths) < 0) goto cleanup; } break; case VIR_DOMAIN_NET_TYPE_DIRECT: - if (lxcSetupInterfaceDirect(conn, - def, - def->nets[i], - nveths, - veths) < 0) + if (virLXCProcessSetupInterfaceDirect(conn, + def, + def->nets[i], + nveths, + veths) < 0) goto cleanup; break; @@ -472,8 +472,8 @@ cleanup: } -static int lxcMonitorClient(lxc_driver_t * driver, - virDomainObjPtr vm) +static int virLXCProcessMonitorClient(lxc_driver_t * driver, + virDomainObjPtr vm) { char *sockpath = NULL; int fd = -1; @@ -529,9 +529,9 @@ error: } -int lxcVmTerminate(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason) +int virLXCProcessStop(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason) { virCgroupPtr group = NULL; int rc; @@ -572,7 +572,7 @@ int lxcVmTerminate(lxc_driver_t *driver, */ } - lxcVmCleanup(driver, vm, reason); + virLXCProcessCleanup(driver, vm, reason); rc = 0; @@ -582,10 +582,10 @@ cleanup: } extern lxc_driver_t *lxc_driver; -static void lxcMonitorEvent(int watch, - int fd, - int events ATTRIBUTE_UNUSED, - void *data) +static void virLXCProcessMonitorEvent(int watch, + int fd, + int events ATTRIBUTE_UNUSED, + void *data) { lxc_driver_t *driver = lxc_driver; virDomainObjPtr vm = data; @@ -603,7 +603,7 @@ static void lxcMonitorEvent(int watch, goto cleanup; } - if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) { + if (virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) { virEventRemoveHandle(watch); } else { event = virDomainEventNewFromObj(vm, @@ -628,13 +628,13 @@ cleanup: static virCommandPtr -lxcBuildControllerCmd(lxc_driver_t *driver, - virDomainObjPtr vm, - int nveths, - char **veths, - int *ttyFDs, - size_t nttyFDs, - int handshakefd) +virLXCProcessBuildControllerCmd(lxc_driver_t *driver, + virDomainObjPtr vm, + int nveths, + char **veths, + int *ttyFDs, + size_t nttyFDs, + int handshakefd) { size_t i; char *filterstr; @@ -704,11 +704,11 @@ cleanup: } static int -lxcReadLogOutput(virDomainObjPtr vm, - char *logfile, - off_t pos, - char *buf, - size_t buflen) +virLXCProcessReadLogOutput(virDomainObjPtr vm, + char *logfile, + off_t pos, + char *buf, + size_t buflen) { int fd; off_t off; @@ -777,7 +777,7 @@ cleanup: } /** - * lxcVmStart: + * virLXCProcessStart: * @conn: pointer to connection * @driver: pointer to driver structure * @vm: pointer to virtual machine structure @@ -788,11 +788,11 @@ cleanup: * * Returns 0 on success or -1 in case of error */ -int lxcVmStart(virConnectPtr conn, - lxc_driver_t * driver, - virDomainObjPtr vm, - bool autoDestroy, - virDomainRunningReason reason) +int virLXCProcessStart(virConnectPtr conn, + lxc_driver_t * driver, + virDomainObjPtr vm, + bool autoDestroy, + virDomainRunningReason reason) { int rc = -1, r; size_t nttyFDs = 0; @@ -927,7 +927,7 @@ int lxcVmStart(virConnectPtr conn, } } - if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0) + if (virLXCProcessSetupInterfaces(conn, vm->def, &nveths, &veths) != 0) goto cleanup; /* Save the configuration for the controller */ @@ -948,11 +948,11 @@ int lxcVmStart(virConnectPtr conn, goto cleanup; } - if (!(cmd = lxcBuildControllerCmd(driver, - vm, - nveths, veths, - ttyFDs, nttyFDs, - handshakefds[1]))) + if (!(cmd = virLXCProcessBuildControllerCmd(driver, + vm, + nveths, veths, + ttyFDs, nttyFDs, + handshakefds[1]))) goto cleanup; virCommandSetOutputFD(cmd, &logfd); virCommandSetErrorFD(cmd, &logfd); @@ -1003,7 +1003,7 @@ int lxcVmStart(virConnectPtr conn, /* Connect to the controller as a client *first* because * this will block until the child has written their * pid file out to disk */ - if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) + if ((priv->monitor = virLXCProcessMonitorClient(driver, vm)) < 0) goto cleanup; /* And get its pid */ @@ -1020,7 +1020,7 @@ int lxcVmStart(virConnectPtr conn, if (lxcContainerWaitForContinue(handshakefds[0]) < 0) { char out[1024]; - if (!(lxcReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { + if (!(virLXCProcessReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { lxcError(VIR_ERR_INTERNAL_ERROR, _("guest failed to start: %s"), out); } @@ -1031,13 +1031,13 @@ int lxcVmStart(virConnectPtr conn, if ((priv->monitorWatch = virEventAddHandle( priv->monitor, VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, - lxcMonitorEvent, + virLXCProcessMonitorEvent, vm, NULL)) < 0) { goto error; } if (autoDestroy && - lxcProcessAutoDestroyAdd(driver, vm, conn) < 0) + virLXCProcessAutoDestroyAdd(driver, vm, conn) < 0) goto error; if (virDomainObjSetDefTransient(driver->caps, vm, false) < 0) @@ -1114,25 +1114,25 @@ cleanup: error: err = virSaveLastError(); - lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); goto cleanup; } -struct lxcAutostartData { +struct virLXCAutostartData { lxc_driver_t *driver; virConnectPtr conn; }; static void -lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) +virLXCProcessAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) { virDomainObjPtr vm = payload; - const struct lxcAutostartData *data = opaque; + const struct virLXCAutostartData *data = opaque; virDomainObjLock(vm); if (vm->autostart && !virDomainObjIsActive(vm)) { - int ret = lxcVmStart(data->conn, data->driver, vm, false, + int ret = virLXCProcessStart(data->conn, data->driver, vm, false, VIR_DOMAIN_RUNNING_BOOTED); virDomainAuditStart(vm, "booted", ret >= 0); if (ret < 0) { @@ -1154,7 +1154,7 @@ lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaqu void -lxcAutostartConfigs(lxc_driver_t *driver) { +virLXCProcessAutostartAll(lxc_driver_t *driver) { /* XXX: Figure out a better way todo this. The domain * startup code needs a connection handle in order * to lookup the bridge associated with a virtual @@ -1163,10 +1163,10 @@ lxcAutostartConfigs(lxc_driver_t *driver) { virConnectPtr conn = virConnectOpen("lxc:///"); /* Ignoring NULL conn which is mostly harmless here */ - struct lxcAutostartData data = { driver, conn }; + struct virLXCAutostartData data = { driver, conn }; lxcDriverLock(driver); - virHashForEach(driver->domains.objs, lxcAutostartDomain, &data); + virHashForEach(driver->domains.objs, virLXCProcessAutostartDomain, &data); lxcDriverUnlock(driver); if (conn) @@ -1174,7 +1174,7 @@ lxcAutostartConfigs(lxc_driver_t *driver) { } static void -lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) +virLXCProcessReconnectDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) { virDomainObjPtr vm = payload; lxc_driver_t *driver = opaque; @@ -1190,13 +1190,13 @@ lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN); - if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) + if ((priv->monitor = virLXCProcessMonitorClient(driver, vm)) < 0) goto error; if ((priv->monitorWatch = virEventAddHandle( priv->monitor, VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, - lxcMonitorEvent, + virLXCProcessMonitorEvent, vm, NULL)) < 0) goto error; @@ -1228,15 +1228,15 @@ cleanup: return; error: - lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); + virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED); virDomainAuditStop(vm, "failed"); goto cleanup; } -int lxcReconnectAll(lxc_driver_t *driver, - virDomainObjListPtr doms) +int virLXCProcessReconnectAll(lxc_driver_t *driver, + virDomainObjListPtr doms) { - virHashForEach(doms->objs, lxcReconnectVM, driver); + virHashForEach(doms->objs, virLXCProcessReconnectDomain, driver); return 0; } diff --git a/src/lxc/lxc_process.h b/src/lxc/lxc_process.h index b4b707b..eece8ad 100644 --- a/src/lxc/lxc_process.h +++ b/src/lxc/lxc_process.h @@ -24,26 +24,27 @@ # include "lxc_conf.h" -int lxcVmStart(virConnectPtr conn, - lxc_driver_t * driver, - virDomainObjPtr vm, - bool autoDestroy, - virDomainRunningReason reason); -int lxcVmTerminate(lxc_driver_t *driver, - virDomainObjPtr vm, - virDomainShutoffReason reason); -int lxcProcessAutoDestroyInit(lxc_driver_t *driver); -void lxcProcessAutoDestroyRun(lxc_driver_t *driver, - virConnectPtr conn); -void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver); -int lxcProcessAutoDestroyAdd(lxc_driver_t *driver, - virDomainObjPtr vm, - virConnectPtr conn); -int lxcProcessAutoDestroyRemove(lxc_driver_t *driver, - virDomainObjPtr vm); +int virLXCProcessStart(virConnectPtr conn, + lxc_driver_t * driver, + virDomainObjPtr vm, + bool autoDestroy, + virDomainRunningReason reason); +int virLXCProcessStop(lxc_driver_t *driver, + virDomainObjPtr vm, + virDomainShutoffReason reason); -void lxcAutostartConfigs(lxc_driver_t *driver); -int lxcReconnectAll(lxc_driver_t *driver, - virDomainObjListPtr doms); +int virLXCProcessAutoDestroyInit(lxc_driver_t *driver); +void virLXCProcessAutoDestroyRun(lxc_driver_t *driver, + virConnectPtr conn); +void virLXCProcessAutoDestroyShutdown(lxc_driver_t *driver); +int virLXCProcessAutoDestroyAdd(lxc_driver_t *driver, + virDomainObjPtr vm, + virConnectPtr conn); +int virLXCProcessAutoDestroyRemove(lxc_driver_t *driver, + virDomainObjPtr vm); + +void virLXCProcessAutostartAll(lxc_driver_t *driver); +int virLXCProcessReconnectAll(lxc_driver_t *driver, + virDomainObjListPtr doms); #endif /* __LXC_PROCESS_H__ */ -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> For consistency all the APIs in the lxc_domain.c file should have a virLXCDomain prefix in their name Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/lxc/lxc_domain.c | 14 +++++++------- src/lxc/lxc_domain.h | 2 +- src/lxc/lxc_driver.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 75fd74f..0376f0b 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -25,9 +25,9 @@ #include "memory.h" -static void *lxcDomainObjPrivateAlloc(void) +static void *virLXCDomainObjPrivateAlloc(void) { - lxcDomainObjPrivatePtr priv; + virLXCDomainObjPrivatePtr priv; if (VIR_ALLOC(priv) < 0) return NULL; @@ -38,16 +38,16 @@ static void *lxcDomainObjPrivateAlloc(void) return priv; } -static void lxcDomainObjPrivateFree(void *data) +static void virLXCDomainObjPrivateFree(void *data) { - lxcDomainObjPrivatePtr priv = data; + virLXCDomainObjPrivatePtr priv = data; VIR_FREE(priv); } -void lxcDomainSetPrivateDataHooks(virCapsPtr caps) +void virLXCDomainSetPrivateDataHooks(virCapsPtr caps) { - caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc; - caps->privateDataFreeFunc = lxcDomainObjPrivateFree; + caps->privateDataAllocFunc = virLXCDomainObjPrivateAlloc; + caps->privateDataFreeFunc = virLXCDomainObjPrivateFree; } diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h index e97b2b4..08d09c1 100644 --- a/src/lxc/lxc_domain.h +++ b/src/lxc/lxc_domain.h @@ -32,6 +32,6 @@ struct _lxcDomainObjPrivate { int monitorWatch; }; -void lxcDomainSetPrivateDataHooks(virCapsPtr caps); +void virLXCDomainSetPrivateDataHooks(virCapsPtr caps); #endif /* __LXC_DOMAIN_H__ */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index dcb9737..3807cee 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -1434,7 +1434,7 @@ static int lxcStartup(int privileged) if ((lxc_driver->caps = lxcCapsInit(lxc_driver)) == NULL) goto cleanup; - lxcDomainSetPrivateDataHooks(lxc_driver->caps); + virLXCDomainSetPrivateDataHooks(lxc_driver->caps); if (virLXCProcessAutoDestroyInit(lxc_driver) < 0) goto cleanup; -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Rename the lxc_driver_t struct typedef to virLXCDriver to more closely follow normal libvirt naming conventions Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/lxc/lxc_conf.c | 4 +- src/lxc/lxc_conf.h | 14 ++++--- src/lxc/lxc_driver.c | 101 ++++++++++++++++++++++++------------------------- src/lxc/lxc_process.c | 37 +++++++++--------- src/lxc/lxc_process.h | 18 ++++----- 5 files changed, 88 insertions(+), 86 deletions(-) diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 72547c4..49a6958 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -49,7 +49,7 @@ static int lxcDefaultConsoleType(const char *ostype ATTRIBUTE_UNUSED) /* Functions */ -virCapsPtr lxcCapsInit(lxc_driver_t *driver) +virCapsPtr lxcCapsInit(virLXCDriverPtr driver) { struct utsname utsname; virCapsPtr caps; @@ -156,7 +156,7 @@ error: return NULL; } -int lxcLoadDriverConfig(lxc_driver_t *driver) +int lxcLoadDriverConfig(virLXCDriverPtr driver) { char *filename; virConfPtr conf; diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index 937da16..a771cb5 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -43,8 +43,10 @@ # define LXC_LOG_DIR LOCALSTATEDIR "/log/libvirt/lxc" # define LXC_AUTOSTART_DIR LXC_CONFIG_DIR "/autostart" -typedef struct __lxc_driver lxc_driver_t; -struct __lxc_driver { +typedef struct _virLXCDriver virLXCDriver; +typedef virLXCDriver *virLXCDriverPtr; + +struct _virLXCDriver { virMutex lock; virCapsPtr caps; @@ -71,18 +73,18 @@ struct __lxc_driver { virHashTablePtr autodestroy; }; -int lxcLoadDriverConfig(lxc_driver_t *driver); -virCapsPtr lxcCapsInit(lxc_driver_t *driver); +int lxcLoadDriverConfig(virLXCDriverPtr driver); +virCapsPtr lxcCapsInit(virLXCDriverPtr driver); # define lxcError(code, ...) \ virReportErrorHelper(VIR_FROM_LXC, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) -static inline void lxcDriverLock(lxc_driver_t *driver) +static inline void lxcDriverLock(virLXCDriverPtr driver) { virMutexLock(&driver->lock); } -static inline void lxcDriverUnlock(lxc_driver_t *driver) +static inline void lxcDriverUnlock(virLXCDriverPtr driver) { virMutexUnlock(&driver->lock); } diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 3807cee..80933f4 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -72,11 +72,10 @@ static int lxcStartup(int privileged); static int lxcShutdown(void); -static lxc_driver_t *lxc_driver = NULL; +static virLXCDriverPtr lxc_driver = NULL; /* Functions */ - static virDrvOpenStatus lxcOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) @@ -123,7 +122,7 @@ static virDrvOpenStatus lxcOpen(virConnectPtr conn, static int lxcClose(virConnectPtr conn) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; lxcDriverLock(driver); virLXCProcessAutoDestroyRun(driver, conn); @@ -155,7 +154,7 @@ static int lxcIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED) static char *lxcGetCapabilities(virConnectPtr conn) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; char *xml; lxcDriverLock(driver); @@ -170,7 +169,7 @@ static char *lxcGetCapabilities(virConnectPtr conn) { static virDomainPtr lxcDomainLookupByID(virConnectPtr conn, int id) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; virDomainObjPtr vm; virDomainPtr dom = NULL; @@ -197,7 +196,7 @@ cleanup: static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; virDomainObjPtr vm; virDomainPtr dom = NULL; @@ -226,7 +225,7 @@ cleanup: static virDomainPtr lxcDomainLookupByName(virConnectPtr conn, const char *name) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; virDomainObjPtr vm; virDomainPtr dom = NULL; @@ -252,7 +251,7 @@ cleanup: static int lxcDomainIsActive(virDomainPtr dom) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr obj; int ret = -1; @@ -277,7 +276,7 @@ cleanup: static int lxcDomainIsPersistent(virDomainPtr dom) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr obj; int ret = -1; @@ -301,7 +300,7 @@ cleanup: static int lxcDomainIsUpdated(virDomainPtr dom) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr obj; int ret = -1; @@ -324,7 +323,7 @@ cleanup: } static int lxcListDomains(virConnectPtr conn, int *ids, int nids) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int n; lxcDriverLock(driver); @@ -335,7 +334,7 @@ static int lxcListDomains(virConnectPtr conn, int *ids, int nids) { } static int lxcNumDomains(virConnectPtr conn) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int n; lxcDriverLock(driver); @@ -347,7 +346,7 @@ static int lxcNumDomains(virConnectPtr conn) { static int lxcListDefinedDomains(virConnectPtr conn, char **const names, int nnames) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int n; lxcDriverLock(driver); @@ -359,7 +358,7 @@ static int lxcListDefinedDomains(virConnectPtr conn, static int lxcNumDefinedDomains(virConnectPtr conn) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int n; lxcDriverLock(driver); @@ -373,7 +372,7 @@ static int lxcNumDefinedDomains(virConnectPtr conn) { static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; virDomainDefPtr def = NULL; virDomainObjPtr vm = NULL; virDomainPtr dom = NULL; @@ -434,7 +433,7 @@ cleanup: static int lxcDomainUndefineFlags(virDomainPtr dom, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; virDomainEventPtr event = NULL; int ret = -1; @@ -492,7 +491,7 @@ static int lxcDomainUndefine(virDomainPtr dom) static int lxcDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; virCgroupPtr cgroup = NULL; int ret = -1, rc; @@ -556,7 +555,7 @@ lxcDomainGetState(virDomainPtr dom, int *reason, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; int ret = -1; @@ -585,7 +584,7 @@ cleanup: static char *lxcGetOSType(virDomainPtr dom) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; char *ret = NULL; @@ -616,7 +615,7 @@ cleanup: static unsigned long long lxcDomainGetMaxMemory(virDomainPtr dom) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; unsigned long long ret = 0; @@ -641,7 +640,7 @@ cleanup: } static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; int ret = -1; @@ -673,7 +672,7 @@ cleanup: } static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; virCgroupPtr cgroup = NULL; int ret = -1; @@ -735,7 +734,7 @@ lxcDomainSetMemoryParameters(virDomainPtr dom, int nparams, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; int i; virCgroupPtr cgroup = NULL; virDomainObjPtr vm = NULL; @@ -813,7 +812,7 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, int *nparams, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; int i; virCgroupPtr cgroup = NULL; virDomainObjPtr vm = NULL; @@ -909,7 +908,7 @@ cleanup: static char *lxcDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; char *ret = NULL; @@ -949,7 +948,7 @@ cleanup: */ static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; virDomainEventPtr event = NULL; int ret = -1; @@ -1027,7 +1026,7 @@ static virDomainPtr lxcDomainCreateAndStart(virConnectPtr conn, const char *xml, unsigned int flags) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; virDomainObjPtr vm = NULL; virDomainDefPtr def; virDomainPtr dom = NULL; @@ -1090,7 +1089,7 @@ cleanup: static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; int ret = -1; @@ -1149,7 +1148,7 @@ cleanup: static int lxcNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int ret = 0; lxcDriverLock(driver); @@ -1190,7 +1189,7 @@ lxcDomainEventRegister(virConnectPtr conn, void *opaque, virFreeCallback freecb) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int ret; lxcDriverLock(driver); @@ -1207,7 +1206,7 @@ static int lxcDomainEventDeregister(virConnectPtr conn, virConnectDomainEventCallback callback) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int ret; lxcDriverLock(driver); @@ -1228,7 +1227,7 @@ lxcDomainEventRegisterAny(virConnectPtr conn, void *opaque, virFreeCallback freecb) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int ret; lxcDriverLock(driver); @@ -1247,7 +1246,7 @@ static int lxcDomainEventDeregisterAny(virConnectPtr conn, int callbackID) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int ret; lxcDriverLock(driver); @@ -1273,7 +1272,7 @@ static int lxcDomainDestroyFlags(virDomainPtr dom, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; virDomainEventPtr event = NULL; int ret = -1; @@ -1346,7 +1345,7 @@ static int lxcCheckNetNsSupport(void) static int -lxcSecurityInit(lxc_driver_t *driver) +lxcSecurityInit(virLXCDriverPtr driver) { VIR_INFO("lxcSecurityInit %s", driver->securityDriverName); virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName, @@ -1473,7 +1472,7 @@ cleanup: static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque) { - lxc_driver_t *driver = opaque; + virLXCDriverPtr driver = opaque; if (newVM) { virDomainEventPtr event = @@ -1601,7 +1600,7 @@ cleanup: } -static bool lxcCgroupControllerActive(lxc_driver_t *driver, +static bool lxcCgroupControllerActive(virLXCDriverPtr driver, int controller) { if (driver->cgroup == NULL) @@ -1622,7 +1621,7 @@ static bool lxcCgroupControllerActive(lxc_driver_t *driver, static char *lxcGetSchedulerType(virDomainPtr domain, int *nparams) { - lxc_driver_t *driver = domain->conn->privateData; + virLXCDriverPtr driver = domain->conn->privateData; char *ret = NULL; int rc; @@ -1732,7 +1731,7 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, int nparams, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; int i; virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; @@ -1872,7 +1871,7 @@ lxcGetSchedulerParametersFlags(virDomainPtr dom, int *nparams, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; virDomainDefPtr persistentDef; @@ -1992,7 +1991,7 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, int nparams, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; int i; virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; @@ -2093,7 +2092,7 @@ lxcDomainGetBlkioParameters(virDomainPtr dom, int *nparams, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; int i; virCgroupPtr group = NULL; virDomainObjPtr vm = NULL; @@ -2198,7 +2197,7 @@ lxcDomainInterfaceStats(virDomainPtr dom, const char *path, struct _virDomainInterfaceStats *stats) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; int i; int ret = -1; @@ -2254,7 +2253,7 @@ lxcDomainInterfaceStats(virDomainPtr dom, static int lxcDomainGetAutostart(virDomainPtr dom, int *autostart) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; int ret = -1; @@ -2281,7 +2280,7 @@ cleanup: static int lxcDomainSetAutostart(virDomainPtr dom, int autostart) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; char *configFile = NULL, *autostartLink = NULL; int ret = -1; @@ -2354,7 +2353,7 @@ cleanup: return ret; } -static int lxcFreezeContainer(lxc_driver_t *driver, virDomainObjPtr vm) +static int lxcFreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm) { int timeout = 1000; /* In milliseconds */ int check_interval = 1; /* In milliseconds */ @@ -2449,7 +2448,7 @@ cleanup: static int lxcDomainSuspend(virDomainPtr dom) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; virDomainEventPtr event = NULL; int ret = -1; @@ -2497,7 +2496,7 @@ cleanup: return ret; } -static int lxcUnfreezeContainer(lxc_driver_t *driver, virDomainObjPtr vm) +static int lxcUnfreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm) { int ret; virCgroupPtr cgroup = NULL; @@ -2514,7 +2513,7 @@ static int lxcUnfreezeContainer(lxc_driver_t *driver, virDomainObjPtr vm) static int lxcDomainResume(virDomainPtr dom) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm; virDomainEventPtr event = NULL; int ret = -1; @@ -2569,7 +2568,7 @@ lxcDomainOpenConsole(virDomainPtr dom, virStreamPtr st, unsigned int flags) { - lxc_driver_t *driver = dom->conn->privateData; + virLXCDriverPtr driver = dom->conn->privateData; virDomainObjPtr vm = NULL; char uuidstr[VIR_UUID_STRING_BUFLEN]; int ret = -1; @@ -2638,7 +2637,7 @@ lxcListAllDomains(virConnectPtr conn, virDomainPtr **domains, unsigned int flags) { - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; int ret = -1; virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1); diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 86895a4..90830b4 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -48,7 +48,7 @@ #define START_POSTFIX ": starting up\n" -int virLXCProcessAutoDestroyInit(lxc_driver_t *driver) +int virLXCProcessAutoDestroyInit(virLXCDriverPtr driver) { if (!(driver->autodestroy = virHashCreate(5, NULL))) return -1; @@ -57,7 +57,7 @@ int virLXCProcessAutoDestroyInit(lxc_driver_t *driver) } struct virLXCProcessAutoDestroyData { - lxc_driver_t *driver; + virLXCDriverPtr driver; virConnectPtr conn; }; @@ -108,7 +108,7 @@ static void virLXCProcessAutoDestroyDom(void *payload, /* * Precondition: driver is locked */ -void virLXCProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn) +void virLXCProcessAutoDestroyRun(virLXCDriverPtr driver, virConnectPtr conn) { struct virLXCProcessAutoDestroyData data = { driver, conn @@ -117,12 +117,12 @@ void virLXCProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn) virHashForEach(driver->autodestroy, virLXCProcessAutoDestroyDom, &data); } -void virLXCProcessAutoDestroyShutdown(lxc_driver_t *driver) +void virLXCProcessAutoDestroyShutdown(virLXCDriverPtr driver) { virHashFree(driver->autodestroy); } -int virLXCProcessAutoDestroyAdd(lxc_driver_t *driver, +int virLXCProcessAutoDestroyAdd(virLXCDriverPtr driver, virDomainObjPtr vm, virConnectPtr conn) { @@ -134,7 +134,7 @@ int virLXCProcessAutoDestroyAdd(lxc_driver_t *driver, return 0; } -int virLXCProcessAutoDestroyRemove(lxc_driver_t *driver, +int virLXCProcessAutoDestroyRemove(virLXCDriverPtr driver, virDomainObjPtr vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; @@ -155,7 +155,7 @@ int virLXCProcessAutoDestroyRemove(lxc_driver_t *driver, * Cleanout resources associated with the now dead VM * */ -static void virLXCProcessCleanup(lxc_driver_t *driver, +static void virLXCProcessCleanup(virLXCDriverPtr driver, virDomainObjPtr vm, virDomainShutoffReason reason) { @@ -300,7 +300,7 @@ static int virLXCProcessSetupInterfaceDirect(virConnectPtr conn, { int ret = 0; char *res_ifname = NULL; - lxc_driver_t *driver = conn->privateData; + virLXCDriverPtr driver = conn->privateData; virNetDevBandwidthPtr bw; virNetDevVPortProfilePtr prof; @@ -472,7 +472,7 @@ cleanup: } -static int virLXCProcessMonitorClient(lxc_driver_t * driver, +static int virLXCProcessMonitorClient(virLXCDriverPtr driver, virDomainObjPtr vm) { char *sockpath = NULL; @@ -529,7 +529,7 @@ error: } -int virLXCProcessStop(lxc_driver_t *driver, +int virLXCProcessStop(virLXCDriverPtr driver, virDomainObjPtr vm, virDomainShutoffReason reason) { @@ -581,13 +581,13 @@ cleanup: return rc; } -extern lxc_driver_t *lxc_driver; +extern virLXCDriverPtr lxc_driver; static void virLXCProcessMonitorEvent(int watch, int fd, int events ATTRIBUTE_UNUSED, void *data) { - lxc_driver_t *driver = lxc_driver; + virLXCDriverPtr driver = lxc_driver; virDomainObjPtr vm = data; virDomainEventPtr event = NULL; lxcDomainObjPrivatePtr priv; @@ -628,7 +628,7 @@ cleanup: static virCommandPtr -virLXCProcessBuildControllerCmd(lxc_driver_t *driver, +virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, virDomainObjPtr vm, int nveths, char **veths, @@ -789,7 +789,7 @@ cleanup: * Returns 0 on success or -1 in case of error */ int virLXCProcessStart(virConnectPtr conn, - lxc_driver_t * driver, + virLXCDriverPtr driver, virDomainObjPtr vm, bool autoDestroy, virDomainRunningReason reason) @@ -1119,7 +1119,7 @@ error: } struct virLXCAutostartData { - lxc_driver_t *driver; + virLXCDriverPtr driver; virConnectPtr conn; }; @@ -1154,7 +1154,8 @@ virLXCProcessAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, v void -virLXCProcessAutostartAll(lxc_driver_t *driver) { +virLXCProcessAutostartAll(virLXCDriverPtr driver) +{ /* XXX: Figure out a better way todo this. The domain * startup code needs a connection handle in order * to lookup the bridge associated with a virtual @@ -1177,7 +1178,7 @@ static void virLXCProcessReconnectDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque) { virDomainObjPtr vm = payload; - lxc_driver_t *driver = opaque; + virLXCDriverPtr driver = opaque; lxcDomainObjPrivatePtr priv; virDomainObjLock(vm); @@ -1234,7 +1235,7 @@ error: } -int virLXCProcessReconnectAll(lxc_driver_t *driver, +int virLXCProcessReconnectAll(virLXCDriverPtr driver, virDomainObjListPtr doms) { virHashForEach(doms->objs, virLXCProcessReconnectDomain, driver); diff --git a/src/lxc/lxc_process.h b/src/lxc/lxc_process.h index eece8ad..ea7de96 100644 --- a/src/lxc/lxc_process.h +++ b/src/lxc/lxc_process.h @@ -25,26 +25,26 @@ # include "lxc_conf.h" int virLXCProcessStart(virConnectPtr conn, - lxc_driver_t * driver, + virLXCDriverPtr driver, virDomainObjPtr vm, bool autoDestroy, virDomainRunningReason reason); -int virLXCProcessStop(lxc_driver_t *driver, +int virLXCProcessStop(virLXCDriverPtr driver, virDomainObjPtr vm, virDomainShutoffReason reason); -int virLXCProcessAutoDestroyInit(lxc_driver_t *driver); -void virLXCProcessAutoDestroyRun(lxc_driver_t *driver, +int virLXCProcessAutoDestroyInit(virLXCDriverPtr driver); +void virLXCProcessAutoDestroyRun(virLXCDriverPtr driver, virConnectPtr conn); -void virLXCProcessAutoDestroyShutdown(lxc_driver_t *driver); -int virLXCProcessAutoDestroyAdd(lxc_driver_t *driver, +void virLXCProcessAutoDestroyShutdown(virLXCDriverPtr driver); +int virLXCProcessAutoDestroyAdd(virLXCDriverPtr driver, virDomainObjPtr vm, virConnectPtr conn); -int virLXCProcessAutoDestroyRemove(lxc_driver_t *driver, +int virLXCProcessAutoDestroyRemove(virLXCDriverPtr driver, virDomainObjPtr vm); -void virLXCProcessAutostartAll(lxc_driver_t *driver); -int virLXCProcessReconnectAll(lxc_driver_t *driver, +void virLXCProcessAutostartAll(virLXCDriverPtr driver); +int virLXCProcessReconnectAll(virLXCDriverPtr driver, virDomainObjListPtr doms); #endif /* __LXC_PROCESS_H__ */ -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Update all LXC code to use virReportError instead of the custom lxcError macro Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/lxc/lxc_conf.c | 10 +- src/lxc/lxc_conf.h | 5 - src/lxc/lxc_container.c | 30 ++-- src/lxc/lxc_controller.c | 58 ++++---- src/lxc/lxc_driver.c | 304 ++++++++++++++++++++--------------------- src/lxc/lxc_process.c | 64 ++++----- src/util/virterror_internal.h | 5 + 7 files changed, 238 insertions(+), 238 deletions(-) diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 49a6958..5ce6c7f 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -77,8 +77,8 @@ virCapsPtr lxcCapsInit(virLXCDriverPtr driver) VIR_WARN("Failed to get host power management capabilities"); if (virGetHostUUID(caps->host.host_uuid)) { - lxcError(VIR_ERR_INTERNAL_ERROR, - "%s", _("cannot get the host uuid")); + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("cannot get the host uuid")); goto error; } @@ -187,9 +187,9 @@ int lxcLoadDriverConfig(virLXCDriverPtr driver) goto done; #define CHECK_TYPE(name,typ) if (p && p->type != (typ)) { \ - lxcError(VIR_ERR_INTERNAL_ERROR, \ - "%s: %s: expected type " #typ, \ - filename, (name)); \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "%s: %s: expected type " #typ, \ + filename, (name)); \ virConfFree(conf); \ return -1; \ } diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index a771cb5..62e2229 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -76,10 +76,6 @@ struct _virLXCDriver { int lxcLoadDriverConfig(virLXCDriverPtr driver); virCapsPtr lxcCapsInit(virLXCDriverPtr driver); -# define lxcError(code, ...) \ - virReportErrorHelper(VIR_FROM_LXC, code, __FILE__, \ - __FUNCTION__, __LINE__, __VA_ARGS__) - static inline void lxcDriverLock(virLXCDriverPtr driver) { virMutexLock(&driver->lock); @@ -89,5 +85,4 @@ static inline void lxcDriverUnlock(virLXCDriverPtr driver) virMutexUnlock(&driver->lock); } - #endif /* LXC_CONF_H */ diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 145accb..b6f78d3 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -875,9 +875,9 @@ retry: * /etc/filesystems is only allowed to contain '*' on the last line */ if (gotStar && !tryProc) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("%s has unexpected '*' before last line"), - fslist); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("%s has unexpected '*' before last line"), + fslist); goto cleanup; } @@ -1066,14 +1066,14 @@ static int lxcContainerMountFS(virDomainFSDefPtr fs, /* We do actually support this, but the lxc controller * should have associated the file with a loopback * device and changed this to TYPE_BLOCK for us */ - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected filesystem type %s"), - virDomainFSTypeToString(fs->type)); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected filesystem type %s"), + virDomainFSTypeToString(fs->type)); break; default: - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Cannot mount filesystem type %s"), - virDomainFSTypeToString(fs->type)); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cannot mount filesystem type %s"), + virDomainFSTypeToString(fs->type)); break; } return 0; @@ -1582,14 +1582,14 @@ static int lxcContainerDropCapabilities(void) CAP_AUDIT_CONTROL, /* No messing with auditing status */ CAP_MAC_ADMIN, /* No messing with LSM config */ -1 /* sentinal */)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Failed to remove capabilities: %d"), ret); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to remove capabilities: %d"), ret); return -1; } if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Failed to apply capabilities: %d"), ret); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to apply capabilities: %d"), ret); return -1; } @@ -1629,8 +1629,8 @@ static int lxcContainerChild( void *data ) virCommandPtr cmd = NULL; if (NULL == vmDef) { - lxcError(VIR_ERR_INTERNAL_ERROR, - "%s", _("lxcChild() passed invalid vm definition")); + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("lxcChild() passed invalid vm definition")); goto cleanup; } diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 4777d51..8d6c883 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -291,9 +291,9 @@ static int virLXCControllerDaemonHandshake(virLXCControllerPtr ctrl) static int virLXCControllerValidateNICs(virLXCControllerPtr ctrl) { if (ctrl->def->nnets != ctrl->nveths) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("expecting %d veths, but got %zu"), - ctrl->def->nnets, ctrl->nveths); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("expecting %d veths, but got %zu"), + ctrl->def->nnets, ctrl->nveths); return -1; } @@ -304,9 +304,9 @@ static int virLXCControllerValidateNICs(virLXCControllerPtr ctrl) static int virLXCControllerValidateConsoles(virLXCControllerPtr ctrl) { if (ctrl->def->nconsoles != ctrl->nconsoles) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("expecting %d consoles, but got %zu tty file handlers"), - ctrl->def->nconsoles, ctrl->nconsoles); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("expecting %d consoles, but got %zu tty file handlers"), + ctrl->def->nconsoles, ctrl->nconsoles); return -1; } @@ -383,8 +383,8 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) VIR_DEBUG("Setting NUMA memory policy"); if (numa_available() < 0) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("Host kernel is not aware of NUMA.")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("Host kernel is not aware of NUMA.")); return -1; } @@ -395,8 +395,8 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { if (ctrl->def->numatune.memory.nodemask[i]) { if (i > NUMA_NUM_NODES) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Host cannot support NUMA node %d"), i); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Host cannot support NUMA node %d"), i); return -1; } if (i > maxnode && !warned) { @@ -424,9 +424,9 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) } if (nnodes != 1) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("NUMA memory tuning in 'preferred' mode " - "only supports single node")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("NUMA memory tuning in 'preferred' mode " + "only supports single node")); goto cleanup; } @@ -435,9 +435,9 @@ static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) } else if (mode == VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE) { numa_set_interleave_mask(&mask); } else { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Unable to set NUMA policy %s"), - virDomainNumatuneMemModeTypeToString(mode)); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unable to set NUMA policy %s"), + virDomainNumatuneMemModeTypeToString(mode)); goto cleanup; } @@ -450,8 +450,8 @@ cleanup: static int virLXCControllerSetupNUMAPolicy(virLXCControllerPtr ctrl) { if (ctrl->def->numatune.memory.nodemask) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("NUMA policy is not available on this platform")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("NUMA policy is not available on this platform")); return -1; } @@ -602,8 +602,8 @@ static int lxcControllerClearCapabilities(void) capng_clear(CAPNG_SELECT_BOTH); if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("failed to apply capabilities: %d"), ret); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to apply capabilities: %d"), ret); return -1; } #else @@ -913,8 +913,8 @@ static int virLXCControllerMain(virLXCControllerPtr ctrl) virLXCControllerConsoleEPoll, &(ctrl->consoles[i]), NULL)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to watch epoll FD")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to watch epoll FD")); goto cleanup; } @@ -923,8 +923,8 @@ static int virLXCControllerMain(virLXCControllerPtr ctrl) virLXCControllerConsoleIO, &(ctrl->consoles[i]), NULL)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to watch host console PTY")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to watch host console PTY")); goto cleanup; } @@ -933,8 +933,8 @@ static int virLXCControllerMain(virLXCControllerPtr ctrl) virLXCControllerConsoleIO, &(ctrl->consoles[i]), NULL)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to watch host console PTY")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to watch host console PTY")); goto cleanup; } } @@ -1092,9 +1092,9 @@ virLXCControllerSetupDevPTS(virLXCControllerPtr ctrl) if (!root) { if (ctrl->nconsoles != 1) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Expected exactly one console, but got %zu"), - ctrl->nconsoles); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Expected exactly one console, but got %zu"), + ctrl->nconsoles); return -1; } return 0; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 80933f4..28b2230 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -101,16 +101,16 @@ static virDrvOpenStatus lxcOpen(virConnectPtr conn, /* If path isn't '/' then they typoed, tell them correct path */ if (conn->uri->path != NULL && STRNEQ(conn->uri->path, "/")) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unexpected LXC URI path '%s', try lxc:///"), - conn->uri->path); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected LXC URI path '%s', try lxc:///"), + conn->uri->path); return VIR_DRV_OPEN_ERROR; } /* URI was good, but driver isn't active */ if (lxc_driver == NULL) { - lxcError(VIR_ERR_INTERNAL_ERROR, - "%s", _("lxc state driver is not active")); + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("lxc state driver is not active")); return VIR_DRV_OPEN_ERROR; } } @@ -178,8 +178,8 @@ static virDomainPtr lxcDomainLookupByID(virConnectPtr conn, lxcDriverUnlock(driver); if (!vm) { - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching id %d"), id); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching id %d"), id); goto cleanup; } @@ -207,8 +207,8 @@ static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } @@ -233,8 +233,8 @@ static virDomainPtr lxcDomainLookupByName(virConnectPtr conn, vm = virDomainFindByName(&driver->domains, name); lxcDriverUnlock(driver); if (!vm) { - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching name '%s'"), name); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching name '%s'"), name); goto cleanup; } @@ -261,8 +261,8 @@ static int lxcDomainIsActive(virDomainPtr dom) if (!obj) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } ret = virDomainObjIsActive(obj); @@ -286,8 +286,8 @@ static int lxcDomainIsPersistent(virDomainPtr dom) if (!obj) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } ret = obj->persistent; @@ -310,8 +310,8 @@ static int lxcDomainIsUpdated(virDomainPtr dom) if (!obj) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } ret = obj->updated; @@ -392,8 +392,8 @@ static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml) goto cleanup; if ((def->nets != NULL) && !(driver->have_netns)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("System lacks NETNS support")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("System lacks NETNS support")); goto cleanup; } @@ -445,14 +445,14 @@ static int lxcDomainUndefineFlags(virDomainPtr dom, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (!vm->persistent) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("Cannot undefine transient domain")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Cannot undefine transient domain")); goto cleanup; } @@ -502,8 +502,8 @@ static int lxcDomainGetInfo(virDomainPtr dom, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } @@ -514,19 +514,19 @@ static int lxcDomainGetInfo(virDomainPtr dom, info->memory = vm->def->mem.cur_balloon; } else { if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unable to get cgroup for %s"), vm->def->name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get cgroup for %s"), vm->def->name); goto cleanup; } if (virCgroupGetCpuacctUsage(cgroup, &(info->cpuTime)) < 0) { - lxcError(VIR_ERR_OPERATION_FAILED, - "%s", _("Cannot read cputime for domain")); + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Cannot read cputime for domain")); goto cleanup; } if ((rc = virCgroupGetMemoryUsage(cgroup, &(info->memory))) < 0) { - lxcError(VIR_ERR_OPERATION_FAILED, - "%s", _("Cannot read memory usage for domain")); + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Cannot read memory usage for domain")); if (rc == -ENOENT) { /* Don't fail if we can't read memory usage due to a lack of * kernel support */ @@ -568,8 +568,8 @@ lxcDomainGetState(virDomainPtr dom, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } @@ -595,8 +595,8 @@ static char *lxcGetOSType(virDomainPtr dom) if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } @@ -626,8 +626,8 @@ lxcDomainGetMaxMemory(virDomainPtr dom) if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } @@ -651,14 +651,14 @@ static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) { if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (newmax < vm->def->mem.cur_balloon) { - lxcError(VIR_ERR_INVALID_ARG, - "%s", _("Cannot set max memory lower than current memory")); + virReportError(VIR_ERR_INVALID_ARG, + "%s", _("Cannot set max memory lower than current memory")); goto cleanup; } @@ -683,38 +683,38 @@ static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) { if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (newmem > vm->def->mem.max_balloon) { - lxcError(VIR_ERR_INVALID_ARG, - "%s", _("Cannot set memory higher than max memory")); + virReportError(VIR_ERR_INVALID_ARG, + "%s", _("Cannot set memory higher than max memory")); goto cleanup; } if (!virDomainObjIsActive(vm)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("Domain is not running")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Domain is not running")); goto cleanup; } if (driver->cgroup == NULL) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("cgroups must be configured on the host")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cgroups must be configured on the host")); goto cleanup; } if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unable to get cgroup for %s"), vm->def->name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get cgroup for %s"), vm->def->name); goto cleanup; } if (virCgroupSetMemory(cgroup, newmem) < 0) { - lxcError(VIR_ERR_OPERATION_FAILED, - "%s", _("Failed to set memory for domain")); + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Failed to set memory for domain")); goto cleanup; } @@ -758,14 +758,14 @@ lxcDomainSetMemoryParameters(virDomainPtr dom, if (vm == NULL) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot find cgroup for domain %s"), vm->def->name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } @@ -828,8 +828,8 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, if (vm == NULL) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } @@ -841,8 +841,8 @@ lxcDomainGetMemoryParameters(virDomainPtr dom, } if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unable to get cgroup for %s"), vm->def->name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to get cgroup for %s"), vm->def->name); goto cleanup; } @@ -921,8 +921,8 @@ static char *lxcDomainGetXMLDesc(virDomainPtr dom, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } @@ -960,20 +960,20 @@ static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags) if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if ((vm->def->nets != NULL) && !(driver->have_netns)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("System lacks NETNS support")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("System lacks NETNS support")); goto cleanup; } if (virDomainObjIsActive(vm)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("Domain is already running")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Domain is already running")); goto cleanup; } @@ -1047,8 +1047,8 @@ lxcDomainCreateAndStart(virConnectPtr conn, goto cleanup; if ((def->nets != NULL) && !(driver->have_netns)) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, - "%s", _("System lacks NETNS support")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("System lacks NETNS support")); goto cleanup; } @@ -1101,15 +1101,15 @@ static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr secla if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("no domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (!virDomainVirtTypeToString(vm->def->virtType)) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("unknown virt type in domain definition '%d'"), - vm->def->virtType); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown virt type in domain definition '%d'"), + vm->def->virtType); goto cleanup; } @@ -1130,8 +1130,8 @@ static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr secla if (virDomainObjIsActive(vm)) { if (virSecurityManagerGetProcessLabel(driver->securityManager, vm->def, vm->pid, seclabel) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Failed to get security label")); + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Failed to get security label")); goto cleanup; } } @@ -1161,18 +1161,18 @@ static int lxcNodeGetSecurityModel(virConnectPtr conn, if (!virStrcpy(secmodel->model, driver->caps->host.secModel.model, VIR_SECURITY_MODEL_BUFLEN)) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("security model string exceeds max %d bytes"), - VIR_SECURITY_MODEL_BUFLEN - 1); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("security model string exceeds max %d bytes"), + VIR_SECURITY_MODEL_BUFLEN - 1); ret = -1; goto cleanup; } if (!virStrcpy(secmodel->doi, driver->caps->host.secModel.doi, VIR_SECURITY_DOI_BUFLEN)) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("security DOI string exceeds max %d bytes"), - VIR_SECURITY_DOI_BUFLEN-1); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("security DOI string exceeds max %d bytes"), + VIR_SECURITY_DOI_BUFLEN-1); ret = -1; goto cleanup; } @@ -1284,14 +1284,14 @@ lxcDomainDestroyFlags(virDomainPtr dom, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (!virDomainObjIsActive(vm)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("Domain is not running")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Domain is not running")); goto cleanup; } @@ -1559,7 +1559,7 @@ static int lxcVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *versio uname(&ver); if (virParseVersionString(ver.release, version, true) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release); + virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release); return -1; } @@ -1627,8 +1627,8 @@ static char *lxcGetSchedulerType(virDomainPtr domain, lxcDriverLock(driver); if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("cgroup CPU controller is not mounted")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cgroup CPU controller is not mounted")); goto cleanup; } @@ -1756,8 +1756,8 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, vm = virDomainFindByUUID(&driver->domains, dom->uuid); if (vm == NULL) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("No such domain %s"), dom->uuid); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No such domain %s"), dom->uuid); goto cleanup; } @@ -1774,14 +1774,14 @@ lxcSetSchedulerParametersFlags(virDomainPtr dom, if (flags & VIR_DOMAIN_AFFECT_LIVE) { if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("cgroup CPU controller is not mounted")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cgroup CPU controller is not mounted")); goto cleanup; } if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot find cgroup for domain %s"), - vm->def->name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), + vm->def->name); goto cleanup; } } @@ -1898,8 +1898,8 @@ lxcGetSchedulerParametersFlags(virDomainPtr dom, vm = virDomainFindByUUID(&driver->domains, dom->uuid); if (vm == NULL) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("No such domain %s"), dom->uuid); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No such domain %s"), dom->uuid); goto cleanup; } @@ -1917,14 +1917,14 @@ lxcGetSchedulerParametersFlags(virDomainPtr dom, } if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("cgroup CPU controller is not mounted")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("cgroup CPU controller is not mounted")); goto cleanup; } if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot find cgroup for domain %s"), vm->def->name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } @@ -2011,8 +2011,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, vm = virDomainFindByUUID(&driver->domains, dom->uuid); if (vm == NULL) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("No such domain %s"), dom->uuid); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No such domain %s"), dom->uuid); goto cleanup; } @@ -2022,13 +2022,13 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, if (flags & VIR_DOMAIN_AFFECT_LIVE) { if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) { - lxcError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted")); + virReportError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted")); goto cleanup; } if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot find cgroup for domain %s"), vm->def->name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } @@ -2039,8 +2039,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, int rc; if (params[i].value.ui > 1000 || params[i].value.ui < 100) { - lxcError(VIR_ERR_INVALID_ARG, "%s", - _("out of blkio weight range.")); + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("out of blkio weight range.")); goto cleanup; } @@ -2062,8 +2062,8 @@ lxcDomainSetBlkioParameters(virDomainPtr dom, if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) { if (params[i].value.ui > 1000 || params[i].value.ui < 100) { - lxcError(VIR_ERR_INVALID_ARG, "%s", - _("out of blkio weight range.")); + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("out of blkio weight range.")); goto cleanup; } @@ -2108,8 +2108,8 @@ lxcDomainGetBlkioParameters(virDomainPtr dom, vm = virDomainFindByUUID(&driver->domains, dom->uuid); if (vm == NULL) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("No such domain %s"), dom->uuid); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No such domain %s"), dom->uuid); goto cleanup; } @@ -2126,13 +2126,13 @@ lxcDomainGetBlkioParameters(virDomainPtr dom, if (flags & VIR_DOMAIN_AFFECT_LIVE) { if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) { - lxcError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted")); + virReportError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted")); goto cleanup; } if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot find cgroup for domain %s"), vm->def->name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find cgroup for domain %s"), vm->def->name); goto cleanup; } @@ -2209,14 +2209,14 @@ lxcDomainInterfaceStats(virDomainPtr dom, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (!virDomainObjIsActive(vm)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("Domain is not running")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Domain is not running")); goto cleanup; } @@ -2232,8 +2232,8 @@ lxcDomainInterfaceStats(virDomainPtr dom, if (ret == 0) ret = linuxDomainInterfaceStats(path, stats); else - lxcError(VIR_ERR_INVALID_ARG, - _("Invalid path, '%s' is not a known interface"), path); + virReportError(VIR_ERR_INVALID_ARG, + _("Invalid path, '%s' is not a known interface"), path); cleanup: if (vm) @@ -2246,7 +2246,7 @@ lxcDomainInterfaceStats(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED, struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED) { - lxcError(VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__); + virReportError(VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__); return -1; } #endif @@ -2264,8 +2264,8 @@ static int lxcDomainGetAutostart(virDomainPtr dom, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } @@ -2291,14 +2291,14 @@ static int lxcDomainSetAutostart(virDomainPtr dom, if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (!vm->persistent) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("Cannot set autostart for transient domain")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Cannot set autostart for transient domain")); goto cleanup; } @@ -2459,21 +2459,21 @@ static int lxcDomainSuspend(virDomainPtr dom) if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (!virDomainObjIsActive(vm)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("Domain is not running")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Domain is not running")); goto cleanup; } if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) { if (lxcFreezeContainer(driver, vm) < 0) { - lxcError(VIR_ERR_OPERATION_FAILED, - "%s", _("Suspend operation failed")); + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Suspend operation failed")); goto cleanup; } virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER); @@ -2524,21 +2524,21 @@ static int lxcDomainResume(virDomainPtr dom) if (!vm) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(dom->uuid, uuidstr); - lxcError(VIR_ERR_NO_DOMAIN, - _("No domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("No domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (!virDomainObjIsActive(vm)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("Domain is not running")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("Domain is not running")); goto cleanup; } if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) { if (lxcUnfreezeContainer(driver, vm) < 0) { - lxcError(VIR_ERR_OPERATION_FAILED, - "%s", _("Resume operation failed")); + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Resume operation failed")); goto cleanup; } virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, @@ -2581,14 +2581,14 @@ lxcDomainOpenConsole(virDomainPtr dom, virUUIDFormat(dom->uuid, uuidstr); vm = virDomainFindByUUID(&driver->domains, dom->uuid); if (!vm) { - lxcError(VIR_ERR_NO_DOMAIN, - _("no domain with matching uuid '%s'"), uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); goto cleanup; } if (!virDomainObjIsActive(vm)) { - lxcError(VIR_ERR_OPERATION_INVALID, - "%s", _("domain is not running")); + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); goto cleanup; } @@ -2608,15 +2608,15 @@ lxcDomainOpenConsole(virDomainPtr dom, } if (!chr) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot find console device '%s'"), - dev_name ? dev_name : _("default")); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot find console device '%s'"), + dev_name ? dev_name : _("default")); goto cleanup; } if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("character device %s is not using a PTY"), dev_name); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("character device %s is not using a PTY"), dev_name); goto cleanup; } diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 90830b4..f8e2e31 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -275,9 +275,9 @@ static int virLXCProcessSetupInterfaceBridged(virConnectPtr conn, if (virNetDevBandwidthSet(net->ifname, virDomainNetGetActualBandwidth(net)) < 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("cannot set bandwidth limits on %s"), - net->ifname); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot set bandwidth limits on %s"), + net->ifname); goto cleanup; } @@ -311,8 +311,8 @@ static int virLXCProcessSetupInterfaceDirect(virConnectPtr conn, */ bw = virDomainNetGetActualBandwidth(net); if (bw) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unable to set network bandwidth on direct interfaces")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set network bandwidth on direct interfaces")); return -1; } @@ -325,8 +325,8 @@ static int virLXCProcessSetupInterfaceDirect(virConnectPtr conn, */ prof = virDomainNetGetActualVirtPortProfile(net); if (prof) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Unable to set port profile on direct interfaces")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Unable to set port profile on direct interfaces")); return -1; } @@ -416,8 +416,8 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_BRIDGE: { const char *brname = virDomainNetGetActualBridgeName(def->nets[i]); if (!brname) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("No bridge name specified")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No bridge name specified")); goto cleanup; } if (virLXCProcessSetupInterfaceBridged(conn, @@ -445,11 +445,11 @@ static int virLXCProcessSetupInterfaces(virConnectPtr conn, case VIR_DOMAIN_NET_TYPE_MCAST: case VIR_DOMAIN_NET_TYPE_INTERNAL: case VIR_DOMAIN_NET_TYPE_LAST: - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Unsupported network type %s"), - virDomainNetTypeToString( - virDomainNetGetActualType(def->nets[i]) - )); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unsupported network type %s"), + virDomainNetTypeToString( + virDomainNetGetActualType(def->nets[i]) + )); goto cleanup; } } @@ -508,8 +508,8 @@ static int virLXCProcessMonitorClient(virLXCDriverPtr driver, memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Socket path %s too big for destination"), sockpath); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Socket path %s too big for destination"), sockpath); goto error; } @@ -537,8 +537,8 @@ int virLXCProcessStop(virLXCDriverPtr driver, int rc; if (vm->pid <= 0) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("Invalid PID %d for container"), vm->pid); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid PID %d for container"), vm->pid); return -1; } @@ -561,8 +561,8 @@ int virLXCProcessStop(virLXCDriverPtr driver, goto cleanup; } if (rc == 1) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Some container PIDs refused to die")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Some container PIDs refused to die")); rc = -1; goto cleanup; } @@ -811,27 +811,27 @@ int virLXCProcessStart(virConnectPtr conn, virErrorPtr err = NULL; if (!lxc_driver->cgroup) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("The 'cpuacct', 'devices' & 'memory' cgroups controllers must be mounted")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("The 'cpuacct', 'devices' & 'memory' cgroups controllers must be mounted")); return -1; } if (!virCgroupMounted(lxc_driver->cgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'cpuacct' cgroups controller mount")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'cpuacct' cgroups controller mount")); return -1; } if (!virCgroupMounted(lxc_driver->cgroup, VIR_CGROUP_CONTROLLER_DEVICES)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'devices' cgroups controller mount")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'devices' cgroups controller mount")); return -1; } if (!virCgroupMounted(lxc_driver->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) { - lxcError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to find 'memory' cgroups controller mount")); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to find 'memory' cgroups controller mount")); return -1; } @@ -906,8 +906,8 @@ int virLXCProcessStart(virConnectPtr conn, for (i = 0 ; i < vm->def->nconsoles ; i++) { char *ttyPath; if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) { - lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only PTY console types are supported")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only PTY console types are supported")); goto cleanup; } @@ -1021,8 +1021,8 @@ int virLXCProcessStart(virConnectPtr conn, char out[1024]; if (!(virLXCProcessReadLogOutput(vm, logfile, pos, out, 1024) < 0)) { - lxcError(VIR_ERR_INTERNAL_ERROR, - _("guest failed to start: %s"), out); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("guest failed to start: %s"), out); } goto error; diff --git a/src/util/virterror_internal.h b/src/util/virterror_internal.h index 06417b5..0508d38 100644 --- a/src/util/virterror_internal.h +++ b/src/util/virterror_internal.h @@ -157,6 +157,11 @@ void virReportOOMErrorFull(int domcode, virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) +# define virReportError(code, ...) \ + virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + + int virSetError(virErrorPtr newerr); void virDispatchError(virConnectPtr conn); const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen); -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Update the LXC driver to use the virNetClient APIs for connecting to the libvirt_lxc monitor, instead of the low-level socket APIs. This is a step towards running a full RPC protocol with libvirt_lxc Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/lxc/lxc_domain.c | 3 - src/lxc/lxc_domain.h | 5 +- src/lxc/lxc_process.c | 161 +++++++++++++++++-------------------------------- 3 files changed, 58 insertions(+), 111 deletions(-) diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 0376f0b..ec450f0 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -32,9 +32,6 @@ static void *virLXCDomainObjPrivateAlloc(void) if (VIR_ALLOC(priv) < 0) return NULL; - priv->monitor = -1; - priv->monitorWatch = -1; - return priv; } diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h index 08d09c1..845d85a 100644 --- a/src/lxc/lxc_domain.h +++ b/src/lxc/lxc_domain.h @@ -24,12 +24,13 @@ # define __LXC_DOMAIN_H__ # include "lxc_conf.h" +# include "rpc/virnetclient.h" + typedef struct _lxcDomainObjPrivate lxcDomainObjPrivate; typedef lxcDomainObjPrivate *lxcDomainObjPrivatePtr; struct _lxcDomainObjPrivate { - int monitor; - int monitorWatch; + virNetClientPtr monitor; }; void virLXCDomainSetPrivateDataHooks(virCapsPtr caps); diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index f8e2e31..cc276b7 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -178,8 +178,9 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, /* Stop autodestroy in case guest is restarted */ virLXCProcessAutoDestroyRemove(driver, vm); - virEventRemoveHandle(priv->monitorWatch); - VIR_FORCE_CLOSE(priv->monitor); + virNetClientClose(priv->monitor); + virNetClientFree(priv->monitor); + priv->monitor = NULL; virPidFileDelete(driver->stateDir, vm->def->name); virDomainDeleteConfig(driver->stateDir, NULL, vm); @@ -187,8 +188,6 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason); vm->pid = -1; vm->def->id = -1; - priv->monitor = -1; - priv->monitorWatch = -1; for (i = 0 ; i < vm->def->nnets ; i++) { virDomainNetDefPtr iface = vm->def->nets[i]; @@ -472,60 +471,69 @@ cleanup: } -static int virLXCProcessMonitorClient(virLXCDriverPtr driver, - virDomainObjPtr vm) +extern virLXCDriverPtr lxc_driver; +static void virLXCProcessMonitorEOFNotify(virNetClientPtr client ATTRIBUTE_UNUSED, + void *opaque) +{ + virLXCDriverPtr driver = lxc_driver; + virDomainObjPtr vm = opaque; + virDomainEventPtr event = NULL; + + lxcDriverLock(driver); + virDomainObjLock(vm); + lxcDriverUnlock(driver); + + virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN); + event = virDomainEventNewFromObj(vm, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); + virDomainAuditStop(vm, "shutdown"); + if (!vm->persistent) { + virDomainRemoveInactive(&driver->domains, vm); + vm = NULL; + } + + if (vm) + virDomainObjUnlock(vm); + if (event) { + lxcDriverLock(driver); + virDomainEventStateQueue(driver->domainEventState, event); + lxcDriverUnlock(driver); + } +} + + +static virNetClientPtr virLXCProcessConnectMonitor(virLXCDriverPtr driver, + virDomainObjPtr vm) { char *sockpath = NULL; - int fd = -1; - struct sockaddr_un addr; + virNetClientPtr monitor = NULL; if (virAsprintf(&sockpath, "%s/%s.sock", driver->stateDir, vm->def->name) < 0) { virReportOOMError(); - return -1; + return NULL; } - if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0) { - VIR_ERROR(_("Failed to set security context for monitor for %s"), - vm->def->name); - goto error; - } + if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0) + goto cleanup; - fd = socket(PF_UNIX, SOCK_STREAM, 0); + monitor = virNetClientNewUNIX(sockpath, false, NULL); if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0) { - VIR_ERROR(_("Failed to clear security context for monitor for %s"), - vm->def->name); - goto error; - } - - if (fd < 0) { - virReportSystemError(errno, "%s", - _("Failed to create client socket")); - goto error; - } - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Socket path %s too big for destination"), sockpath); - goto error; + virNetClientFree(monitor); + monitor = NULL; + goto cleanup; } - if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - virReportSystemError(errno, "%s", - _("Failed to connect to client socket")); - goto error; - } + if (!monitor) + goto cleanup; - VIR_FREE(sockpath); - return fd; + virNetClientSetEOFNotify(monitor, virLXCProcessMonitorEOFNotify, vm, NULL); -error: +cleanup: VIR_FREE(sockpath); - VIR_FORCE_CLOSE(fd); - return -1; + return monitor; } @@ -581,51 +589,6 @@ cleanup: return rc; } -extern virLXCDriverPtr lxc_driver; -static void virLXCProcessMonitorEvent(int watch, - int fd, - int events ATTRIBUTE_UNUSED, - void *data) -{ - virLXCDriverPtr driver = lxc_driver; - virDomainObjPtr vm = data; - virDomainEventPtr event = NULL; - lxcDomainObjPrivatePtr priv; - - lxcDriverLock(driver); - virDomainObjLock(vm); - lxcDriverUnlock(driver); - - priv = vm->privateData; - - if (priv->monitor != fd || priv->monitorWatch != watch) { - virEventRemoveHandle(watch); - goto cleanup; - } - - if (virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) { - virEventRemoveHandle(watch); - } else { - event = virDomainEventNewFromObj(vm, - VIR_DOMAIN_EVENT_STOPPED, - VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN); - virDomainAuditStop(vm, "shutdown"); - } - if (!vm->persistent) { - virDomainRemoveInactive(&driver->domains, vm); - vm = NULL; - } - -cleanup: - if (vm) - virDomainObjUnlock(vm); - if (event) { - lxcDriverLock(driver); - virDomainEventStateQueue(driver->domainEventState, event); - lxcDriverUnlock(driver); - } -} - static virCommandPtr virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, @@ -1003,7 +966,7 @@ int virLXCProcessStart(virConnectPtr conn, /* Connect to the controller as a client *first* because * this will block until the child has written their * pid file out to disk */ - if ((priv->monitor = virLXCProcessMonitorClient(driver, vm)) < 0) + if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) goto cleanup; /* And get its pid */ @@ -1028,14 +991,6 @@ int virLXCProcessStart(virConnectPtr conn, goto error; } - if ((priv->monitorWatch = virEventAddHandle( - priv->monitor, - VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, - virLXCProcessMonitorEvent, - vm, NULL)) < 0) { - goto error; - } - if (autoDestroy && virLXCProcessAutoDestroyAdd(driver, vm, conn) < 0) goto error; @@ -1085,7 +1040,9 @@ cleanup: VIR_FREE(veths[i]); } if (rc != 0) { - VIR_FORCE_CLOSE(priv->monitor); + virNetClientClose(priv->monitor); + virNetClientFree(priv->monitor); + priv->monitor = NULL; virDomainConfVMNWFilterTeardown(vm); virSecurityManagerRestoreAllLabel(driver->securityManager, @@ -1191,14 +1148,7 @@ virLXCProcessReconnectDomain(void *payload, const void *name ATTRIBUTE_UNUSED, v virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN); - if ((priv->monitor = virLXCProcessMonitorClient(driver, vm)) < 0) - goto error; - - if ((priv->monitorWatch = virEventAddHandle( - priv->monitor, - VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP, - virLXCProcessMonitorEvent, - vm, NULL)) < 0) + if (!(priv->monitor = virLXCProcessConnectMonitor(driver, vm))) goto error; if (virSecurityManagerReserveLabel(driver->securityManager, @@ -1221,7 +1171,6 @@ virLXCProcessReconnectDomain(void *payload, const void *name ATTRIBUTE_UNUSED, v } else { vm->def->id = -1; - VIR_FORCE_CLOSE(priv->monitor); } cleanup: -- 1.7.10.4

From: "Daniel P. Berrange" <berrange@redhat.com> Move the code that handles the LXC monitor out of the lxc_process.c file and into lxc_monitor.{c,h} Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/Makefile.am | 1 + src/lxc/lxc_domain.h | 4 +- src/lxc/lxc_monitor.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_monitor.h | 54 +++++++++++++++++ src/lxc/lxc_process.c | 49 +++++++++------ 5 files changed, 249 insertions(+), 19 deletions(-) create mode 100644 src/lxc/lxc_monitor.c create mode 100644 src/lxc/lxc_monitor.h diff --git a/src/Makefile.am b/src/Makefile.am index 59f1ac8..6cec08e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -352,6 +352,7 @@ LXC_DRIVER_SOURCES = \ lxc/lxc_container.c lxc/lxc_container.h \ lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ lxc/lxc_domain.c lxc/lxc_domain.h \ + lxc/lxc_monitor.c lxc/lxc_monitor.h \ lxc/lxc_process.c lxc/lxc_process.h \ lxc/lxc_driver.c lxc/lxc_driver.h diff --git a/src/lxc/lxc_domain.h b/src/lxc/lxc_domain.h index 845d85a..cbe19f5 100644 --- a/src/lxc/lxc_domain.h +++ b/src/lxc/lxc_domain.h @@ -24,13 +24,13 @@ # define __LXC_DOMAIN_H__ # include "lxc_conf.h" -# include "rpc/virnetclient.h" +# include "lxc_monitor.h" typedef struct _lxcDomainObjPrivate lxcDomainObjPrivate; typedef lxcDomainObjPrivate *lxcDomainObjPrivatePtr; struct _lxcDomainObjPrivate { - virNetClientPtr monitor; + virLXCMonitorPtr monitor; }; void virLXCDomainSetPrivateDataHooks(virCapsPtr caps); diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c new file mode 100644 index 0000000..fef985a --- /dev/null +++ b/src/lxc/lxc_monitor.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * + * lxc_monitor.c: client for LXC controller monitor + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <config.h> + +#include "lxc_monitor.h" +#include "lxc_conf.h" + +#include "memory.h" + +#include "virterror_internal.h" +#include "logging.h" +#include "threads.h" +#include "rpc/virnetclient.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +struct _virLXCMonitor { + int refs; + + virMutex lock; /* also used to protect fd */ + + virDomainObjPtr vm; + virLXCMonitorCallbacksPtr cb; + + virNetClientPtr client; +}; + +static void virLXCMonitorFree(virLXCMonitorPtr mon); + + +static void virLXCMonitorEOFNotify(virNetClientPtr client ATTRIBUTE_UNUSED, + void *opaque) +{ + virLXCMonitorPtr mon = opaque; + virLXCMonitorCallbackEOFNotify eofNotify; + virDomainObjPtr vm; + + virLXCMonitorLock(mon); + eofNotify = mon->cb->eofNotify; + vm = mon->vm; + virLXCMonitorUnlock(mon); + + eofNotify(mon, vm); +} + + +virLXCMonitorPtr virLXCMonitorNew(virDomainObjPtr vm, + const char *socketdir, + virLXCMonitorCallbacksPtr cb) +{ + virLXCMonitorPtr mon; + char *sockpath = NULL; + + if (VIR_ALLOC(mon) < 0) + return NULL; + + if (virMutexInit(&mon->lock) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot initialize monitor mutex")); + VIR_FREE(mon); + return NULL; + } + + if (virAsprintf(&sockpath, "%s/%s.sock", + socketdir, vm->def->name) < 0) + goto no_memory; + + if (!(mon->client = virNetClientNewUNIX(sockpath, false, NULL))) + goto error; + + + mon->vm = vm; + mon->cb = cb; + + virNetClientSetEOFNotify(mon->client, virLXCMonitorEOFNotify, mon, NULL); + +cleanup: + VIR_FREE(sockpath); + return mon; + +no_memory: + virReportOOMError(); +error: + virLXCMonitorClose(mon); + virLXCMonitorFree(mon); + mon = NULL; + goto cleanup; +} + + +static void virLXCMonitorFree(virLXCMonitorPtr mon) +{ + VIR_DEBUG("mon=%p", mon); + if (mon->client) + virLXCMonitorClose(mon); + + if (mon->cb && mon->cb->destroy) + (mon->cb->destroy)(mon, mon->vm); + virMutexDestroy(&mon->lock); + virNetClientFree(mon->client); + VIR_FREE(mon); +} + + +int virLXCMonitorRef(virLXCMonitorPtr mon) +{ + mon->refs++; + return mon->refs; +} + +int virLXCMonitorUnref(virLXCMonitorPtr mon) +{ + mon->refs--; + + if (mon->refs == 0) { + virLXCMonitorUnlock(mon); + virLXCMonitorFree(mon); + return 0; + } + + return mon->refs; +} + + +void virLXCMonitorClose(virLXCMonitorPtr mon) +{ + virNetClientClose(mon->client); + virNetClientFree(mon->client); + mon->client = NULL; +} + + +void virLXCMonitorLock(virLXCMonitorPtr mon) +{ + virMutexLock(&mon->lock); +} + + +void virLXCMonitorUnlock(virLXCMonitorPtr mon) +{ + virMutexUnlock(&mon->lock); +} diff --git a/src/lxc/lxc_monitor.h b/src/lxc/lxc_monitor.h new file mode 100644 index 0000000..c2448bb --- /dev/null +++ b/src/lxc/lxc_monitor.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010-2012 Red Hat, Inc. + * + * lxc_monitor.h: client for LXC controller monitor + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __LXC_MONITOR_H__ +# define __LXC_MONITOR_H__ + +#include "domain_conf.h" + +typedef struct _virLXCMonitor virLXCMonitor; +typedef virLXCMonitor *virLXCMonitorPtr; + +typedef struct _virLXCMonitorCallbacks virLXCMonitorCallbacks; +typedef virLXCMonitorCallbacks *virLXCMonitorCallbacksPtr; + +typedef void (*virLXCMonitorCallbackDestroy)(virLXCMonitorPtr mon, + virDomainObjPtr vm); +typedef void (*virLXCMonitorCallbackEOFNotify)(virLXCMonitorPtr mon, + virDomainObjPtr vm); + +struct _virLXCMonitorCallbacks { + virLXCMonitorCallbackDestroy destroy; + virLXCMonitorCallbackEOFNotify eofNotify; +}; + +virLXCMonitorPtr virLXCMonitorNew(virDomainObjPtr vm, + const char *socketdir, + virLXCMonitorCallbacksPtr cb); + +void virLXCMonitorClose(virLXCMonitorPtr mon); + +void virLXCMonitorLock(virLXCMonitorPtr mon); +void virLXCMonitorUnlock(virLXCMonitorPtr mon); + +int virLXCMonitorRef(virLXCMonitorPtr mon); +int virLXCMonitorUnref(virLXCMonitorPtr mon); + +#endif /* __LXC_MONITOR_H__ */ diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index cc276b7..ba7f3e0 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -178,8 +178,8 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, /* Stop autodestroy in case guest is restarted */ virLXCProcessAutoDestroyRemove(driver, vm); - virNetClientClose(priv->monitor); - virNetClientFree(priv->monitor); + virLXCMonitorClose(priv->monitor); + virLXCMonitorUnref(priv->monitor); priv->monitor = NULL; virPidFileDelete(driver->stateDir, vm->def->name); @@ -471,12 +471,25 @@ cleanup: } +static void virLXCProcessMonitorDestroy(virLXCMonitorPtr mon, + virDomainObjPtr vm) +{ + lxcDomainObjPrivatePtr priv; + + virDomainObjLock(vm); + priv = vm->privateData; + if (priv->monitor == mon) + priv->monitor = NULL; + if (virDomainObjUnref(vm) > 0) + virDomainObjUnlock(vm); +} + + extern virLXCDriverPtr lxc_driver; -static void virLXCProcessMonitorEOFNotify(virNetClientPtr client ATTRIBUTE_UNUSED, - void *opaque) +static void virLXCProcessMonitorEOFNotify(virLXCMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm) { virLXCDriverPtr driver = lxc_driver; - virDomainObjPtr vm = opaque; virDomainEventPtr event = NULL; lxcDriverLock(driver); @@ -503,11 +516,17 @@ static void virLXCProcessMonitorEOFNotify(virNetClientPtr client ATTRIBUTE_UNUSE } -static virNetClientPtr virLXCProcessConnectMonitor(virLXCDriverPtr driver, - virDomainObjPtr vm) +static virLXCMonitorCallbacks monitorCallbacks = { + .eofNotify = virLXCProcessMonitorEOFNotify, + .destroy = virLXCProcessMonitorDestroy, +}; + + +static virLXCMonitorPtr virLXCProcessConnectMonitor(virLXCDriverPtr driver, + virDomainObjPtr vm) { char *sockpath = NULL; - virNetClientPtr monitor = NULL; + virLXCMonitorPtr monitor = NULL; if (virAsprintf(&sockpath, "%s/%s.sock", driver->stateDir, vm->def->name) < 0) { @@ -518,19 +537,15 @@ static virNetClientPtr virLXCProcessConnectMonitor(virLXCDriverPtr driver, if (virSecurityManagerSetSocketLabel(driver->securityManager, vm->def) < 0) goto cleanup; - monitor = virNetClientNewUNIX(sockpath, false, NULL); + monitor = virLXCMonitorNew(vm, sockpath, &monitorCallbacks); if (virSecurityManagerClearSocketLabel(driver->securityManager, vm->def) < 0) { - virNetClientFree(monitor); + virLXCMonitorClose(monitor); + virLXCMonitorUnref(monitor); monitor = NULL; goto cleanup; } - if (!monitor) - goto cleanup; - - virNetClientSetEOFNotify(monitor, virLXCProcessMonitorEOFNotify, vm, NULL); - cleanup: VIR_FREE(sockpath); return monitor; @@ -1040,8 +1055,8 @@ cleanup: VIR_FREE(veths[i]); } if (rc != 0) { - virNetClientClose(priv->monitor); - virNetClientFree(priv->monitor); + virLXCMonitorClose(priv->monitor); + virLXCMonitorUnref(priv->monitor); priv->monitor = NULL; virDomainConfVMNWFilterTeardown(vm); -- 1.7.10.4
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Jiri Denemark