@@ -1136,10 +1136,6 @@ qemuMonitorTextSetBalloon(qemuMonitorPtr mon,
}


/*
* Returns: 0 if CPU hotplug not supported, +1 if CPU hotplug worked
* or -1 on failure
*/
int qemuMonitorTextSetCPU(qemuMonitorPtr mon, int cpu, bool online)
{
char *cmd;
@@ -1149,22 +1145,23 @@ int qemuMonitorTextSetCPU(qemuMonitorPtr mon, int cpu, bool online)
if (virAsprintf(&cmd, "cpu_set %d %s", cpu, online ? "online" : "offline") < 0)
return -1;

if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) {
VIR_FREE(cmd);
return -1;
}
VIR_FREE(cmd);
if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0)
goto cleanup;

/* If the command failed qemu prints: 'unknown command'
* No message is printed on success it seems */
if (strstr(reply, "unknown command:")) {
/* Don't set error - it is expected CPU onlining fails on many qemu - caller will handle */
ret = 0;
} else {
ret = 1;
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot change vcpu count of this domain"));
goto cleanup;
}

ret = 0;

cleanup:
VIR_FREE(reply);
VIR_FREE(cmd);

return ret;
}

@@ -1356,15 +1353,15 @@ int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon,
#define MIGRATION_DISK_REMAINING_PREFIX "remaining disk: "
#define MIGRATION_DISK_TOTAL_PREFIX "total disk: "

int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon,
qemuMonitorMigrationStatusPtr status)
int qemuMonitorTextGetMigrationStats(qemuMonitorPtr mon,
qemuMonitorMigrationStatsPtr stats)
{
char *reply;
char *tmp;
char *end;
int ret = -1;

memset(status, 0, sizeof(*status));
memset(stats, 0, sizeof(*stats));

if (qemuMonitorHMPCommand(mon, "info migrate", &reply) < 0)
return -1;
@@ -1379,97 +1376,97 @@ int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon,
}
*end = '\0';

status->status = qemuMonitorMigrationStatusTypeFromString(tmp);
if (status->status < 0) {
stats->status = qemuMonitorMigrationStatusTypeFromString(tmp);
if (stats->status < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected migration status in %s"), reply);
goto cleanup;
}

if (status->status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) {
if (stats->status == QEMU_MONITOR_MIGRATION_STATUS_ACTIVE) {
tmp = end + 1;

if (!(tmp = strstr(tmp, MIGRATION_TRANSFER_PREFIX)))
goto done;
tmp += strlen(MIGRATION_TRANSFER_PREFIX);

if (virStrToLong_ull(tmp, &end, 10,
&status->ram_transferred) < 0) {
&stats->ram_transferred) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse migration data transferred "
"statistic %s"), tmp);
goto cleanup;
}
status->ram_transferred *= 1024;
stats->ram_transferred *= 1024;
tmp = end;

if (!(tmp = strstr(tmp, MIGRATION_REMAINING_PREFIX)))
goto done;
tmp += strlen(MIGRATION_REMAINING_PREFIX);

if (virStrToLong_ull(tmp, &end, 10, &status->ram_remaining) < 0) {
if (virStrToLong_ull(tmp, &end, 10, &stats->ram_remaining) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse migration data remaining "
"statistic %s"), tmp);
goto cleanup;
}
status->ram_remaining *= 1024;
stats->ram_remaining *= 1024;
tmp = end;

if (!(tmp = strstr(tmp, MIGRATION_TOTAL_PREFIX)))
goto done;
tmp += strlen(MIGRATION_TOTAL_PREFIX);

if (virStrToLong_ull(tmp, &end, 10, &status->ram_total) < 0) {
if (virStrToLong_ull(tmp, &end, 10, &stats->ram_total) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse migration data total "
"statistic %s"), tmp);
goto cleanup;
}
status->ram_total *= 1024;
stats->ram_total *= 1024;
tmp = end;

/*
* Check for Optional Disk Migration status
* Check for Optional Disk Migration stats
*/
if (!(tmp = strstr(tmp, MIGRATION_DISK_TRANSFER_PREFIX)))
goto done;
tmp += strlen(MIGRATION_DISK_TRANSFER_PREFIX);

if (virStrToLong_ull(tmp, &end, 10,
&status->disk_transferred) < 0) {
&stats->disk_transferred) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse disk migration data "
"transferred statistic %s"), tmp);
goto cleanup;
}
status->disk_transferred *= 1024;
stats->disk_transferred *= 1024;
tmp = end;

if (!(tmp = strstr(tmp, MIGRATION_DISK_REMAINING_PREFIX)))
goto done;
tmp += strlen(MIGRATION_DISK_REMAINING_PREFIX);

if (virStrToLong_ull(tmp, &end, 10, &status->disk_remaining) < 0) {
if (virStrToLong_ull(tmp, &end, 10, &stats->disk_remaining) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse disk migration data remaining "
"statistic %s"), tmp);
goto cleanup;
}
status->disk_remaining *= 1024;
stats->disk_remaining *= 1024;
tmp = end;

if (!(tmp = strstr(tmp, MIGRATION_DISK_TOTAL_PREFIX)))
goto done;
tmp += strlen(MIGRATION_DISK_TOTAL_PREFIX);

if (virStrToLong_ull(tmp, &end, 10, &status->disk_total) < 0) {
if (virStrToLong_ull(tmp, &end, 10, &stats->disk_total) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse disk migration data total "
"statistic %s"), tmp);
goto cleanup;
}
status->disk_total *= 1024;
stats->disk_total *= 1024;
}
}

@@ -1479,7 +1476,7 @@ int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon,
cleanup:
VIR_FREE(reply);
if (ret < 0)
memset(status, 0, sizeof(*status));
memset(stats, 0, sizeof(*stats));
return ret;
}

@@ -103,8 +103,8 @@ int qemuMonitorTextSetMigrationSpeed(qemuMonitorPtr mon,
int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon,
unsigned long long downtime);

int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon,
qemuMonitorMigrationStatusPtr status);
int qemuMonitorTextGetMigrationStats(qemuMonitorPtr mon,
qemuMonitorMigrationStatsPtr stats);

int qemuMonitorTextMigrate(qemuMonitorPtr mon,
unsigned int flags,
@@ -203,7 +203,7 @@ qemuConnectAgent(virQEMUDriverPtr driver, virDomainObjPtr vm)
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret = -1;
qemuAgentPtr agent = NULL;
virDomainChrSourceDefPtr config = qemuFindAgentConfig(vm->def);
virDomainChrDefPtr config = qemuFindAgentConfig(vm->def);

if (!config)
return 0;
@@ -223,7 +223,7 @@ qemuConnectAgent(virQEMUDriverPtr driver, virDomainObjPtr vm)
virObjectUnlock(vm);

agent = qemuAgentOpen(vm,
config,
&config->source,
&agentCallbacks);

virObjectLock(vm);
@@ -1507,7 +1507,7 @@ qemuProcessHandleMigrationStatus(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
goto cleanup;
}

priv->job.current->status.status = status;
priv->job.current->stats.status = status;
virDomainObjBroadcast(vm);

cleanup:
@@ -2020,11 +2020,11 @@ qemuProcessDetectVcpuPIDs(virQEMUDriverPtr driver,
return 0;
}

if (ncpupids != vm->def->vcpus) {
if (ncpupids != virDomainDefGetVcpus(vm->def)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("got wrong number of vCPU pids from QEMU monitor. "
"got %d, wanted %d"),
ncpupids, vm->def->vcpus);
ncpupids, virDomainDefGetVcpus(vm->def));
VIR_FREE(cpupids);
return -1;
}
@@ -2234,17 +2234,17 @@ qemuProcessSetLinkStates(virQEMUDriverPtr driver,
static int
qemuProcessSetVcpuAffinities(virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainDefPtr def = vm->def;
virDomainPinDefPtr pininfo;
int n;
int ret = -1;
VIR_DEBUG("Setting affinity on CPUs nvcpupin=%zu nvcpus=%d nvcpupids=%d",
def->cputune.nvcpupin, def->vcpus, priv->nvcpupids);
VIR_DEBUG("Setting affinity on CPUs nvcpupin=%zu nvcpus=%d hasVcpupids=%d",
def->cputune.nvcpupin, virDomainDefGetVcpus(def),
qemuDomainHasVcpuPids(vm));
if (!def->cputune.nvcpupin)
return 0;

if (priv->vcpupids == NULL) {
if (!qemuDomainHasVcpuPids(vm)) {
/* If any CPU has custom affinity that differs from the
* VM default affinity, we must reject it
*/
@@ -2259,14 +2259,14 @@ qemuProcessSetVcpuAffinities(virDomainObjPtr vm)
return 0;
}

for (n = 0; n < def->vcpus; n++) {
for (n = 0; n < virDomainDefGetVcpus(def); n++) {
/* set affinity only for existing vcpus */
if (!(pininfo = virDomainPinFind(def->cputune.vcpupin,
def->cputune.nvcpupin,
n)))
continue;

if (virProcessSetAffinity(priv->vcpupids[n],
if (virProcessSetAffinity(qemuDomainGetVcpuPid(vm, n),
pininfo->cpumask) < 0) {
goto cleanup;
}
@@ -2354,7 +2354,7 @@ qemuProcessSetSchedulers(virDomainObjPtr vm)
size_t i = 0;

for (i = 0; i < priv->nvcpupids; i++) {
if (qemuProcessSetSchedParams(i, priv->vcpupids[i],
if (qemuProcessSetSchedParams(i, qemuDomainGetVcpuPid(vm, i),
vm->def->cputune.nvcpusched,
vm->def->cputune.vcpusched) < 0)
return -1;
@@ -2862,7 +2862,8 @@ qemuProcessCleanupChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
if (dev->source.type == VIR_DOMAIN_CHR_TYPE_UNIX &&
dev->source.data.nix.listen)
dev->source.data.nix.listen &&
dev->source.data.nix.path)
unlink(dev->source.data.nix.path);

return 0;
@@ -3869,7 +3870,7 @@ qemuValidateCpuMax(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
if (!maxCpus)
return true;

if (def->maxvcpus > maxCpus) {
if (virDomainDefGetVcpusMax(def) > maxCpus) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("Maximum CPUs greater than specified machine type limit"));
return false;
@@ -4124,6 +4125,7 @@ qemuProcessIncomingDefFree(qemuProcessIncomingDefPtr inc)
if (!inc)
return;

VIR_FREE(inc->address);
VIR_FREE(inc->launchURI);
VIR_FREE(inc->deferredURI);
VIR_FREE(inc);
@@ -4137,6 +4139,7 @@ qemuProcessIncomingDefFree(qemuProcessIncomingDefPtr inc)
*/
qemuProcessIncomingDefPtr
qemuProcessIncomingDefNew(virQEMUCapsPtr qemuCaps,
const char *listenAddress,
const char *migrateFrom,
int fd,
const char *path)
@@ -4149,6 +4152,9 @@ qemuProcessIncomingDefNew(virQEMUCapsPtr qemuCaps,
if (VIR_ALLOC(inc) < 0)
return NULL;

if (VIR_STRDUP(inc->address, listenAddress) < 0)
goto error;

inc->launchURI = qemuMigrationIncomingURI(migrateFrom, fd);
if (!inc->launchURI)
goto error;
@@ -4542,6 +4548,7 @@ qemuProcessLaunch(virConnectPtr conn,
unsigned int hostdev_flags = 0;
size_t nnicindexes = 0;
int *nicindexes = NULL;
bool check_shmem = false;

VIR_DEBUG("vm=%p name=%s id=%d asyncJob=%d "
"incoming.launchURI=%s incoming.deferredURI=%s "
@@ -4670,7 +4677,7 @@ qemuProcessLaunch(virConnectPtr conn,
* either <vcpu> or <numatune> is 'auto'.
*/
if (virDomainDefNeedsPlacementAdvice(vm->def)) {
nodeset = virNumaGetAutoPlacementAdvice(vm->def->vcpus,
nodeset = virNumaGetAutoPlacementAdvice(virDomainDefGetVcpus(vm->def),
virDomainDefGetMemoryActual(vm->def));
if (!nodeset)
goto cleanup;
@@ -4749,6 +4756,50 @@ qemuProcessLaunch(virConnectPtr conn,
goto cleanup;
}

VIR_DEBUG("Checking for any possible (non-fatal) issues");

/*
* For vhost-user to work, the domain has to have some type of
* shared memory configured. We're not the proper ones to judge
* whether shared hugepages or shm are enough and will be in the
* future, so we'll just warn in case neither is configured.
* Moreover failing would give the false illusion that libvirt is
* really checking that everything works before running the domain
* and not only we are unable to do that, but it's also not our
* aim to do so.
*/
for (i = 0; i < vm->def->nnets; i++) {
if (virDomainNetGetActualType(vm->def->nets[i]) ==
VIR_DOMAIN_NET_TYPE_VHOSTUSER) {
check_shmem = true;
break;
}
}

if (check_shmem) {
bool shmem = vm->def->nshmems;

/*
* This check is by no means complete. We merely check
* whether there are *some* hugepages enabled and *some* NUMA
* nodes with shared memory access.
*/
if (!shmem && vm->def->mem.nhugepages) {
for (i = 0; i < virDomainNumaGetNodeCount(vm->def->numa); i++) {
if (virDomainNumaGetNodeMemoryAccessMode(vm->def->numa, i) ==
VIR_NUMA_MEM_ACCESS_SHARED) {
shmem = true;
break;
}
}
}

if (!shmem) {
VIR_WARN("Detected vhost-user interface without any shared memory, "
"the interface might not be operational");
}
}

VIR_DEBUG("Building emulator command line");
if (!(cmd = qemuBuildCommandLine(conn, driver, vm->def, priv->monConfig,
priv->monJSON, priv->qemuCaps,
@@ -5092,7 +5143,7 @@ qemuProcessStart(virConnectPtr conn,
goto cleanup;

if (migrateFrom) {
incoming = qemuProcessIncomingDefNew(priv->qemuCaps, migrateFrom,
incoming = qemuProcessIncomingDefNew(priv->qemuCaps, NULL, migrateFrom,
migrateFd, migratePath);
if (!incoming)
goto stop;
@@ -47,13 +47,15 @@ int qemuProcessAssignPCIAddresses(virDomainDefPtr def);
typedef struct _qemuProcessIncomingDef qemuProcessIncomingDef;
typedef qemuProcessIncomingDef *qemuProcessIncomingDefPtr;
struct _qemuProcessIncomingDef {
char *address; /* address where QEMU is supposed to listen */
char *launchURI; /* used as a parameter for -incoming command line option */
char *deferredURI; /* used when calling migrate-incoming QMP command */
int fd; /* for fd:N URI */
const char *path; /* path associated with fd */
};

qemuProcessIncomingDefPtr qemuProcessIncomingDefNew(virQEMUCapsPtr qemuCaps,
const char *listenAddress,
const char *migrateFrom,
int fd,
const char *path);
@@ -38,27 +38,9 @@

%#include <libvirt/libvirt.h>
%#include "internal.h"
%#include "virxdrdefs.h"
%#include <arpa/inet.h>

/* cygwin's xdr implementation defines xdr_u_int64_t instead of xdr_uint64_t
* and lacks IXDR_PUT_INT32 and IXDR_GET_INT32
*/
%#ifdef HAVE_XDR_U_INT64_T
%# define xdr_uint64_t xdr_u_int64_t
%#endif
%#ifndef IXDR_PUT_INT32
%# define IXDR_PUT_INT32 IXDR_PUT_LONG
%#endif
%#ifndef IXDR_GET_INT32
%# define IXDR_GET_INT32 IXDR_GET_LONG
%#endif
%#ifndef IXDR_PUT_U_INT32
%# define IXDR_PUT_U_INT32 IXDR_PUT_U_LONG
%#endif
%#ifndef IXDR_GET_U_INT32
%# define IXDR_GET_U_INT32 IXDR_GET_U_LONG
%#endif

/*----- Data types. -----*/

/* Length of long, but not unbounded, strings.
@@ -49,7 +49,7 @@
my $protocol = shift or die "missing protocol argument";
my @autogen;

my $connect_ptr = $structprefix eq "admin" ? "virAdmDaemonPtr" : "virConnectPtr";
my $connect_ptr = $structprefix eq "admin" ? "virAdmConnectPtr" : "virConnectPtr";
my $prefix = ($structprefix eq "admin") ? "admin" : "vir";

sub fixup_name {
@@ -21,27 +21,9 @@
*/

%#include "internal.h"
%#include "virxdrdefs.h"
%#include <arpa/inet.h>

/* cygwin's xdr implementation defines xdr_u_int64_t instead of xdr_uint64_t
* and lacks IXDR_PUT_INT32 and IXDR_GET_INT32
*/
%#ifdef HAVE_XDR_U_INT64_T
%# define xdr_uint64_t xdr_u_int64_t
%#endif
%#ifndef IXDR_PUT_INT32
%# define IXDR_PUT_INT32 IXDR_PUT_LONG
%#endif
%#ifndef IXDR_GET_INT32
%# define IXDR_GET_INT32 IXDR_GET_LONG
%#endif
%#ifndef IXDR_PUT_U_INT32
%# define IXDR_PUT_U_INT32 IXDR_PUT_U_LONG
%#endif
%#ifndef IXDR_GET_U_INT32
%# define IXDR_GET_U_INT32 IXDR_GET_U_LONG
%#endif

/*----- Data types. -----*/

/* Initial message size.
@@ -1107,36 +1107,38 @@ static void virNetServerClientDispatchRead(virNetServerClientPtr client)

/* Now figure out if we need to read more data to get some
* file descriptors */
if (msg->header.type == VIR_NET_CALL_WITH_FDS &&
virNetMessageDecodeNumFDs(msg) < 0) {
virNetMessageQueueServe(&client->rx);
virNetMessageFree(msg);
client->wantClose = true;
return; /* Error */
}

/* Try getting the file descriptors (may fail if blocking) */
for (i = msg->donefds; i < msg->nfds; i++) {
int rv;
if ((rv = virNetSocketRecvFD(client->sock, &(msg->fds[i]))) < 0) {
if (msg->header.type == VIR_NET_CALL_WITH_FDS) {
if (msg->nfds == 0 &&
virNetMessageDecodeNumFDs(msg) < 0) {
virNetMessageQueueServe(&client->rx);
virNetMessageFree(msg);
client->wantClose = true;
return;
return; /* Error */
}
if (rv == 0) /* Blocking */
break;
msg->donefds++;
}

/* Need to poll() until FDs arrive */
if (msg->donefds < msg->nfds) {
/* Because DecodeHeader/NumFDs reset bufferOffset, we
* put it back to what it was, so everything works
* again next time we run this method
*/
client->rx->bufferOffset = client->rx->bufferLength;
return;
/* Try getting the file descriptors (may fail if blocking) */
for (i = msg->donefds; i < msg->nfds; i++) {
int rv;
if ((rv = virNetSocketRecvFD(client->sock, &(msg->fds[i]))) < 0) {
virNetMessageQueueServe(&client->rx);
virNetMessageFree(msg);
client->wantClose = true;
return;
}
if (rv == 0) /* Blocking */
break;
msg->donefds++;
}

/* Need to poll() until FDs arrive */
if (msg->donefds < msg->nfds) {
/* Because DecodeHeader/NumFDs reset bufferOffset, we
* put it back to what it was, so everything works
* again next time we run this method
*/
client->rx->bufferOffset = client->rx->bufferLength;
return;
}
}

/* Definitely finished reading, so remove from queue */
@@ -619,6 +619,10 @@ int virNetSocketNewConnectUNIX(const char *path,
virSocketAddr remoteAddr;
char *rundir = NULL;
int ret = -1;
bool daemonLaunched = false;

VIR_DEBUG("path=%s spawnDaemon=%d binary=%s", path, spawnDaemon,
NULLSTR(binary));

memset(&localAddr, 0, sizeof(localAddr));
memset(&remoteAddr, 0, sizeof(remoteAddr));
@@ -680,19 +684,29 @@ int virNetSocketNewConnectUNIX(const char *path,
if (remoteAddr.data.un.sun_path[0] == '@')
remoteAddr.data.un.sun_path[0] = '\0';

while (retries &&
connect(fd, &remoteAddr.data.sa, remoteAddr.len) < 0) {
if (!(spawnDaemon && (errno == ENOENT ||
errno == ECONNREFUSED))) {
while (retries) {
if (connect(fd, &remoteAddr.data.sa, remoteAddr.len) == 0) {
VIR_DEBUG("connect() succeeded");
break;
}
VIR_DEBUG("connect() failed: retries=%d errno=%d", retries, errno);

retries--;
if (!spawnDaemon ||
retries == 0 ||
(errno != ENOENT && errno != ECONNREFUSED)) {
virReportSystemError(errno, _("Failed to connect socket to '%s'"),
path);
goto cleanup;
}

if (virNetSocketForkDaemon(binary) < 0)
goto cleanup;
if (!daemonLaunched) {
if (virNetSocketForkDaemon(binary) < 0)
goto cleanup;

daemonLaunched = true;
}

retries--;
usleep(5000);
}

@@ -1259,7 +1273,11 @@ int virNetSocketGetUNIXIdentity(virNetSocketPtr sock,
pid_t *pid,
unsigned long long *timestamp)
{
# if defined(HAVE_STRUCT_SOCKPEERCRED)
struct sockpeercred cr;
# else
struct ucred cr;
# endif
socklen_t cr_len = sizeof(cr);
int ret = -1;

Large diffs are not rendered by default.

Large diffs are not rendered by default.

@@ -222,9 +222,9 @@ virSecurityStackReserveLabel(virSecurityManagerPtr mgr,


static int
virSecurityStackSetSecurityDiskLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virDomainDiskDefPtr disk)
virSecurityStackSetDiskLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virDomainDiskDefPtr disk)
{
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
virSecurityStackItemPtr item = priv->itemsHead;
@@ -240,9 +240,9 @@ virSecurityStackSetSecurityDiskLabel(virSecurityManagerPtr mgr,


static int
virSecurityStackRestoreSecurityDiskLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virDomainDiskDefPtr disk)
virSecurityStackRestoreDiskLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virDomainDiskDefPtr disk)
{
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
virSecurityStackItemPtr item = priv->itemsHead;
@@ -258,10 +258,10 @@ virSecurityStackRestoreSecurityDiskLabel(virSecurityManagerPtr mgr,


static int
virSecurityStackSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virDomainHostdevDefPtr dev,
const char *vroot)
virSecurityStackSetHostdevLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virDomainHostdevDefPtr dev,
const char *vroot)

{
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
@@ -281,10 +281,10 @@ virSecurityStackSetSecurityHostdevLabel(virSecurityManagerPtr mgr,


static int
virSecurityStackRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virDomainHostdevDefPtr dev,
const char *vroot)
virSecurityStackRestoreHostdevLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virDomainHostdevDefPtr dev,
const char *vroot)
{
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
virSecurityStackItemPtr item = priv->itemsHead;
@@ -303,9 +303,9 @@ virSecurityStackRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,


static int
virSecurityStackSetSecurityAllLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
const char *stdin_path)
virSecurityStackSetAllLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
const char *stdin_path)
{
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
virSecurityStackItemPtr item = priv->itemsHead;
@@ -321,9 +321,9 @@ virSecurityStackSetSecurityAllLabel(virSecurityManagerPtr mgr,


static int
virSecurityStackRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
bool migrated)
virSecurityStackRestoreAllLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
bool migrated)
{
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
virSecurityStackItemPtr item = priv->itemsHead;
@@ -565,9 +565,9 @@ virSecurityStackGetBaseLabel(virSecurityManagerPtr mgr, int virtType)
}

static int
virSecurityStackSetSecurityImageLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virStorageSourcePtr src)
virSecurityStackSetImageLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virStorageSourcePtr src)
{
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
virSecurityStackItemPtr item = priv->itemsHead;
@@ -582,9 +582,9 @@ virSecurityStackSetSecurityImageLabel(virSecurityManagerPtr mgr,
}

static int
virSecurityStackRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virStorageSourcePtr src)
virSecurityStackRestoreImageLabel(virSecurityManagerPtr mgr,
virDomainDefPtr vm,
virStorageSourcePtr src)
{
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
virSecurityStackItemPtr item = priv->itemsHead;
@@ -631,11 +631,11 @@ virSecurityDriver virSecurityDriverStack = {

.domainSecurityVerify = virSecurityStackVerify,

.domainSetSecurityDiskLabel = virSecurityStackSetSecurityDiskLabel,
.domainRestoreSecurityDiskLabel = virSecurityStackRestoreSecurityDiskLabel,
.domainSetSecurityDiskLabel = virSecurityStackSetDiskLabel,
.domainRestoreSecurityDiskLabel = virSecurityStackRestoreDiskLabel,

.domainSetSecurityImageLabel = virSecurityStackSetSecurityImageLabel,
.domainRestoreSecurityImageLabel = virSecurityStackRestoreSecurityImageLabel,
.domainSetSecurityImageLabel = virSecurityStackSetImageLabel,
.domainRestoreSecurityImageLabel = virSecurityStackRestoreImageLabel,

.domainSetSecurityDaemonSocketLabel = virSecurityStackSetDaemonSocketLabel,
.domainSetSecuritySocketLabel = virSecurityStackSetSocketLabel,
@@ -649,11 +649,11 @@ virSecurityDriver virSecurityDriverStack = {
.domainSetSecurityProcessLabel = virSecurityStackSetProcessLabel,
.domainSetSecurityChildProcessLabel = virSecurityStackSetChildProcessLabel,

.domainSetSecurityAllLabel = virSecurityStackSetSecurityAllLabel,
.domainRestoreSecurityAllLabel = virSecurityStackRestoreSecurityAllLabel,
.domainSetSecurityAllLabel = virSecurityStackSetAllLabel,
.domainRestoreSecurityAllLabel = virSecurityStackRestoreAllLabel,

.domainSetSecurityHostdevLabel = virSecurityStackSetSecurityHostdevLabel,
.domainRestoreSecurityHostdevLabel = virSecurityStackRestoreSecurityHostdevLabel,
.domainSetSecurityHostdevLabel = virSecurityStackSetHostdevLabel,
.domainRestoreSecurityHostdevLabel = virSecurityStackRestoreHostdevLabel,

.domainSetSavedStateLabel = virSecurityStackSetSavedStateLabel,
.domainRestoreSavedStateLabel = virSecurityStackRestoreSavedStateLabel,
@@ -1127,7 +1127,10 @@ get_files(vahControl * ctl)
ctl->def->fss[i]->src) {
virDomainFSDefPtr fs = ctl->def->fss[i];

if (vah_add_path(&buf, fs->src, fs->readonly ? "r" : "rw", true) != 0)
/* We don't need to add deny rw rules for readonly mounts,
* this can only lead to troubles when mounting / readonly.
*/
if (vah_add_path(&buf, fs->src, "rw", true) != 0)
goto cleanup;
}
}
@@ -1389,9 +1389,21 @@ static struct diskType const disk_types[] = {
};


/*
* virStorageBackendDetectBlockVolFormatFD
* @target: target definition ptr of volume to update
* @fd: fd of storage volume to update,
* @readflags: VolReadErrorMode flags to handle read error after open
* is successful, but read is not.
*
* Returns 0 for success, -1 on a legitimate error condition, -2 if
* the read error is desired to be ignored (along with appropriate
* VIR_WARN of the issue).
*/
static int
virStorageBackendDetectBlockVolFormatFD(virStorageSourcePtr target,
int fd)
int fd,
unsigned int readflags)
{
size_t i;
off_t start;
@@ -1410,10 +1422,16 @@ virStorageBackendDetectBlockVolFormatFD(virStorageSourcePtr target,
}
bytes = saferead(fd, buffer, sizeof(buffer));
if (bytes < 0) {
virReportSystemError(errno,
_("cannot read beginning of file '%s'"),
target->path);
return -1;
if (readflags & VIR_STORAGE_VOL_READ_NOERROR) {
VIR_WARN("ignoring failed saferead of file '%s'",
target->path);
return -2;
} else {
virReportSystemError(errno,
_("cannot read beginning of file '%s'"),
target->path);
return -1;
}
}

for (i = 0; disk_types[i].part_table_type != -1; i++) {
@@ -1426,6 +1444,10 @@ virStorageBackendDetectBlockVolFormatFD(virStorageSourcePtr target,
}
}

if (target->format == VIR_STORAGE_POOL_DISK_UNKNOWN)
VIR_DEBUG("cannot determine the target format for '%s'",
target->path);

return 0;
}

@@ -1577,10 +1599,24 @@ virStorageBackendVolOpen(const char *path, struct stat *sb,
return fd;
}

/*
* virStorageBackendUpdateVolTargetInfo
* @target: target definition ptr of volume to update
* @withBlockVolFormat: true if caller determined a block file
* @openflags: various VolOpenCheckMode flags to handle errors on open
* @readflags: VolReadErrorMode flags to handle read error after open
* is successful, but read is not.
*
* Returns 0 for success, -1 on a legitimate error condition, and -2
* if the openflags used VIR_STORAGE_VOL_OPEN_NOERROR and some sort of
* open error occurred. It is up to the caller to handle. A -2 may also
* be returned if the caller passed a readflagsflag.
*/
int
virStorageBackendUpdateVolTargetInfo(virStorageSourcePtr target,
bool withBlockVolFormat,
unsigned int openflags)
unsigned int openflags,
unsigned int readflags)
{
int ret, fd = -1;
struct stat sb;
@@ -1604,16 +1640,27 @@ virStorageBackendUpdateVolTargetInfo(virStorageSourcePtr target,

if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
virReportSystemError(errno, _("cannot seek to start of '%s'"), target->path);
ret = -1;
goto cleanup;
}

if ((len = virFileReadHeaderFD(fd, len, &buf)) < 0) {
virReportSystemError(errno, _("cannot read header '%s'"), target->path);
if (readflags & VIR_STORAGE_VOL_READ_NOERROR) {
VIR_WARN("ignoring failed header read for '%s'",
target->path);
ret = -2;
} else {
virReportSystemError(errno,
_("cannot read header '%s'"),
target->path);
ret = -1;
}
goto cleanup;
}

if (!(meta = virStorageFileGetMetadataFromBuf(target->path, buf, len, target->format,
NULL))) {
ret = -1;
goto cleanup;
}

@@ -1622,7 +1669,8 @@ virStorageBackendUpdateVolTargetInfo(virStorageSourcePtr target,
}

if (withBlockVolFormat) {
if ((ret = virStorageBackendDetectBlockVolFormatFD(target, fd)) < 0)
if ((ret = virStorageBackendDetectBlockVolFormatFD(target, fd,
readflags)) < 0)
goto cleanup;
}

@@ -1633,23 +1681,36 @@ virStorageBackendUpdateVolTargetInfo(virStorageSourcePtr target,
return ret;
}

/*
* virStorageBackendUpdateVolInfo
* @vol: Pointer to a volume storage definition
* @withBlockVolFormat: true if the caller determined a block file
* @openflags: various VolOpenCheckMode flags to handle errors on open
* @readflags: various VolReadErrorMode flags to handle errors on read
*
* Returns 0 for success, -1 on a legitimate error condition, and -2
* if the openflags used VIR_STORAGE_VOL_OPEN_NOERROR and some sort of
* open error occurred. It is up to the caller to handle.
*/
int
virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
bool withBlockVolFormat,
unsigned int openflags)
unsigned int openflags,
unsigned int readflags)
{
int ret;

if ((ret = virStorageBackendUpdateVolTargetInfo(&vol->target,
withBlockVolFormat,
openflags)) < 0)
openflags, readflags)) < 0)
return ret;

if (vol->target.backingStore &&
(ret = virStorageBackendUpdateVolTargetInfo(vol->target.backingStore,
withBlockVolFormat,
VIR_STORAGE_VOL_OPEN_DEFAULT |
VIR_STORAGE_VOL_OPEN_NOERROR) < 0))
VIR_STORAGE_VOL_OPEN_NOERROR,
readflags) < 0))
return ret;

return 0;
@@ -1926,30 +1987,30 @@ virStorageBackendVolZeroSparseFileLocal(virStorageVolDefPtr vol,


static int
virStorageBackendWipeExtentLocal(virStorageVolDefPtr vol,
int fd,
off_t extent_start,
off_t extent_length,
char *writebuf,
size_t writebuf_length,
size_t *bytes_wiped)
virStorageBackendWipeLocal(virStorageVolDefPtr vol,
int fd,
unsigned long long wipe_len,
size_t writebuf_length)
{
int ret = -1, written = 0;
off_t remaining = 0;
unsigned long long remaining = 0;
size_t write_size = 0;
char *writebuf = NULL;

VIR_DEBUG("wiping start: 0 len: %llu", wipe_len);

VIR_DEBUG("extent logical start: %ju len: %ju",
(uintmax_t)extent_start, (uintmax_t)extent_length);
if (VIR_ALLOC_N(writebuf, writebuf_length) < 0)
goto cleanup;

if ((ret = lseek(fd, extent_start, SEEK_SET)) < 0) {
if (lseek(fd, 0, SEEK_SET) < 0) {
virReportSystemError(errno,
_("Failed to seek to position %ju in volume "
_("Failed to seek to the start in volume "
"with path '%s'"),
(uintmax_t)extent_start, vol->target.path);
vol->target.path);
goto cleanup;
}

remaining = extent_length;
remaining = wipe_len;
while (remaining > 0) {

write_size = (writebuf_length < remaining) ? writebuf_length : remaining;
@@ -1963,24 +2024,23 @@ virStorageBackendWipeExtentLocal(virStorageVolDefPtr vol,
goto cleanup;
}

*bytes_wiped += written;
remaining -= written;
}

if (fdatasync(fd) < 0) {
ret = -errno;
virReportSystemError(errno,
_("cannot sync data to volume with path '%s'"),
vol->target.path);
goto cleanup;
}

VIR_DEBUG("Wrote %zu bytes to volume with path '%s'",
*bytes_wiped, vol->target.path);
VIR_DEBUG("Wrote %llu bytes to volume with path '%s'",
wipe_len, vol->target.path);

ret = 0;

cleanup:
VIR_FREE(writebuf);
return ret;
}

@@ -1994,8 +2054,6 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
{
int ret = -1, fd = -1;
struct stat st;
char *writebuf = NULL;
size_t bytes_wiped = 0;
virCommandPtr cmd = NULL;

virCheckFlags(0, -1);
@@ -2063,23 +2121,15 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) {
ret = virStorageBackendVolZeroSparseFileLocal(vol, st.st_size, fd);
} else {

if (VIR_ALLOC_N(writebuf, st.st_blksize) < 0)
goto cleanup;

ret = virStorageBackendWipeExtentLocal(vol,
fd,
0,
vol->target.allocation,
writebuf,
st.st_blksize,
&bytes_wiped);
ret = virStorageBackendWipeLocal(vol,
fd,
vol->target.allocation,
st.st_blksize);
}
}

cleanup:
virCommandFree(cmd);
VIR_FREE(writebuf);
VIR_FORCE_CLOSE(fd);
return ret;
}
@@ -179,6 +179,15 @@ enum {
VIR_STORAGE_VOL_OPEN_DIR = 1 << 4, /* directories okay */
};

/* VolReadErrorMode flags
* If flag is present, then operation won't cause fatal error for
* specified operation, rather a VIR_WARN will be issued and a -2 returned
* for function call
*/
enum {
VIR_STORAGE_VOL_READ_NOERROR = 1 << 0, /* ignore *read errors */
};

# define VIR_STORAGE_VOL_OPEN_DEFAULT (VIR_STORAGE_VOL_OPEN_REG |\
VIR_STORAGE_VOL_OPEN_BLOCK)

@@ -192,10 +201,12 @@ int virStorageBackendVolOpen(const char *path, struct stat *sb,

int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
bool withBlockVolFormat,
unsigned int openflags);
unsigned int openflags,
unsigned int readflags);
int virStorageBackendUpdateVolTargetInfo(virStorageSourcePtr target,
bool withBlockVolFormat,
unsigned int openflags);
unsigned int openflags,
unsigned int readflags);
int virStorageBackendUpdateVolTargetInfoFD(virStorageSourcePtr target,
int fd,
struct stat *sb);
@@ -154,14 +154,15 @@ virStorageBackendDiskMakeDataVol(virStoragePoolObjPtr pool,
if (vol->source.partType == VIR_STORAGE_VOL_DISK_TYPE_EXTENDED) {
if (virStorageBackendUpdateVolInfo(vol, false,
VIR_STORAGE_VOL_OPEN_DEFAULT |
VIR_STORAGE_VOL_OPEN_NOERROR) == -1)
VIR_STORAGE_VOL_OPEN_NOERROR,
0) == -1)
return -1;
vol->target.allocation = 0;
vol->target.capacity =
(vol->source.extents[0].end - vol->source.extents[0].start);
} else {
if (virStorageBackendUpdateVolInfo(vol, false,
VIR_STORAGE_VOL_OPEN_DEFAULT) < 0)
VIR_STORAGE_VOL_OPEN_DEFAULT, 0) < 0)
return -1;
}

@@ -1,7 +1,7 @@
/*
* storage_backend_fs.c: storage backend for FS and directory handling
*
* Copyright (C) 2007-2014 Red Hat, Inc.
* Copyright (C) 2007-2015 Red Hat, Inc.
* Copyright (C) 2007-2008 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
@@ -375,6 +375,39 @@ virStorageBackendFileSystemIsValid(virStoragePoolObjPtr pool)
return 0;
}


/**
* virStorageBackendFileSystemGetPoolSource
* @pool: storage pool object pointer
*
* Allocate/return a string representing the FS storage pool source.
* It is up to the caller to VIR_FREE the allocated string
*/
static char *
virStorageBackendFileSystemGetPoolSource(virStoragePoolObjPtr pool)
{
char *src = NULL;

if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
if (pool->def->source.format == VIR_STORAGE_POOL_NETFS_CIFS) {
if (virAsprintf(&src, "//%s/%s",
pool->def->source.hosts[0].name,
pool->def->source.dir) < 0)
return NULL;
} else {
if (virAsprintf(&src, "%s:%s",
pool->def->source.hosts[0].name,
pool->def->source.dir) < 0)
return NULL;
}
} else {
if (VIR_STRDUP(src, pool->def->source.devices[0].path) < 0)
return NULL;
}
return src;
}


/**
* @pool storage pool to check for status
*
@@ -385,6 +418,8 @@ virStorageBackendFileSystemIsValid(virStoragePoolObjPtr pool)
static int
virStorageBackendFileSystemIsMounted(virStoragePoolObjPtr pool)
{
int ret = -1;
char *src = NULL;
FILE *mtab;
struct mntent ent;
char buf[1024];
@@ -393,18 +428,28 @@ virStorageBackendFileSystemIsMounted(virStoragePoolObjPtr pool)
virReportSystemError(errno,
_("cannot read mount list '%s'"),
_PATH_MOUNTED);
return -1;
goto cleanup;
}

while ((getmntent_r(mtab, &ent, buf, sizeof(buf))) != NULL) {
if (STREQ(ent.mnt_dir, pool->def->target.path)) {
VIR_FORCE_FCLOSE(mtab);
return 1;
if (!(src = virStorageBackendFileSystemGetPoolSource(pool)))
goto cleanup;

if (STREQ(ent.mnt_dir, pool->def->target.path) &&
STREQ(ent.mnt_fsname, src)) {
ret = 1;
goto cleanup;
}

VIR_FREE(src);
}

ret = 0;

cleanup:
VIR_FORCE_FCLOSE(mtab);
return 0;
VIR_FREE(src);
return ret;
}

/**
@@ -445,22 +490,8 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool)
return -1;
}

if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
if (pool->def->source.format == VIR_STORAGE_POOL_NETFS_CIFS) {
if (virAsprintf(&src, "//%s/%s",
pool->def->source.hosts[0].name,
pool->def->source.dir) == -1)
return -1;
} else {
if (virAsprintf(&src, "%s:%s",
pool->def->source.hosts[0].name,
pool->def->source.dir) == -1)
return -1;
}
} else {
if (VIR_STRDUP(src, pool->def->source.devices[0].path) < 0)
return -1;
}
if (!(src = virStorageBackendFileSystemGetPoolSource(pool)))
return -1;

if (netauto)
cmd = virCommandNewArgList(MOUNT,
@@ -921,7 +952,7 @@ virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
if (vol->target.backingStore) {
ignore_value(virStorageBackendUpdateVolTargetInfo(vol->target.backingStore,
false,
VIR_STORAGE_VOL_OPEN_DEFAULT));
VIR_STORAGE_VOL_OPEN_DEFAULT, 0));
/* If this failed, the backing file is currently unavailable,
* the capacity, allocation, owner, group and mode are unknown.
* An error message was raised, but we just continue. */
@@ -1057,6 +1088,14 @@ virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
else
vol->type = VIR_STORAGE_VOL_FILE;

/* Volumes within a directory pools are not recursive; do not
* allow escape to ../ or a subdir */
if (strchr(vol->name, '/')) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("volume name '%s' cannot contain '/'"), vol->name);
return -1;
}

VIR_FREE(vol->target.path);
if (virAsprintf(&vol->target.path, "%s/%s",
pool->def->target.path,
@@ -1245,7 +1284,7 @@ virStorageBackendFileSystemVolRefresh(virConnectPtr conn,

/* Refresh allocation / capacity / permissions info in case its changed */
ret = virStorageBackendUpdateVolInfo(vol, false,
VIR_STORAGE_VOL_FS_OPEN_FLAGS);
VIR_STORAGE_VOL_FS_OPEN_FLAGS, 0);
if (ret < 0)
return ret;

@@ -162,7 +162,7 @@ virStorageBackendLogicalMakeVol(char **const groups,
goto cleanup;

if (virStorageBackendUpdateVolInfo(vol, false,
VIR_STORAGE_VOL_OPEN_DEFAULT) < 0)
VIR_STORAGE_VOL_OPEN_DEFAULT, 0) < 0)
goto cleanup;

nextents = 1;
@@ -414,10 +414,16 @@ virStorageBackendLogicalFindPoolSourcesFunc(char **const groups,
return -1;
}

static char *
virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
const char *srcSpec ATTRIBUTE_UNUSED,
unsigned int flags)
/*
* @sourceList: Pointer to a storage pool source list
*
* Use the pvs command to fill the list of pv_name and vg_name associated
* into the passed sourceList.
*
* Returns 0 if successful, -1 and sets error on failure
*/
static int
virStorageBackendLogicalGetPoolSources(virStoragePoolSourceListPtr sourceList)
{
/*
* # pvs --noheadings -o pv_name,vg_name
@@ -431,11 +437,7 @@ virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
2
};
virCommandPtr cmd;
char *retval = NULL;
virStoragePoolSourceList sourceList;
size_t i;

virCheckFlags(0, NULL);
int ret = -1;

/*
* NOTE: ignoring errors here; this is just to "touch" any logical volumes
@@ -447,20 +449,38 @@ virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
VIR_WARN("Failure when running vgscan to refresh physical volumes");
virCommandFree(cmd);

memset(&sourceList, 0, sizeof(sourceList));
sourceList.type = VIR_STORAGE_POOL_LOGICAL;

cmd = virCommandNewArgList(PVS,
"--noheadings",
"-o", "pv_name,vg_name",
NULL);
if (virCommandRunRegex(cmd, 1, regexes, vars,
virStorageBackendLogicalFindPoolSourcesFunc,
&sourceList, "pvs") < 0) {
virCommandFree(cmd);
return NULL;
}
sourceList, "pvs") < 0)
goto cleanup;
ret = 0;

cleanup:
virCommandFree(cmd);
return ret;
}


static char *
virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
const char *srcSpec ATTRIBUTE_UNUSED,
unsigned int flags)
{
virStoragePoolSourceList sourceList;
size_t i;
char *retval = NULL;

virCheckFlags(0, NULL);

memset(&sourceList, 0, sizeof(sourceList));
sourceList.type = VIR_STORAGE_POOL_LOGICAL;

if (virStorageBackendLogicalGetPoolSources(&sourceList) < 0)
goto cleanup;

retval = virStoragePoolSourceListFormat(&sourceList);
if (retval == NULL) {
@@ -478,19 +498,119 @@ virStorageBackendLogicalFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
}


/*
* virStorageBackendLogicalMatchPoolSource
* @pool: Pointer to the source pool object
*
* Search the output generated by a 'pvs --noheadings -o pv_name,vg_name'
* to match the 'vg_name' with the pool def->source.name and for the list
* of pool def->source.devices[].
*
* Returns true if the volume group name matches the pool's source.name
* and at least one of the pool's def->source.devices[] matches the
* list of physical device names listed for the pool. Return false if
* we cannot find a matching volume group name and if we cannot match
* the any device list members.
*/
static bool
virStorageBackendLogicalMatchPoolSource(virStoragePoolObjPtr pool)
{
virStoragePoolSourceList sourceList;
virStoragePoolSource *thisSource;
size_t i, j;
int matchcount = 0;
bool ret = false;

memset(&sourceList, 0, sizeof(sourceList));
sourceList.type = VIR_STORAGE_POOL_LOGICAL;

if (virStorageBackendLogicalGetPoolSources(&sourceList) < 0)
goto cleanup;

/* Search the pvs output for this pool's source.name */
for (i = 0; i < sourceList.nsources; i++) {
thisSource = &sourceList.sources[i];
if (STREQ(thisSource->name, pool->def->source.name))
break;
}

if (i == sourceList.nsources) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("cannot find logical volume group name '%s'"),
pool->def->source.name);
goto cleanup;
}

/* If the pool has defined source device(s), then let's make sure
* they match as well; otherwise, matching can only occur on the
* pool's name.
*/
if (!pool->def->source.ndevice) {
ret = true;
goto cleanup;
}

/* Let's make sure the pool's device(s) match what the pvs output has
* for volume group devices.
*/
for (i = 0; i < pool->def->source.ndevice; i++) {
for (j = 0; j < thisSource->ndevice; j++) {
if (STREQ(pool->def->source.devices[i].path,
thisSource->devices[j].path))
matchcount++;
}
}

/* If we didn't find any matches, then this pool has listed (a) source
* device path(s) that don't/doesn't match what was created for the pool
*/
if (matchcount == 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("cannot find any matching source devices for logical "
"volume group '%s'"), pool->def->source.name);
goto cleanup;
}

/* Either there's more devices in the pool source device list or there's
* more devices in the pvs output. Could easily happen if someone decides
* to 'add' to or 'remove' from the volume group outside of libvirt's
* knowledge. Rather than fail on that, provide a warning and move on.
*/
if (matchcount != pool->def->source.ndevice)
VIR_WARN("pool device list count doesn't match pvs device list count");

ret = true;

cleanup:
for (i = 0; i < sourceList.nsources; i++)
virStoragePoolSourceClear(&sourceList.sources[i]);
VIR_FREE(sourceList.sources);

return ret;
}


static int
virStorageBackendLogicalCheckPool(virStoragePoolObjPtr pool,
bool *isActive)
{
*isActive = virFileExists(pool->def->target.path);
/* If we can find the target.path as well as ensure that the
* pool's def source
*/
*isActive = virFileExists(pool->def->target.path) &&
virStorageBackendLogicalMatchPoolSource(pool);
return 0;
}

static int
virStorageBackendLogicalStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool)
{
if (virStorageBackendLogicalSetActive(pool, 1) < 0)
/* Let's make sure that the pool's name matches the pvs output and
* that the pool's source devices match the pvs output.
*/
if (!virStorageBackendLogicalMatchPoolSource(pool) ||
virStorageBackendLogicalSetActive(pool, 1) < 0)
return -1;

return 0;
@@ -61,7 +61,7 @@ virStorageBackendMpathNewVol(virStoragePoolObjPtr pool,
goto cleanup;

if (virStorageBackendUpdateVolInfo(vol, true,
VIR_STORAGE_VOL_OPEN_DEFAULT) < 0) {
VIR_STORAGE_VOL_OPEN_DEFAULT, 0) < 0) {
goto cleanup;
}

@@ -173,7 +173,7 @@ static int virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr ptr,
for (i = 0; i < source->nhost; i++) {
if (source->hosts[i].name != NULL &&
!source->hosts[i].port) {
virBufferAsprintf(&mon_host, "%s:6789,",
virBufferAsprintf(&mon_host, "%s,",
source->hosts[i].name);
} else if (source->hosts[i].name != NULL &&
source->hosts[i].port) {
@@ -281,18 +281,20 @@ static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
{
int ret = -1;
int r = 0;
rbd_image_t image;
rbd_image_t image = NULL;

r = rbd_open(ptr->ioctx, vol->name, &image, NULL);
if (r < 0) {
ret = -r;
virReportSystemError(-r, _("failed to open the RBD image '%s'"),
vol->name);
return ret;
goto cleanup;
}

rbd_image_info_t info;
r = rbd_stat(image, &info, sizeof(info));
if (r < 0) {
ret = -r;
virReportSystemError(-r, _("failed to stat the RBD image '%s'"),
vol->name);
goto cleanup;
@@ -306,6 +308,7 @@ static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
vol->target.capacity = info.size;
vol->target.allocation = info.obj_size * info.num_objs;
vol->type = VIR_STORAGE_VOL_NETWORK;
vol->target.format = VIR_STORAGE_FILE_RAW;

VIR_FREE(vol->target.path);
if (virAsprintf(&vol->target.path, "%s/%s",
@@ -322,7 +325,8 @@ static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
ret = 0;

cleanup:
rbd_close(image);
if (image)
rbd_close(image);
return ret;
}

@@ -398,7 +402,21 @@ static int virStorageBackendRBDRefreshPool(virConnectPtr conn,

name += strlen(name) + 1;

if (volStorageBackendRBDRefreshVolInfo(vol, pool, &ptr) < 0) {
r = volStorageBackendRBDRefreshVolInfo(vol, pool, &ptr);

/* It could be that a volume has been deleted through a different route
* then libvirt and that will cause a -ENOENT to be returned.
*
* Another possibility is that there is something wrong with the placement
* group (PG) that RBD image's header is in and that causes -ETIMEDOUT
* to be returned.
*
* Do not error out and simply ignore the volume
*/
if (r < 0) {
if (r == -ENOENT || r == -ETIMEDOUT)
continue;

virStorageVolDefFree(vol);
goto cleanup;
}
@@ -513,6 +531,9 @@ static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
ptr.cluster = NULL;
ptr.ioctx = NULL;

virCheckFlags(VIR_STORAGE_VOL_DELETE_ZEROED |
VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS, -1);

VIR_DEBUG("Removing RBD image %s/%s", pool->def->source.name, vol->name);

if (flags & VIR_STORAGE_VOL_DELETE_ZEROED)
@@ -554,6 +575,12 @@ virStorageBackendRBDCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
{
vol->type = VIR_STORAGE_VOL_NETWORK;

if (vol->target.format != VIR_STORAGE_FILE_RAW) {
virReportError(VIR_ERR_NO_SUPPORT, "%s",
_("only RAW volumes are supported by this storage pool"));
return -VIR_ERR_NO_SUPPORT;
}

VIR_FREE(vol->target.path);
if (virAsprintf(&vol->target.path, "%s/%s",
pool->def->source.name,
@@ -600,6 +627,12 @@ virStorageBackendRBDBuildVol(virConnectPtr conn,
goto cleanup;
}

if (vol->target.format != VIR_STORAGE_FILE_RAW) {
virReportError(VIR_ERR_NO_SUPPORT, "%s",
_("only RAW volumes are supported by this storage pool"));
goto cleanup;
}

if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source) < 0)
goto cleanup;

@@ -224,8 +224,10 @@ virStorageBackendSCSINewLun(virStoragePoolObjPtr pool,
goto cleanup;
}

if (virStorageBackendUpdateVolInfo(vol, true,
VIR_STORAGE_VOL_OPEN_DEFAULT) < 0)
/* Allow a volume read failure to ignore or skip this block file */
if ((retval = virStorageBackendUpdateVolInfo(vol, true,
VIR_STORAGE_VOL_OPEN_DEFAULT,
VIR_STORAGE_VOL_READ_NOERROR)) < 0)
goto cleanup;

if (!(vol->key = virStorageBackendSCSISerial(vol->target.path)))
@@ -151,7 +151,6 @@ static void
storageDriverAutostart(void)
{
size_t i;
char *stateFile = NULL;
virConnectPtr conn = NULL;

/* XXX Remove hardcoding of QEMU URI */
@@ -187,6 +186,8 @@ storageDriverAutostart(void)
}

if (started) {
char *stateFile;

virStoragePoolObjClearVols(pool);
stateFile = virFileBuildPath(driver->stateDir,
pool->def->name, ".xml");
@@ -201,11 +202,10 @@ storageDriverAutostart(void)
VIR_ERROR(_("Failed to autostart storage pool '%s': %s"),
pool->def->name, err ? err->message :
_("no error message found"));
VIR_FREE(stateFile);
virStoragePoolObjUnlock(pool);
continue;
} else {
pool->active = true;
}
pool->active = true;
VIR_FREE(stateFile);
}
virStoragePoolObjUnlock(pool);
}
@@ -671,8 +671,14 @@ storagePoolCreateXML(virConnectPtr conn,
virStoragePoolPtr ret = NULL;
virStorageBackendPtr backend;
char *stateFile = NULL;
unsigned int build_flags = 0;

virCheckFlags(0, NULL);
virCheckFlags(VIR_STORAGE_POOL_CREATE_WITH_BUILD |
VIR_STORAGE_POOL_CREATE_WITH_BUILD_OVERWRITE |
VIR_STORAGE_POOL_CREATE_WITH_BUILD_NO_OVERWRITE, NULL);

VIR_EXCLUSIVE_FLAGS_RET(VIR_STORAGE_POOL_BUILD_OVERWRITE,
VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, NULL);

storageDriverLock();
if (!(def = virStoragePoolDefParseString(xml)))
@@ -694,6 +700,22 @@ storagePoolCreateXML(virConnectPtr conn,
goto cleanup;
def = NULL;

if (backend->buildPool) {
if (flags & VIR_STORAGE_POOL_CREATE_WITH_BUILD_OVERWRITE)
build_flags |= VIR_STORAGE_POOL_BUILD_OVERWRITE;
else if (flags & VIR_STORAGE_POOL_CREATE_WITH_BUILD_NO_OVERWRITE)
build_flags |= VIR_STORAGE_POOL_BUILD_NO_OVERWRITE;

if (build_flags ||
(flags & VIR_STORAGE_POOL_CREATE_WITH_BUILD)) {
if (backend->buildPool(conn, pool, build_flags) < 0) {
virStoragePoolObjRemove(&driver->pools, pool);
pool = NULL;
goto cleanup;
}
}
}

if (backend->startPool &&
backend->startPool(conn, pool) < 0) {
virStoragePoolObjRemove(&driver->pools, pool);
@@ -845,8 +867,14 @@ storagePoolCreate(virStoragePoolPtr obj,
virStorageBackendPtr backend;
int ret = -1;
char *stateFile = NULL;
unsigned int build_flags = 0;

virCheckFlags(0, -1);
virCheckFlags(VIR_STORAGE_POOL_CREATE_WITH_BUILD |
VIR_STORAGE_POOL_CREATE_WITH_BUILD_OVERWRITE |
VIR_STORAGE_POOL_CREATE_WITH_BUILD_NO_OVERWRITE, -1);

VIR_EXCLUSIVE_FLAGS_RET(VIR_STORAGE_POOL_BUILD_OVERWRITE,
VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, -1);

if (!(pool = virStoragePoolObjFromStoragePool(obj)))
return -1;
@@ -864,6 +892,22 @@ storagePoolCreate(virStoragePoolPtr obj,
goto cleanup;
}

if (backend->buildPool) {
if (flags & VIR_STORAGE_POOL_CREATE_WITH_BUILD_OVERWRITE)
build_flags |= VIR_STORAGE_POOL_BUILD_OVERWRITE;
else if (flags & VIR_STORAGE_POOL_CREATE_WITH_BUILD_NO_OVERWRITE)
build_flags |= VIR_STORAGE_POOL_BUILD_NO_OVERWRITE;

if (build_flags ||
(flags & VIR_STORAGE_POOL_CREATE_WITH_BUILD)) {
if (backend->buildPool(obj->conn, pool, build_flags) < 0) {
virStoragePoolObjRemove(&driver->pools, pool);
pool = NULL;
goto cleanup;
}
}
}

VIR_INFO("Starting up storage pool '%s'", pool->def->name);
if (backend->startPool &&
backend->startPool(obj->conn, pool) < 0)
@@ -886,7 +930,8 @@ storagePoolCreate(virStoragePoolPtr obj,

cleanup:
VIR_FREE(stateFile);
virStoragePoolObjUnlock(pool);
if (pool)
virStoragePoolObjUnlock(pool);
return ret;
}

@@ -2436,7 +2481,14 @@ storageVolWipePattern(virStorageVolPtr obj,
goto cleanup;
}

ret = backend->wipeVol(obj->conn, pool, vol, algorithm, flags);
if (backend->wipeVol(obj->conn, pool, vol, algorithm, flags) < 0)
goto cleanup;

if (backend->refreshVol &&
backend->refreshVol(obj->conn, pool, vol) < 0)
goto cleanup;

ret = 0;

cleanup:
virStoragePoolObjUnlock(pool);
@@ -1928,7 +1928,7 @@ static int testDomainGetInfo(virDomainPtr domain,
info->state = virDomainObjGetState(privdom, NULL);
info->memory = privdom->def->mem.cur_balloon;
info->maxMem = virDomainDefGetMemoryActual(privdom->def);
info->nrVirtCpu = privdom->def->vcpus;
info->nrVirtCpu = virDomainDefGetVcpus(privdom->def);
info->cpuTime = ((tv.tv_sec * 1000ll * 1000ll * 1000ll) + (tv.tv_usec * 1000ll));
ret = 0;

@@ -2313,7 +2313,10 @@ testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
if (!(def = virDomainObjGetOneDef(vm, flags)))
goto cleanup;

ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
ret = virDomainDefGetVcpusMax(def);
else
ret = virDomainDefGetVcpus(def);

cleanup:
virDomainObjEndAPI(&vm);
@@ -2356,32 +2359,33 @@ testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus,
if (virDomainObjGetDefs(privdom, flags, &def, &persistentDef) < 0)
goto cleanup;

if (def && def->maxvcpus < nrCpus) {
if (def && virDomainDefGetVcpusMax(def) < nrCpus) {
virReportError(VIR_ERR_INVALID_ARG,
_("requested cpu amount exceeds maximum (%d > %d)"),
nrCpus, def->maxvcpus);
nrCpus, virDomainDefGetVcpusMax(def));
goto cleanup;
}

if (persistentDef &&
!(flags & VIR_DOMAIN_VCPU_MAXIMUM) &&
persistentDef->maxvcpus < nrCpus) {
virDomainDefGetVcpusMax(persistentDef) < nrCpus) {
virReportError(VIR_ERR_INVALID_ARG,
_("requested cpu amount exceeds maximum (%d > %d)"),
nrCpus, persistentDef->maxvcpus);
nrCpus, virDomainDefGetVcpusMax(persistentDef));
goto cleanup;
}

if (def)
def->vcpus = nrCpus;
if (def &&
virDomainDefSetVcpus(def, nrCpus) < 0)
goto cleanup;

if (persistentDef) {
if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
persistentDef->maxvcpus = nrCpus;
if (nrCpus < persistentDef->vcpus)
persistentDef->vcpus = nrCpus;
if (virDomainDefSetVcpusMax(persistentDef, nrCpus) < 0)
goto cleanup;
} else {
persistentDef->vcpus = nrCpus;
if (virDomainDefSetVcpus(persistentDef, nrCpus) < 0)
goto cleanup;
}
}

@@ -2444,8 +2448,8 @@ static int testDomainGetVcpus(virDomainPtr domain,
virBitmapSetAll(allcpumap);

/* Clamp to actual number of vcpus */
if (maxinfo > privdom->def->vcpus)
maxinfo = privdom->def->vcpus;
if (maxinfo > virDomainDefGetVcpus(privdom->def))
maxinfo = virDomainDefGetVcpus(privdom->def);

memset(info, 0, sizeof(*info) * maxinfo);
memset(cpumaps, 0, maxinfo * maplen);
@@ -2503,7 +2507,7 @@ static int testDomainPinVcpu(virDomainPtr domain,
goto cleanup;
}

if (vcpu > privdom->def->vcpus) {
if (vcpu > virDomainDefGetVcpus(privdom->def)) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("requested vcpu is higher than allocated vcpus"));
goto cleanup;
@@ -2557,8 +2561,8 @@ testDomainGetVcpuPinInfo(virDomainPtr dom,
virBitmapSetAll(allcpumap);

/* Clamp to actual number of vcpus */
if (ncpumaps > def->vcpus)
ncpumaps = def->vcpus;
if (ncpumaps > virDomainDefGetVcpus(def))
ncpumaps = virDomainDefGetVcpus(def);

for (vcpu = 0; vcpu < ncpumaps; vcpu++) {
virDomainPinDefPtr pininfo;
@@ -409,6 +409,7 @@ static int
umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
const virDomainDef *def ATTRIBUTE_UNUSED,
virCapsPtr caps ATTRIBUTE_UNUSED,
unsigned int parseFlags ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
@@ -436,6 +437,7 @@ umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
static int
umlDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps ATTRIBUTE_UNUSED,
unsigned int parseFlags ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
/* memory hotplug tunables are not supported by this driver */
@@ -1916,7 +1918,7 @@ static int umlDomainGetInfo(virDomainPtr dom,

info->maxMem = virDomainDefGetMemoryActual(vm->def);
info->memory = vm->def->mem.cur_balloon;
info->nrVirtCpu = vm->def->vcpus;
info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
ret = 0;

cleanup:
@@ -24,10 +24,9 @@
#include <config.h>

#include <stdio.h>
#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
#if defined HAVE_MNTENT_H && defined HAVE_SYS_MOUNT_H \
&& defined HAVE_GETMNTENT_R
# include <mntent.h>
#endif
#if defined HAVE_SYS_MOUNT_H
# include <sys/mount.h>
#endif
#include <fcntl.h>
@@ -38,6 +37,7 @@
#include <sys/types.h>
#include <signal.h>
#include <dirent.h>
#include <unistd.h>

#define __VIR_CGROUP_ALLOW_INCLUDE_PRIV_H__
#include "vircgrouppriv.h"
@@ -29,6 +29,7 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>

#if WITH_CAPNG
# include <cap-ng.h>
@@ -237,22 +237,13 @@ virHostdevGetPCIHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
}

virPCIDeviceSetManaged(dev, hostdev->managed);
if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) {
virObjectUnref(list);
return NULL;
}
} else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN) {
if (virPCIDeviceSetStubDriver(dev, "pciback") < 0) {
virObjectUnref(list);
return NULL;
}
} else {
if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) {
virObjectUnref(list);
return NULL;
}
}

if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_VFIO);
else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN)
virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_XEN);
else
virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_KVM);
}

return list;
@@ -574,7 +565,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
bool usesVfio = STREQ(virPCIDeviceGetStubDriver(dev), "vfio-pci");
bool usesVfio = (virPCIDeviceGetStubDriver(dev) == VIR_PCI_STUB_DRIVER_VFIO);
struct virHostdevIsPCINodeDeviceUsedData data = {hostdev_mgr, dom_name,
usesVfio};

@@ -585,15 +576,12 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
goto cleanup;
}

VIR_FREE(devAddr);
if (!(devAddr = virPCIDeviceGetAddress(dev)))
goto cleanup;

/* The device is in use by other active domain if
* the dev is in list activePCIHostdevs. VFIO devices
* belonging to same iommu group can't be shared
* across guests.
*/
devAddr = virPCIDeviceGetAddress(dev);
if (usesVfio) {
if (virPCIDeviceAddressIOMMUGroupIterate(devAddr,
virHostdevIsPCINodeDeviceUsed,
@@ -607,16 +595,29 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
/* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
if (virPCIDeviceGetManaged(dev) &&
virPCIDeviceDetach(dev, hostdev_mgr->activePCIHostdevs, NULL) < 0)
goto reattachdevs;

if (virPCIDeviceGetManaged(dev)) {
VIR_DEBUG("Detaching managed PCI device %s",
virPCIDeviceGetName(dev));
if (virPCIDeviceDetach(dev,
hostdev_mgr->activePCIHostdevs,
hostdev_mgr->inactivePCIHostdevs) < 0)
goto reattachdevs;
} else {
VIR_DEBUG("Not detaching unmanaged PCI device %s",
virPCIDeviceGetName(dev));
}
}

/* At this point, all devices are attached to the stub driver and have
* been marked as inactive */

/* Loop 3: Now that all the PCI hostdevs have been detached, we
* can safely reset them */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

VIR_DEBUG("Resetting PCI device %s", virPCIDeviceGetName(dev));
if (virPCIDeviceReset(dev, hostdev_mgr->activePCIHostdevs,
hostdev_mgr->inactivePCIHostdevs) < 0)
goto reattachdevs;
@@ -638,14 +639,20 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
/* Loop 5: Now mark all the devices as active */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

VIR_DEBUG("Adding PCI device %s to active list",
virPCIDeviceGetName(dev));
if (virPCIDeviceListAdd(hostdev_mgr->activePCIHostdevs, dev) < 0)
goto inactivedevs;
}

/* Loop 6: Now remove the devices from inactive list. */
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
virPCIDeviceListDel(hostdev_mgr->inactivePCIHostdevs, dev);
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

VIR_DEBUG("Removing PCI device %s from inactive list",
virPCIDeviceGetName(dev));
virPCIDeviceListDel(hostdev_mgr->inactivePCIHostdevs, dev);
}

/* Loop 7: Now set the used_by_domain of the device in
@@ -657,6 +664,8 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
dev = virPCIDeviceListGet(pcidevs, i);
activeDev = virPCIDeviceListFind(hostdev_mgr->activePCIHostdevs, dev);

VIR_DEBUG("Setting driver and domain information for PCI device %s",
virPCIDeviceGetName(dev));
if (activeDev)
virPCIDeviceSetUsedBy(activeDev, drv_name, dom_name);
}
@@ -680,6 +689,8 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
* "reprobe" were already set by pciDettachDevice in
* loop 2.
*/
VIR_DEBUG("Saving network configuration of PCI device %s",
virPCIDeviceGetName(dev));
if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) {
hostdev->origstates.states.pci.unbind_from_stub =
virPCIDeviceGetUnbindFromStub(pcidev);
@@ -705,6 +716,9 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
*/
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

VIR_DEBUG("Removing PCI device %s from active list",
virPCIDeviceGetName(dev));
virPCIDeviceListSteal(hostdev_mgr->activePCIHostdevs, dev);
}

@@ -717,18 +731,25 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

/* NB: This doesn't actually re-bind to original driver, just
* unbinds from the stub driver
*/
ignore_value(virPCIDeviceReattach(dev, hostdev_mgr->activePCIHostdevs,
NULL));
if (virPCIDeviceGetManaged(dev)) {
/* NB: This doesn't actually re-bind to original driver, just
* unbinds from the stub driver
*/
VIR_DEBUG("Reattaching managed PCI device %s",
virPCIDeviceGetName(dev));
ignore_value(virPCIDeviceReattach(dev,
hostdev_mgr->activePCIHostdevs,
hostdev_mgr->inactivePCIHostdevs));
} else {
VIR_DEBUG("Not reattaching unmanaged PCI device %s",
virPCIDeviceGetName(dev));
}
}

cleanup:
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnref(pcidevs);
VIR_FREE(devAddr);
return ret;
}

@@ -743,13 +764,15 @@ virHostdevReattachPCIDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr)
* successfully, it must have been inactive.
*/
if (!virPCIDeviceGetManaged(dev)) {
VIR_DEBUG("Adding unmanaged PCI device %s to inactive list",
virPCIDeviceGetName(dev));
if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, dev) < 0)
virPCIDeviceFree(dev);
return;
}

/* Wait for device cleanup if it is qemu/kvm */
if (STREQ(virPCIDeviceGetStubDriver(dev), "pci-stub")) {
if (virPCIDeviceGetStubDriver(dev) == VIR_PCI_STUB_DRIVER_KVM) {
int retries = 100;
while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
&& retries) {
@@ -758,6 +781,7 @@ virHostdevReattachPCIDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr)
}
}

VIR_DEBUG("Reattaching PCI device %s", virPCIDeviceGetName(dev));
if (virPCIDeviceReattach(dev, mgr->activePCIHostdevs,
mgr->inactivePCIHostdevs) < 0) {
virErrorPtr err = virGetLastError();
@@ -825,6 +849,8 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
}
}

VIR_DEBUG("Removing PCI device %s from active list",
virPCIDeviceGetName(dev));
virPCIDeviceListDel(hostdev_mgr->activePCIHostdevs, dev);
i++;
}
@@ -847,6 +873,8 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
pcisrc->addr.slot, pcisrc->addr.function);
if (dev) {
if (virPCIDeviceListFind(pcidevs, dev)) {
VIR_DEBUG("Restoring network configuration of PCI device %s",
virPCIDeviceGetName(dev));
virHostdevNetConfigRestore(hostdev, hostdev_mgr->stateDir,
oldStateDir);
}
@@ -859,6 +887,7 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);

VIR_DEBUG("Resetting PCI device %s", virPCIDeviceGetName(dev));
if (virPCIDeviceReset(dev, hostdev_mgr->activePCIHostdevs,
hostdev_mgr->inactivePCIHostdevs) < 0) {
virErrorPtr err = virGetLastError();
@@ -917,19 +946,15 @@ virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr,
goto cleanup;

virPCIDeviceSetManaged(dev, hostdev->managed);
if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0)
goto cleanup;
} else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN) {
if (virPCIDeviceSetStubDriver(dev, "pciback") < 0)
goto cleanup;
} else {
if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0)
goto cleanup;

}
virPCIDeviceSetUsedBy(dev, drv_name, dom_name);

if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO)
virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_VFIO);
else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN)
virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_XEN);
else
virPCIDeviceSetStubDriver(dev, VIR_PCI_STUB_DRIVER_KVM);

/* Setup the original states for the PCI device */
virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub);
virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot);
@@ -1558,18 +1583,14 @@ int
virHostdevPCINodeDeviceDetach(virHostdevManagerPtr hostdev_mgr,
virPCIDevicePtr pci)
{
virPCIDeviceAddressPtr devAddr = NULL;
struct virHostdevIsPCINodeDeviceUsedData data = { hostdev_mgr, NULL,
false };
int ret = -1;

virObjectLock(hostdev_mgr->activePCIHostdevs);
virObjectLock(hostdev_mgr->inactivePCIHostdevs);

if (!(devAddr = virPCIDeviceGetAddress(pci)))
goto out;

if (virHostdevIsPCINodeDeviceUsed(devAddr, &data))
if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
goto out;

if (virPCIDeviceDetach(pci, hostdev_mgr->activePCIHostdevs,
@@ -1581,26 +1602,21 @@ virHostdevPCINodeDeviceDetach(virHostdevManagerPtr hostdev_mgr,
out:
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
VIR_FREE(devAddr);
return ret;
}

int
virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr,
virPCIDevicePtr pci)
{
virPCIDeviceAddressPtr devAddr = NULL;
struct virHostdevIsPCINodeDeviceUsedData data = {hostdev_mgr, NULL,
false};
int ret = -1;

virObjectLock(hostdev_mgr->activePCIHostdevs);
virObjectLock(hostdev_mgr->inactivePCIHostdevs);

if (!(devAddr = virPCIDeviceGetAddress(pci)))
goto out;

if (virHostdevIsPCINodeDeviceUsed(devAddr, &data))
if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
goto out;

virPCIDeviceReattachInit(pci);
@@ -1613,7 +1629,6 @@ virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr,
out:
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
VIR_FREE(devAddr);
return ret;
}

@@ -94,7 +94,7 @@ static int virLogNbFilters;
* after filtering, multiple output can be used simultaneously
*/
struct _virLogOutput {
bool logVersion;
bool logInitMessage;
void *data;
virLogOutputFunc f;
virLogCloseFunc c;
@@ -402,7 +402,7 @@ virLogDefineOutput(virLogOutputFunc f,
goto cleanup;
}
ret = virLogNbOutputs++;
virLogOutputs[ret].logVersion = true;
virLogOutputs[ret].logInitMessage = true;
virLogOutputs[ret].f = f;
virLogOutputs[ret].c = c;
virLogOutputs[ret].data = data;
@@ -452,6 +452,33 @@ virLogVersionString(const char **rawmsg,
return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, VIR_LOG_VERSION_STRING);
}

/* Similar to virGetHostname() but avoids use of error
* reporting APIs or logging APIs, to prevent recursion
*/
static int
virLogHostnameString(char **rawmsg,
char **msg)
{
char *hostname = virGetHostnameQuiet();
char *hoststr;

if (!hostname)
return -1;

if (virAsprintfQuiet(&hoststr, "hostname: %s", hostname) < 0) {
VIR_FREE(hostname);
return -1;
}
VIR_FREE(hostname);

if (virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, hoststr) < 0) {
VIR_FREE(hoststr);
return -1;
}
*rawmsg = hoststr;
return 0;
}


static void
virLogSourceUpdate(virLogSourcePtr source)
@@ -533,7 +560,7 @@ virLogVMessage(virLogSourcePtr source,
const char *fmt,
va_list vargs)
{
static bool logVersionStderr = true;
static bool logInitMessageStderr = true;
char *str = NULL;
char *msg = NULL;
char timestamp[VIR_TIME_STRING_BUFLEN];
@@ -583,16 +610,24 @@ virLogVMessage(virLogSourcePtr source,
*/
for (i = 0; i < virLogNbOutputs; i++) {
if (priority >= virLogOutputs[i].priority) {
if (virLogOutputs[i].logVersion) {
const char *rawver;
char *ver = NULL;
if (virLogVersionString(&rawver, &ver) >= 0)
if (virLogOutputs[i].logInitMessage) {
const char *rawinitmsg;
char *hoststr = NULL;
char *initmsg = NULL;
if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
__FILE__, __LINE__, __func__,
timestamp, NULL, 0, rawinitmsg, initmsg,
virLogOutputs[i].data);
VIR_FREE(initmsg);
if (virLogHostnameString(&hoststr, &initmsg) >= 0)
virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
__FILE__, __LINE__, __func__,
timestamp, NULL, 0, rawver, ver,
timestamp, NULL, 0, hoststr, initmsg,
virLogOutputs[i].data);
VIR_FREE(ver);
virLogOutputs[i].logVersion = false;
VIR_FREE(hoststr);
VIR_FREE(initmsg);
virLogOutputs[i].logInitMessage = false;
}
virLogOutputs[i].f(source, priority,
filename, linenr, funcname,
@@ -601,16 +636,24 @@ virLogVMessage(virLogSourcePtr source,
}
}
if (virLogNbOutputs == 0) {
if (logVersionStderr) {
const char *rawver;
char *ver = NULL;
if (virLogVersionString(&rawver, &ver) >= 0)
if (logInitMessageStderr) {
const char *rawinitmsg;
char *hoststr = NULL;
char *initmsg = NULL;
if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
__FILE__, __LINE__, __func__,
timestamp, NULL, 0, rawinitmsg, initmsg,
(void *) STDERR_FILENO);
VIR_FREE(initmsg);
if (virLogHostnameString(&hoststr, &initmsg) >= 0)
virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
__FILE__, __LINE__, __func__,
timestamp, NULL, 0, rawver, ver,
timestamp, NULL, 0, hoststr, initmsg,
(void *) STDERR_FILENO);
VIR_FREE(ver);
logVersionStderr = false;
VIR_FREE(hoststr);
VIR_FREE(initmsg);
logInitMessageStderr = false;
}
virLogOutputToFd(source, priority,
filename, linenr, funcname,
@@ -256,9 +256,11 @@ int virNetDevSetMAC(const char *ifname,
virMacAddrGetRaw(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data);

if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0) {
char macstr[VIR_MAC_STRING_BUFLEN];

virReportSystemError(errno,
_("Cannot set interface MAC on '%s'"),
ifname);
_("Cannot set interface MAC to %s on '%s'"),
virMacAddrFormat(macaddr, macstr), ifname);
goto cleanup;
}

@@ -291,8 +293,8 @@ int virNetDevSetMAC(const char *ifname,

if (ioctl(s, SIOCSIFLLADDR, &ifr) < 0) {
virReportSystemError(errno,
_("Cannot set interface MAC on '%s'"),
ifname);
_("Cannot set interface MAC to %s on '%s'"),
mac + 1, ifname);
goto cleanup;
}

@@ -2270,10 +2272,17 @@ virNetDevSetVfConfig(const char *ifname, int ifindex, int vf,
goto malformed_resp;

if (err->error) {
char macstr[VIR_MAC_STRING_BUFLEN];

virReportSystemError(-err->error,
_("error during set %s of ifindex %d"),
(macaddr ? (vlanid >= 0 ? "mac/vlan" : "mac") : "vlanid"),
ifindex);
_("Cannot set interface MAC/vlanid to %s/%d "
"for ifname %s ifindex %d vf %d"),
(macaddr
? virMacAddrFormat(macaddr, macstr)
: "(unchanged)"),
vlanid,
ifname ? ifname : "(unspecified)",
ifindex, vf);
goto cleanup;
}
break;