Exemplo n.º 1
0
static int
virLockManagerSanlockRegisterKillscript(int sock,
                                        const char *vmuri,
                                        const char *uuidstr,
                                        virDomainLockFailureAction action)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *path;
    char *args = NULL;
    int ret = -1;
    int rv;

    if (action > VIR_DOMAIN_LOCK_FAILURE_IGNORE) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Failure action %s is not supported by sanlock"),
                       virDomainLockFailureTypeToString(action));
        goto cleanup;
    }

    virBufferEscape(&buf, '\\', "\\ ", "%s", vmuri);
    virBufferAddLit(&buf, " ");
    virBufferEscape(&buf, '\\', "\\ ", "%s", uuidstr);
    virBufferAddLit(&buf, " ");
    virBufferEscape(&buf, '\\', "\\ ", "%s",
                    virDomainLockFailureTypeToString(action));

    if (virBufferError(&buf)) {
        virBufferFreeAndReset(&buf);
        virReportOOMError();
        goto cleanup;
    }

    /* Unfortunately, sanlock_killpath() does not use const for either
     * path or args even though it will just copy them into its own
     * buffers.
     */
    path = (char *) VIR_LOCK_MANAGER_SANLOCK_KILLPATH;
    args = virBufferContentAndReset(&buf);

    VIR_DEBUG("Register sanlock killpath: %s %s", path, args);

    /* sanlock_killpath() would just crop the strings */
    if (strlen(path) >= SANLK_HELPER_PATH_LEN) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Sanlock helper path is longer than %d: '%s'"),
                       SANLK_HELPER_PATH_LEN - 1, path);
        goto cleanup;
    }
    if (strlen(args) >= SANLK_HELPER_ARGS_LEN) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Sanlock helper arguments are longer than %d:"
                         " '%s'"),
                       SANLK_HELPER_ARGS_LEN - 1, args);
        goto cleanup;
    }

    if ((rv = sanlock_killpath(sock, 0, path, args)) < 0) {
        if (rv <= -200) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to register lock failure action:"
                             " error %d"), rv);
        } else {
            virReportSystemError(-rv, "%s",
                                 _("Failed to register lock failure"
                                   " action"));
        }
        goto cleanup;
    }

    ret = 0;

cleanup:
    VIR_FREE(args);
    return ret;
}
Exemplo n.º 2
0
static int
SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
                        virDomainDefPtr def)
{
    int rc = -1;
    char *mcs = NULL;
    char *scontext = NULL;
    int c1 = 0;
    int c2 = 0;
    context_t ctx = NULL;
    const char *range;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr));
    if ((def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) &&
        !def->seclabel.baselabel &&
        def->seclabel.model) {
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("security model already defined for VM"));
        return rc;
    }

    if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        def->seclabel.label) {
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("security label already defined for VM"));
        return rc;
    }

    if (def->seclabel.imagelabel) {
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("security image label already defined for VM"));
        return rc;
    }

    if (def->seclabel.model &&
        STRNEQ(def->seclabel.model, SECURITY_SELINUX_NAME)) {
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                               _("security label model %s is not supported with selinux"),
                               def->seclabel.model);
        return rc;
    }

    VIR_DEBUG("SELinuxGenSecurityLabel %d", def->seclabel.type);

    switch (def->seclabel.type) {
    case VIR_DOMAIN_SECLABEL_STATIC:
        if (!(ctx = context_new(def->seclabel.label)) ) {
            virReportSystemError(errno,
                                 _("unable to allocate socket security context '%s'"),
                                 def->seclabel.label);
            return rc;
        }

        range = context_range_get(ctx);
        if (!range ||
            !(mcs = strdup(range))) {
            virReportOOMError();
            goto cleanup;
        }
        break;

    case VIR_DOMAIN_SECLABEL_DYNAMIC:
        do {
            c1 = virRandomBits(10);
            c2 = virRandomBits(10);

            if ( c1 == c2 ) {
                if (virAsprintf(&mcs, "s0:c%d", c1) < 0) {
                    virReportOOMError();
                    goto cleanup;
                }
            } else {
                if (c1 > c2) {
                    c1 ^= c2;
                    c2 ^= c1;
                    c1 ^= c2;
                }
                if (virAsprintf(&mcs, "s0:c%d,c%d", c1, c2) < 0) {
                    virReportOOMError();
                    goto cleanup;
                }
            }
        } while (mcsAdd(mcs) == -1);

        def->seclabel.label =
            SELinuxGenNewContext(def->seclabel.baselabel ?
                                 def->seclabel.baselabel :
                                 data->domain_context, mcs);
        if (! def->seclabel.label)  {
            virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot generate selinux context for %s"), mcs);
            goto cleanup;
        }
        break;

    case VIR_DOMAIN_SECLABEL_NONE:
        /* no op */
        break;

    default:
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected security label type '%s'"),
                               virDomainSeclabelTypeToString(def->seclabel.type));
        goto cleanup;
    }

    if (!def->seclabel.norelabel) {
        def->seclabel.imagelabel = SELinuxGenNewContext(data->file_context, mcs);
        if (!def->seclabel.imagelabel)  {
            virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("cannot generate selinux context for %s"), mcs);
            goto cleanup;
        }
    }

    if (!def->seclabel.model &&
        !(def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) {
        virReportOOMError();
        goto cleanup;
    }

    rc = 0;

cleanup:
    if (rc != 0) {
        if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)
            VIR_FREE(def->seclabel.label);
        VIR_FREE(def->seclabel.imagelabel);
        if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
            !def->seclabel.baselabel)
            VIR_FREE(def->seclabel.model);
    }

    if (ctx)
        context_free(ctx);
    VIR_FREE(scontext);
    VIR_FREE(mcs);

    VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s",
              NULLSTR(def->seclabel.model),
              NULLSTR(def->seclabel.label),
              NULLSTR(def->seclabel.imagelabel),
              NULLSTR(def->seclabel.baselabel));

    return rc;
}
Exemplo n.º 3
0
virNodeParseNode(const char *node,
                 int *sockets,
                 int *cores,
                 int *threads,
                 int *offline)
{
    int ret = -1;
    int processors = 0;
    DIR *cpudir = NULL;
    struct dirent *cpudirent = NULL;
    int sock_max = 0;
    cpu_set_t sock_map;
    int sock;
    cpu_set_t *core_maps = NULL;
    int core;
    size_t i;
    int siblings;
    unsigned int cpu;
    int online;

    *threads = 0;
    *cores = 0;
    *sockets = 0;

    if (!(cpudir = opendir(node))) {
        virReportSystemError(errno, _("cannot opendir %s"), node);
        goto cleanup;
    }

    /* enumerate sockets in the node */
    CPU_ZERO(&sock_map);
    errno = 0;
    while ((cpudirent = readdir(cpudir))) {
        if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
            continue;

        if ((online = virNodeGetCpuValue(node, cpu, "online", 1)) < 0)
            goto cleanup;

        if (!online)
            continue;

        /* Parse socket */
        if ((sock = virNodeParseSocket(node, cpu)) < 0)
            goto cleanup;
        CPU_SET(sock, &sock_map);

        if (sock > sock_max)
            sock_max = sock;

        errno = 0;
    }

    if (errno) {
        virReportSystemError(errno, _("problem reading %s"), node);
        goto cleanup;
    }

    sock_max++;

    /* allocate cpu maps for each socket */
    if (VIR_ALLOC_N(core_maps, sock_max) < 0)
        goto cleanup;

    for (i = 0; i < sock_max; i++)
        CPU_ZERO(&core_maps[i]);

    /* iterate over all CPU's in the node */
    rewinddir(cpudir);
    errno = 0;
    while ((cpudirent = readdir(cpudir))) {
        if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
            continue;

        if ((online = virNodeGetCpuValue(node, cpu, "online", 1)) < 0)
            goto cleanup;

        if (!online) {
            (*offline)++;
            continue;
        }

        processors++;

        /* Parse socket */
        if ((sock = virNodeParseSocket(node, cpu)) < 0)
            goto cleanup;
        if (!CPU_ISSET(sock, &sock_map)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("CPU socket topology has changed"));
            goto cleanup;
        }

        /* Parse core */
# if defined(__s390__) || \
    defined(__s390x__)
        /* logical cpu is equivalent to a core on s390 */
        core = cpu;
# else
        core = virNodeGetCpuValue(node, cpu, "topology/core_id", 0);
# endif

        CPU_SET(core, &core_maps[sock]);

        if (!(siblings = virNodeCountThreadSiblings(node, cpu)))
            goto cleanup;

        if (siblings > *threads)
            *threads = siblings;

        errno = 0;
    }

    if (errno) {
        virReportSystemError(errno, _("problem reading %s"), node);
        goto cleanup;
    }

    /* finalize the returned data */
    *sockets = CPU_COUNT(&sock_map);

    for (i = 0; i < sock_max; i++) {
        if (!CPU_ISSET(i, &sock_map))
            continue;

        core = CPU_COUNT(&core_maps[i]);
        if (core > *cores)
            *cores = core;
    }

    ret = processors;

cleanup:
    /* don't shadow a more serious error */
    if (cpudir && closedir(cpudir) < 0 && ret >= 0) {
        virReportSystemError(errno, _("problem closing %s"), node);
        ret = -1;
    }
    VIR_FREE(core_maps);

    return ret;
}
Exemplo n.º 4
0
/*
 * Try to kill the process and verify it has exited
 *
 * Returns 0 if it was killed gracefully, 1 if it
 * was killed forcibly, -1 if it is still alive,
 * or another error occurred.
 *
 * Callers can proide an extra delay in seconds to
 * wait longer than the default.
 */
int
virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay)
{
    size_t i;
    int ret = -1;
    /* This is in 1/5th seconds since polling is on a 0.2s interval */
    unsigned int polldelay = (force ? 200 : 75) + (extradelay*5);
    const char *signame = "TERM";

    VIR_DEBUG("vpid=%lld force=%d extradelay=%u",
              (long long)pid, force, extradelay);

    /* This loop sends SIGTERM, then waits a few iterations (10 seconds)
     * to see if it dies. If the process still hasn't exited, and
     * @force is requested, a SIGKILL will be sent, and this will
     * wait up to 30 seconds more for the process to exit before
     * returning.
     *
     * An extra delay can be passed by the caller for cases that are
     * expected to clean up slower than usual.
     *
     * Note that setting @force could result in dataloss for the process.
     */
    for (i = 0; i < polldelay; i++) {
        int signum;
        if (i == 0) {
            signum = SIGTERM; /* kindly suggest it should exit */
        } else if (i == 50 && force) {
            VIR_DEBUG("Timed out waiting after SIGTERM to process %lld, "
                      "sending SIGKILL", (long long)pid);
            /* No SIGKILL kill on Win32 ! Use SIGABRT instead which our
             * virProcessKill proc will handle more or less like SIGKILL */
#ifdef WIN32
            signum = SIGABRT; /* kill it after a grace period */
            signame = "ABRT";
#else
            signum = SIGKILL; /* kill it after a grace period */
            signame = "KILL";
#endif
        } else {
            signum = 0; /* Just check for existence */
        }

        if (virProcessKill(pid, signum) < 0) {
            if (errno != ESRCH) {
                virReportSystemError(errno,
                                     _("Failed to terminate process %lld with SIG%s"),
                                     (long long)pid, signame);
                goto cleanup;
            }
            ret = signum == SIGTERM ? 0 : 1;
            goto cleanup; /* process is dead */
        }

        usleep(200 * 1000);
    }

    virReportSystemError(EBUSY,
                         _("Failed to terminate process %lld with SIG%s"),
                         (long long)pid, signame);

 cleanup:
    return ret;
}
Exemplo n.º 5
0
int virNetDevExists(const char *ifname)
{
    virReportSystemError(ENOSYS,
                         _("Unable to check interface %s"), ifname);
    return -1;
}
Exemplo n.º 6
0
/*
 * qemuTPMEmulatorPrepareHost:
 *
 * @tpm: tpm definition
 * @logDir: directory where swtpm writes its logs into
 * @vmname: name of the VM
 * @swtpm_user: uid to run the swtpm with
 * @swtpm_group: gid to run the swtpm with
 * @swtpmStateDir: directory for swtpm's persistent state
 * @qemu_user: uid that qemu will run with; we share the socket file with it
 * @shortName: short and unique name of the domain
 *
 * Prepare the log directory for the swtpm and adjust ownership of it and the
 * log file we will be using. Prepare the state directory where we will share
 * the socket between tss and qemu users.
 */
static int
qemuTPMEmulatorPrepareHost(virDomainTPMDefPtr tpm,
                           const char *logDir,
                           const char *vmname,
                           uid_t swtpm_user,
                           gid_t swtpm_group,
                           const char *swtpmStateDir,
                           uid_t qemu_user,
                           const char *shortName)
{
    int ret = -1;

    if (qemuTPMEmulatorInit() < 0)
        return -1;

    /* create log dir ... allow 'tss' user to cd into it */
    if (virFileMakePathWithMode(logDir, 0711) < 0)
        return -1;

    /* ... and adjust ownership */
    if (virDirCreate(logDir, 0730, swtpm_user, swtpm_group,
                     VIR_DIR_CREATE_ALLOW_EXIST) < 0)
        goto cleanup;

    /* create logfile name ... */
    if (!tpm->data.emulator.logfile &&
        virAsprintf(&tpm->data.emulator.logfile, "%s/%s-swtpm.log",
                    logDir, vmname) < 0)
        goto cleanup;

    /* ... and make sure it can be accessed by swtpm_user */
    if (virFileExists(tpm->data.emulator.logfile) &&
        chown(tpm->data.emulator.logfile, swtpm_user, swtpm_group) < 0) {
        virReportSystemError(errno,
                             _("Could not chown on swtpm logfile %s"),
                             tpm->data.emulator.logfile);
        goto cleanup;
    }

    /*
      create our swtpm state dir ...
      - QEMU user needs to be able to access the socket there
      - swtpm group needs to be able to create files there
      - in privileged mode 0570 would be enough, for non-privileged mode
        we need 0770
    */
    if (virDirCreate(swtpmStateDir, 0770, qemu_user, swtpm_group,
                     VIR_DIR_CREATE_ALLOW_EXIST) < 0)
        goto cleanup;

    /* create the socket filename */
    if (!tpm->data.emulator.source.data.nix.path &&
        !(tpm->data.emulator.source.data.nix.path =
          qemuTPMCreateEmulatorSocket(swtpmStateDir, shortName)))
        goto cleanup;
    tpm->data.emulator.source.type = VIR_DOMAIN_CHR_TYPE_UNIX;

    ret = 0;

 cleanup:

    return ret;
}
Exemplo n.º 7
0
static char *
umlBuildCommandLineChr(virDomainChrDefPtr def,
                       const char *dev,
                       virCommandPtr cmd)
{
    char *ret = NULL;

    switch (def->source.type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
        if (virAsprintf(&ret, "%s%d=null", dev, def->target.port) < 0)
            return NULL;
        break;

    case VIR_DOMAIN_CHR_TYPE_PTY:
        if (virAsprintf(&ret, "%s%d=pts", dev, def->target.port) < 0)
            return NULL;
        break;

    case VIR_DOMAIN_CHR_TYPE_DEV:
        if (virAsprintf(&ret, "%s%d=tty:%s", dev, def->target.port,
                        def->source.data.file.path) < 0)
            return NULL;
        break;

    case VIR_DOMAIN_CHR_TYPE_STDIO:
        if (virAsprintf(&ret, "%s%d=fd:0,fd:1", dev, def->target.port) < 0)
            return NULL;
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
        if (def->source.data.tcp.listen != 1) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("only TCP listen is supported for chr device"));
            return NULL;
        }

        if (virAsprintf(&ret, "%s%d=port:%s", dev, def->target.port,
                        def->source.data.tcp.service) < 0)
            return NULL;
        break;

    case VIR_DOMAIN_CHR_TYPE_FILE:
         {
            int fd_out;

            if ((fd_out = open(def->source.data.file.path,
                               O_WRONLY | O_APPEND | O_CREAT, 0660)) < 0) {
                virReportSystemError(errno,
                                     _("failed to open chardev file: %s"),
                                     def->source.data.file.path);
                return NULL;
            }
            if (virAsprintf(&ret, "%s%d=null,fd:%d", dev, def->target.port, fd_out) < 0) {
                VIR_FORCE_CLOSE(fd_out);
                return NULL;
            }
            virCommandPassFD(cmd, fd_out,
                             VIR_COMMAND_PASS_FD_CLOSE_PARENT);
        }
        break;
   case VIR_DOMAIN_CHR_TYPE_PIPE:
        /* XXX could open the pipe & just pass the FDs. Be wary of
         * the effects of blocking I/O, though. */

    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_UDP:
    case VIR_DOMAIN_CHR_TYPE_UNIX:
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported chr device type %d"), def->source.type);
        break;
    }

    return ret;
}
Exemplo n.º 8
0
int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
                             const char *sysfs_dir,
                             virNodeInfoPtr nodeinfo)
{
    char line[1024];
    DIR *cpudir = NULL;
    struct dirent *cpudirent = NULL;
    unsigned int cpu;
    unsigned long core, sock, cur_threads;
    cpu_set_t core_mask;
    cpu_set_t socket_mask;
    int online;
    int ret = -1;
    char *sysfs_cpudir = NULL;
    unsigned int cpu_cores = 0;

    nodeinfo->cpus = 0;
    nodeinfo->mhz = 0;
    nodeinfo->cores = 0;

    /* Start with parsing /proc/cpuinfo; although it tends to have
     * fewer details.  Hyperthreads are ignored at this stage.  */
    while (fgets(line, sizeof(line), cpuinfo) != NULL) {
# if defined(__x86_64__) || \
    defined(__amd64__)  || \
    defined(__i386__)
        char *buf = line;
        if (STRPREFIX(buf, "cpu MHz")) {
            char *p;
            unsigned int ui;

            buf += 9;
            while (*buf && c_isspace(*buf))
                buf++;

            if (*buf != ':' || !buf[1]) {
                nodeReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("parsing cpu MHz from cpuinfo"));
                goto cleanup;
            }

            if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0
                /* Accept trailing fractional part.  */
                && (*p == '\0' || *p == '.' || c_isspace(*p)))
                nodeinfo->mhz = ui;
        }

        if (STRPREFIX(buf, "cpu cores")) {
            char *p;
            unsigned int ui;

            buf += 9;
            while (*buf && c_isspace(*buf))
                buf++;

            if (*buf != ':' || !buf[1]) {
                nodeReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("parsing cpu cores from cpuinfo"));
                return -1;
            }

            if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0
                && (*p == '\0' || c_isspace(*p)))
                cpu_cores = ui;
         }
# elif defined(__powerpc__) || \
      defined(__powerpc64__)
        char *buf = line;
        if (STRPREFIX(buf, "clock")) {
            char *p;
            unsigned int ui;

            buf += 5;
            while (*buf && c_isspace(*buf))
                buf++;

            if (*buf != ':' || !buf[1]) {
                nodeReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("parsing cpu MHz from cpuinfo"));
                goto cleanup;
            }

            if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0
                /* Accept trailing fractional part.  */
                && (*p == '\0' || *p == '.' || c_isspace(*p)))
                nodeinfo->mhz = ui;
            /* No other interesting infos are available in /proc/cpuinfo.
             * However, there is a line identifying processor's version,
             * identification and machine, but we don't want it to be caught
             * and parsed in next iteration, because it is not in expected
             * format and thus lead to error. */
        }
# else
#  warning Parser for /proc/cpuinfo needs to be adapted for your architecture
# endif
    }

    /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the
     * core, node, socket, thread and topology information from /sys
     */
    if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_dir) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    cpudir = opendir(sysfs_cpudir);
    if (cpudir == NULL) {
        virReportSystemError(errno, _("cannot opendir %s"), sysfs_cpudir);
        goto cleanup;
    }

    CPU_ZERO(&core_mask);
    CPU_ZERO(&socket_mask);

    while ((cpudirent = readdir(cpudir))) {
        if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
            continue;

        online = virNodeGetCpuValue(sysfs_cpudir, cpu, "online", true);
        if (online < 0) {
            closedir(cpudir);
            goto cleanup;
        }
        if (!online)
            continue;
        nodeinfo->cpus++;

        /* Parse core */
        core = virNodeGetCpuValue(sysfs_cpudir, cpu, "topology/core_id", false);
        if (!CPU_ISSET(core, &core_mask)) {
            CPU_SET(core, &core_mask);
            nodeinfo->cores++;
        }

        /* Parse socket */
        sock = virNodeParseSocket(sysfs_cpudir, cpu);
        if (!CPU_ISSET(sock, &socket_mask)) {
            CPU_SET(sock, &socket_mask);
            nodeinfo->sockets++;
        }

        cur_threads = virNodeCountThreadSiblings(sysfs_cpudir, cpu);
        if (cur_threads == 0) {
            closedir(cpudir);
            goto cleanup;
        }
        if (cur_threads > nodeinfo->threads)
            nodeinfo->threads = cur_threads;
    }
    if (errno) {
        virReportSystemError(errno,
                             _("problem reading %s"), sysfs_cpudir);
        closedir(cpudir);
        goto cleanup;
    }
    if (closedir(cpudir) < 0) {
        virReportSystemError(errno,
                             _("problem closing %s"), sysfs_cpudir);
        goto cleanup;
    }

    if ((nodeinfo->nodes = virNodeParseNode(sysfs_dir)) <= 0)
        goto cleanup;

    /* There should always be at least one cpu, socket, node, and thread. */
    if (nodeinfo->cpus == 0) {
        nodeReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no CPUs found"));
        goto cleanup;
    }
    if (nodeinfo->sockets == 0) {
        nodeReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no sockets found"));
        goto cleanup;
    }
    if (nodeinfo->threads == 0) {
        nodeReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("no threads found"));
        goto cleanup;
    }

    /* Platform like AMD Magny Cours has two NUMA nodes each package, and
     * the two nodes share the same core ID set, it results in the cores
     * number calculated from sysfs is not the actual cores number. Use
     * "cpu cores" in /proc/cpuinfo as the cores number instead in this case.
     * More details about the problem:
     * https://www.redhat.com/archives/libvir-list/2012-May/msg00607.html
     */
    if (cpu_cores && (cpu_cores > nodeinfo->cores))
        nodeinfo->cores = cpu_cores;

    /* nodeinfo->sockets is supposed to be a number of sockets per NUMA node,
     * however if NUMA nodes are not composed of whole sockets, we just lie
     * about the number of NUMA nodes and force apps to check capabilities XML
     * for the actual NUMA topology.
     */
    if (nodeinfo->sockets % nodeinfo->nodes == 0)
        nodeinfo->sockets /= nodeinfo->nodes;
    else
        nodeinfo->nodes = 1;

    ret = 0;

cleanup:
    VIR_FREE(sysfs_cpudir);
    return ret;
}
Exemplo n.º 9
0
static char*
virBhyveTapGetRealDeviceName(char *name)
{
    /* This is an ugly hack, because if we rename
     * tap device to vnet%d, its device name will be
     * still /dev/tap%d, and bhyve tries to open /dev/tap%d,
     * so we have to find the real name
     */
    char *ret = NULL;
    struct dirent *dp;
    char *devpath = NULL;
    int fd;

    DIR *dirp = opendir("/dev");
    if (dirp == NULL) {
        virReportSystemError(errno,
                             _("Failed to opendir path '%s'"),
                             "/dev");
        return NULL;
    }

    while ((dp = readdir(dirp)) != NULL) {
        if (STRPREFIX(dp->d_name, "tap")) {
            struct ifreq ifr;
            if (virAsprintf(&devpath, "/dev/%s", dp->d_name) < 0) {
                goto cleanup;
            }
            if ((fd = open(devpath, O_RDWR)) < 0) {
                virReportSystemError(errno, _("Unable to open '%s'"), devpath);
                goto cleanup;
            }

            if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) {
                virReportSystemError(errno, "%s",
                                     _("Unable to query tap interface name"));
                goto cleanup;
            }

            if (STREQ(name, ifr.ifr_name)) {
                /* we can ignore the return value
                 * because we still have nothing
                 * to do but return;
                 */
                ignore_value(VIR_STRDUP(ret, dp->d_name));
                goto cleanup;
            }

            VIR_FREE(devpath);
            VIR_FORCE_CLOSE(fd);
        }

        errno = 0;
    }

    if (errno != 0)
        virReportSystemError(errno, "%s",
                             _("Unable to iterate over TAP devices"));

cleanup:
    VIR_FREE(devpath);
    VIR_FORCE_CLOSE(fd);
    closedir(dirp);
    return ret;
}
Exemplo n.º 10
0
/**
 * xenInotifyOpen:
 * @conn: pointer to the connection block
 * @name: URL for the target, NULL for local
 * @flags: combination of virDrvOpenFlag(s)
 *
 * Connects and starts listening for inotify events
 *
 * Returns 0 or -1 in case of error.
 */
virDrvOpenStatus
xenInotifyOpen(virConnectPtr conn,
               virConnectAuthPtr auth ATTRIBUTE_UNUSED,
               unsigned int flags)
{
    DIR *dh;
    struct dirent *ent;
    char *path;
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;

    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

    if (priv->configDir) {
        priv->useXenConfigCache = 1;
    } else {
        /* /var/lib/xend/domains/<uuid>/config.sxp */
        priv->configDir = XEND_DOMAINS_DIR;
        priv->useXenConfigCache = 0;

        if (VIR_ALLOC(priv->configInfoList) < 0) {
            virReportOOMError();
            return -1;
        }

        /* populate initial list */
        if (!(dh = opendir(priv->configDir))) {
            virReportSystemError(errno,
                                 _("cannot open directory: %s"),
                                 priv->configDir);
            return -1;
        }
        while ((ent = readdir(dh))) {
            if (STRPREFIX(ent->d_name, "."))
                continue;

            /* Build the full file path */
            if (!(path = virFileBuildPath(priv->configDir, ent->d_name, NULL))) {
                closedir(dh);
                return -1;
            }

            if (xenInotifyAddDomainConfigInfo(conn, path) < 0 ) {
                virXenInotifyError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("Error adding file to config list"));
                closedir(dh);
                VIR_FREE(path);
                return -1;
            }

            VIR_FREE(path);
        }
        closedir(dh);
    }

    if ((priv->inotifyFD = inotify_init()) < 0) {
        virReportSystemError(errno,
                             "%s", _("initializing inotify"));
        return -1;
    }

    VIR_DEBUG("Adding a watch on %s", priv->configDir);
    if (inotify_add_watch(priv->inotifyFD,
                          priv->configDir,
                          IN_CREATE |
                          IN_CLOSE_WRITE | IN_DELETE |
                          IN_MOVED_TO | IN_MOVED_FROM) < 0) {
        virReportSystemError(errno,
                             _("adding watch on %s"),
                             priv->configDir);
        return -1;
    }

    VIR_DEBUG("Building initial config cache");
    if (priv->useXenConfigCache &&
        xenXMConfigCacheRefresh (conn) < 0) {
        VIR_DEBUG("Failed to enable XM config cache %s", conn->err.message);
        return -1;
    }

    VIR_DEBUG("Registering with event loop");
    /* Add the handle for monitoring */
    if ((priv->inotifyWatch = virEventAddHandle(priv->inotifyFD, VIR_EVENT_HANDLE_READABLE,
                                                xenInotifyEvent, conn, NULL)) < 0) {
        VIR_DEBUG("Failed to add inotify handle, disabling events");
    }

    return 0;
}
Exemplo n.º 11
0
virLockManagerPluginPtr virLockManagerPluginNew(const char *name,
                                                const char *driverName,
                                                const char *configDir,
                                                unsigned int flags)
{
    void *handle = NULL;
    virLockDriverPtr driver;
    virLockManagerPluginPtr plugin = NULL;
    char *modfile = NULL;
    char *configFile = NULL;

    VIR_DEBUG("name=%s driverName=%s configDir=%s flags=0x%x",
              name, driverName, configDir, flags);

    if (virAsprintf(&configFile, "%s/%s-%s.conf",
                    configDir, driverName, name) < 0)
        return NULL;

    if (STREQ(name, "nop")) {
        driver = &virLockDriverNop;
    } else {
        if (!(modfile = virFileFindResourceFull(name,
                                                NULL,
                                                ".so",
                                                abs_top_builddir "/src/.libs",
                                                LIBDIR "/libvirt/lock-driver",
                                                "LIBVIRT_LOCK_MANAGER_PLUGIN_DIR")))
            goto cleanup;

        VIR_DEBUG("Module load %s from %s", name, modfile);

        if (access(modfile, R_OK) < 0) {
            virReportSystemError(errno,
                                 _("Plugin %s not accessible"),
                                 modfile);
            goto cleanup;
        }

        handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL);
        if (!handle) {
            virReportError(VIR_ERR_SYSTEM_ERROR,
                           _("Failed to load plugin %s: %s"),
                           modfile, dlerror());
            goto cleanup;
        }

        if (!(driver = dlsym(handle, "virLockDriverImpl"))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Missing plugin initialization symbol 'virLockDriverImpl'"));
            goto cleanup;
        }
    }

    if (driver->drvInit(VIR_LOCK_MANAGER_VERSION, configFile, flags) < 0)
        goto cleanup;

    if (VIR_ALLOC(plugin) < 0)
        goto cleanup;

    plugin->driver = driver;
    plugin->handle = handle;
    plugin->refs = 1;
    if (VIR_STRDUP(plugin->name, name) < 0)
        goto cleanup;

    VIR_FREE(configFile);
    VIR_FREE(modfile);
    return plugin;

 cleanup:
    VIR_FREE(configFile);
    VIR_FREE(plugin);
    VIR_FREE(modfile);
    if (handle)
        dlclose(handle);
    return NULL;
}
Exemplo n.º 12
0
qemuMonitorTestPtr qemuMonitorTestNew(bool json, virCapsPtr caps)
{
    qemuMonitorTestPtr test = NULL;
    virDomainChrSourceDef src;
    char *path = NULL;
    char *tmpdir_template = NULL;

    if (VIR_ALLOC(test) < 0)
        goto no_memory;

    if (virMutexInit(&test->lock) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       "Cannot initialize mutex");
        VIR_FREE(test);
        return NULL;
    }

    if (!(tmpdir_template = strdup("/tmp/libvirt_XXXXXX")))
        goto no_memory;

    if (!(test->tmpdir = mkdtemp(tmpdir_template))) {
        virReportSystemError(errno, "%s",
                             "Failed to create temporary directory");
        goto error;
    }

    tmpdir_template = NULL;

    if (virAsprintf(&path, "%s/qemumonitorjsontest.sock", test->tmpdir) < 0)
        goto no_memory;

    test->json = json;
    if (!(test->vm = virDomainObjNew(caps)))
        goto error;

    if (virNetSocketNewListenUNIX(path,
                                  0700,
                                  getuid(),
                                  getgid(),
                                  &test->server) < 0)
        goto error;

    memset(&src, 0, sizeof(src));
    src.type = VIR_DOMAIN_CHR_TYPE_UNIX;
    src.data.nix.path = (char *)path;
    src.data.nix.listen = false;

    if (virNetSocketListen(test->server, 1) < 0)
        goto error;

    if (!(test->mon = qemuMonitorOpen(test->vm,
                                      &src,
                                      json ? 1 : 0,
                                      &qemuCallbacks)))
        goto error;
    qemuMonitorLock(test->mon);

    if (virNetSocketAccept(test->server, &test->client) < 0)
        goto error;
    if (!test->client)
        goto error;

    if (qemuMonitorTestAddReponse(test, json ?
                                  QEMU_JSON_GREETING :
                                  QEMU_TEXT_GREETING) < 0)
        goto error;

    if (virNetSocketAddIOCallback(test->client,
                                  VIR_EVENT_HANDLE_WRITABLE,
                                  qemuMonitorTestIO,
                                  test,
                                  NULL) < 0)
        goto error;

    virMutexLock(&test->lock);
    if (virThreadCreate(&test->thread,
                        true,
                        qemuMonitorTestWorker,
                        test) < 0) {
        virMutexUnlock(&test->lock);
        goto error;
    }
    test->running = true;
    virMutexUnlock(&test->lock);

cleanup:
    VIR_FREE(path);
    return test;

no_memory:
    virReportOOMError();

error:
    VIR_FREE(tmpdir_template);
    qemuMonitorTestFree(test);
    goto cleanup;
}
Exemplo n.º 13
0
/**
 * virDomainLxcEnterSecurityLabel:
 * @model: the security model to set
 * @label: the security label to apply
 * @oldlabel: filled with old security label
 * @flags: currently unused, pass 0
 *
 * This API is LXC specific, so it will only work with hypervisor
 * connections to the LXC driver.
 *
 * Attaches the process to the security label specified
 * by @label. @label is interpreted relative to @model
 * Depending on the security driver, this may
 * not take effect until the next call to exec().
 *
 * If @oldlabel is not NULL, it will be filled with info
 * about the current security label. This may let the
 * process be moved back to the previous label if no
 * exec() has yet been performed.
 *
 * Returns 0 on success, -1 on error
 */
int
virDomainLxcEnterSecurityLabel(virSecurityModelPtr model,
                               virSecurityLabelPtr label,
                               virSecurityLabelPtr oldlabel,
                               unsigned int flags)
{
    virCheckFlagsGoto(0, error);

    virCheckNonNullArgGoto(model, error);
    virCheckNonNullArgGoto(label, error);

    if (oldlabel)
        memset(oldlabel, 0, sizeof(*oldlabel));

    if (STREQ(model->model, "selinux")) {
#ifdef WITH_SELINUX
        if (oldlabel) {
            security_context_t ctx;

            if (getcon(&ctx) < 0) {
                virReportSystemError(errno,
                                     _("unable to get PID %d security context"),
                                     getpid());
                goto error;
            }

            if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("security label exceeds "
                                 "maximum length: %d"),
                               VIR_SECURITY_LABEL_BUFLEN - 1);
                freecon(ctx);
                goto error;
            }

            strcpy(oldlabel->label, (char *) ctx);
            freecon(ctx);

            if ((oldlabel->enforcing = security_getenforce()) < 0) {
                virReportSystemError(errno, "%s",
                                     _("error calling security_getenforce()"));
                goto error;
            }
        }

        if (setexeccon(label->label) < 0) {
            virReportSystemError(errno,
                            _("Cannot set context %s"),
                            label->label);
            goto error;
        }
#else
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Support for SELinux is not enabled"));
        goto error;
#endif
    } else {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                       _("Security model %s cannot be entered"),
                       model->model);
        goto error;
    }

    return 0;

error:
    virDispatchError(NULL);
    return -1;
}
Exemplo n.º 14
0
/*
 * sanlock plugin for the libvirt virLockManager API
 */
static int virLockManagerSanlockLoadConfig(const char *configFile)
{
    virConfPtr conf;
    virConfValuePtr p;
    char *tmp;

    if (access(configFile, R_OK) == -1) {
        if (errno != ENOENT) {
            virReportSystemError(errno,
                                 _("Unable to access config file %s"),
                                 configFile);
            return -1;
        }
        return 0;
    }

    if (!(conf = virConfReadFile(configFile, 0)))
        return -1;

#define CHECK_TYPE(name,typ) if (p && p->type != (typ)) {               \
        virReportError(VIR_ERR_INTERNAL_ERROR,                          \
                       "%s: %s: expected type " #typ,                   \
                       configFile, (name));                             \
        virConfFree(conf);                                              \
        return -1;                                                      \
    }

    p = virConfGetValue(conf, "auto_disk_leases");
    CHECK_TYPE("auto_disk_leases", VIR_CONF_LONG);
    if (p) driver->autoDiskLease = p->l;

    p = virConfGetValue(conf, "disk_lease_dir");
    CHECK_TYPE("disk_lease_dir", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->autoDiskLeasePath);
        if (!(driver->autoDiskLeasePath = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue(conf, "host_id");
    CHECK_TYPE("host_id", VIR_CONF_LONG);
    if (p) driver->hostID = p->l;

    p = virConfGetValue(conf, "require_lease_for_disks");
    CHECK_TYPE("require_lease_for_disks", VIR_CONF_LONG);
    if (p)
        driver->requireLeaseForDisks = p->l;
    else
        driver->requireLeaseForDisks = !driver->autoDiskLease;

    p = virConfGetValue(conf, "user");
    CHECK_TYPE("user", VIR_CONF_STRING);
    if (p) {
        if (!(tmp = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }

        if (virGetUserID(tmp, &driver->user) < 0) {
            VIR_FREE(tmp);
            virConfFree(conf);
            return -1;
        }
        VIR_FREE(tmp);
    }

    p = virConfGetValue(conf, "group");
    CHECK_TYPE("group", VIR_CONF_STRING);
    if (p) {
        if (!(tmp = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
        if (virGetGroupID(tmp, &driver->group) < 0) {
            VIR_FREE(tmp);
            virConfFree(conf);
            return -1;
        }
        VIR_FREE(tmp);
    }

    virConfFree(conf);
    return 0;
}
Exemplo n.º 15
0
int virNetSocketNewListenUNIX(const char *path,
                              mode_t mask,
                              uid_t user,
                              gid_t grp,
                              virNetSocketPtr *retsock)
{
    virSocketAddr addr;
    mode_t oldmask;
    int fd;

    *retsock = NULL;

    memset(&addr, 0, sizeof(addr));

    addr.len = sizeof(addr.data.un);

    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
        virReportSystemError(errno, "%s", _("Failed to create socket"));
        goto error;
    }

    addr.data.un.sun_family = AF_UNIX;
    if (virStrcpyStatic(addr.data.un.sun_path, path) == NULL) {
        virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path);
        goto error;
    }
    if (addr.data.un.sun_path[0] == '@')
        addr.data.un.sun_path[0] = '\0';
    else
        unlink(addr.data.un.sun_path);

    oldmask = umask(~mask);

    if (bind(fd, &addr.data.sa, addr.len) < 0) {
        umask(oldmask);
        virReportSystemError(errno,
                             _("Failed to bind socket to '%s'"),
                             path);
        goto error;
    }
    umask(oldmask);

    /* chown() doesn't work for abstract sockets but we use them only
     * if libvirtd runs unprivileged
     */
    if (grp != 0 && chown(path, user, grp)) {
        virReportSystemError(errno,
                             _("Failed to change ownership of '%s' to %d:%d"),
                             path, (int) user, (int) grp);
        goto error;
    }

    if (!(*retsock = virNetSocketNew(&addr, NULL, false, fd, -1, 0)))
        goto error;

    return 0;

error:
    if (path[0] != '@')
        unlink(path);
    VIR_FORCE_CLOSE(fd);
    return -1;
}
Exemplo n.º 16
0
virStorageBackendProbeTarget(virStorageSourcePtr target,
                             char **backingStore,
                             int *backingStoreFormat,
                             virStorageEncryptionPtr *encryption)
{
    int fd = -1;
    int ret = -1;
    virStorageFileMetadata *meta = NULL;
    struct stat sb;
    char *header = NULL;
    ssize_t len = VIR_STORAGE_MAX_HEADER;

    *backingStore = NULL;
    *backingStoreFormat = VIR_STORAGE_FILE_AUTO;
    if (encryption)
        *encryption = NULL;

    if ((ret = virStorageBackendVolOpen(target->path, &sb,
                                        VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0)
        goto error; /* Take care to propagate ret, it is not always -1 */
    fd = ret;

    if ((ret = virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb)) < 0) {
        goto error;
    }

    if (S_ISDIR(sb.st_mode)) {
        target->format = VIR_STORAGE_FILE_DIR;
    } else {
        if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) {
            virReportSystemError(errno, _("cannot read header '%s'"),
                                 target->path);
            goto error;
        }

        target->format = virStorageFileProbeFormatFromBuf(target->path,
                                                          header, len);
        if (target->format < 0) {
            ret = -1;
            goto error;
        }

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

    VIR_FORCE_CLOSE(fd);

    if (meta && meta->backingStore) {
        *backingStore = meta->backingStore;
        meta->backingStore = NULL;
        if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO &&
            meta->backingStoreIsFile) {
            if ((ret = virStorageFileProbeFormat(*backingStore, -1, -1)) < 0) {
                /* If the backing file is currently unavailable, only log an error,
                 * but continue. Returning -1 here would disable the whole storage
                 * pool, making it unavailable for even maintenance. */
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot probe backing volume format: %s"),
                               *backingStore);
                ret = -3;
            } else {
                *backingStoreFormat = ret;
                ret = 0;
            }
        } else {
            *backingStoreFormat = meta->backingStoreFormat;
            ret = 0;
        }
    } else {
        ret = 0;
    }

    if (meta && meta->capacity)
        target->capacity = meta->capacity;

    if (encryption && meta && meta->encryption) {
        *encryption = meta->encryption;
        meta->encryption = NULL;

        switch (target->format) {
        case VIR_STORAGE_FILE_QCOW:
        case VIR_STORAGE_FILE_QCOW2:
            (*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
            break;
        default:
            break;
        }

        /* XXX ideally we'd fill in secret UUID here
         * but we cannot guarantee 'conn' is non-NULL
         * at this point in time :-(  So we only fill
         * in secrets when someone first queries a vol
         */
    }

    virBitmapFree(target->features);
    if (meta) {
        target->features = meta->features;
        meta->features = NULL;
    }

    if (meta && meta->compat) {
        VIR_FREE(target->compat);
        target->compat = meta->compat;
        meta->compat = NULL;
    }

    goto cleanup;

 error:
    VIR_FORCE_CLOSE(fd);

 cleanup:
    virStorageFileFreeMetadata(meta);
    VIR_FREE(header);
    return ret;

}
Exemplo n.º 17
0
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;
}
Exemplo n.º 18
0
static virLockSpaceResourcePtr
virLockSpaceResourceNew(virLockSpacePtr lockspace,
                        const char *resname,
                        unsigned int flags,
                        pid_t owner)
{
    virLockSpaceResourcePtr res;
    bool shared = !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED);

    if (VIR_ALLOC(res) < 0)
        return NULL;

    res->fd = -1;
    res->flags = flags;

    if (VIR_STRDUP(res->name, resname) < 0)
        goto error;

    if (!(res->path = virLockSpaceGetResourcePath(lockspace, resname)))
        goto error;

    if (flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) {
        while (1) {
            struct stat a, b;
            if ((res->fd = open(res->path, O_RDWR|O_CREAT, 0600)) < 0) {
                virReportSystemError(errno,
                                     _("Unable to open/create resource %s"),
                                     res->path);
                goto error;
            }

            if (virSetCloseExec(res->fd) < 0) {
                virReportSystemError(errno,
                                     _("Failed to set close-on-exec flag '%s'"),
                                     res->path);
                goto error;
            }

            if (fstat(res->fd, &b) < 0) {
                virReportSystemError(errno,
                                     _("Unable to check status of pid file '%s'"),
                                     res->path);
                goto error;
            }

            if (virFileLock(res->fd, shared, 0, 1, false) < 0) {
                if (errno == EACCES || errno == EAGAIN) {
                    virReportError(VIR_ERR_RESOURCE_BUSY,
                                   _("Lockspace resource '%s' is locked"),
                                   resname);
                } else {
                    virReportSystemError(errno,
                                         _("Unable to acquire lock on '%s'"),
                                         res->path);
                }
                goto error;
            }

            /* Now make sure the pidfile we locked is the same
             * one that now exists on the filesystem
             */
            if (stat(res->path, &a) < 0) {
                char ebuf[1024] ATTRIBUTE_UNUSED;
                VIR_DEBUG("Resource '%s' disappeared: %s",
                          res->path, virStrerror(errno, ebuf, sizeof(ebuf)));
                VIR_FORCE_CLOSE(res->fd);
                /* Someone else must be racing with us, so try again */
                continue;
            }

            if (a.st_ino == b.st_ino)
                break;

            VIR_DEBUG("Resource '%s' was recreated", res->path);
            VIR_FORCE_CLOSE(res->fd);
            /* Someone else must be racing with us, so try again */
        }
    } else {
Exemplo n.º 19
0
/**
 * virRotatingFileWriterAppend:
 * @file: the file context
 * @buf: the data buffer
 * @len: the number of bytes in @buf
 *
 * Append the data in @buf to the file, performing rollover
 * of the files if their size would exceed the limit
 *
 * Returns the number of bytes written, or -1 on error
 */
ssize_t
virRotatingFileWriterAppend(virRotatingFileWriterPtr file,
                            const char *buf,
                            size_t len)
{
    ssize_t ret = 0;
    size_t i;
    while (len) {
        size_t towrite = len;
        bool forceRollover = false;

        if ((file->entry->pos + towrite) > file->maxlen) {
            towrite = file->maxlen - file->entry->pos;

            /*
             * If there's a newline in the last 80 chars
             * we're about to write, then break at that
             * point to avoid splitting lines across
             * separate files
             */
            for (i = 0; i < towrite && i < 80; i++) {
                if (buf[towrite - i - 1] == '\n') {
                    towrite -= i;
                    forceRollover = true;
                    break;
                }
            }
        }

        if (towrite) {
            if (safewrite(file->entry->fd, buf, towrite) != towrite) {
                virReportSystemError(errno,
                                     _("Unable to write to file %s"),
                                     file->basepath);
                return -1;
            }

            len -= towrite;
            buf += towrite;
            ret += towrite;
            file->entry->pos += towrite;
            file->entry->len += towrite;
        }

        if ((file->entry->pos == file->maxlen && len) ||
            forceRollover) {
            virRotatingFileWriterEntryPtr tmp = file->entry;
            VIR_DEBUG("Hit max size %zu on %s (force=%d)\n",
                      file->maxlen, file->basepath, forceRollover);

            if (virRotatingFileWriterRollover(file) < 0)
                return -1;

            if (!(file->entry = virRotatingFileWriterEntryNew(file->basepath,
                                                              file->mode)))
                return -1;

            virRotatingFileWriterEntryFree(tmp);
        }
    }

    return ret;
}
Exemplo n.º 20
0
virHostCPUParseNode(const char *node,
                    virArch arch,
                    virBitmapPtr present_cpus_map,
                    virBitmapPtr online_cpus_map,
                    int threads_per_subcore,
                    int *sockets,
                    int *cores,
                    int *threads,
                    int *offline)
{
    /* Biggest value we can expect to be used as either socket id
     * or core id. Bitmaps will need to be sized accordingly */
    const int ID_MAX = 4095;
    int ret = -1;
    int processors = 0;
    DIR *cpudir = NULL;
    struct dirent *cpudirent = NULL;
    virBitmapPtr node_cpus_map = NULL;
    virBitmapPtr sockets_map = NULL;
    virBitmapPtr *cores_maps = NULL;
    int npresent_cpus = virBitmapSize(present_cpus_map);
    int sock_max = 0;
    int sock;
    int core;
    size_t i;
    int siblings;
    unsigned int cpu;
    int direrr;

    *threads = 0;
    *cores = 0;
    *sockets = 0;

    if (!(cpudir = opendir(node))) {
        virReportSystemError(errno, _("cannot opendir %s"), node);
        goto cleanup;
    }

    /* Keep track of the CPUs that belong to the current node */
    if (!(node_cpus_map = virBitmapNew(npresent_cpus)))
        goto cleanup;

    /* enumerate sockets in the node */
    if (!(sockets_map = virBitmapNew(ID_MAX + 1)))
        goto cleanup;

    while ((direrr = virDirRead(cpudir, &cpudirent, node)) > 0) {
        if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
            continue;

        if (!virBitmapIsBitSet(present_cpus_map, cpu))
            continue;

        /* Mark this CPU as part of the current node */
        if (virBitmapSetBit(node_cpus_map, cpu) < 0)
            goto cleanup;

        if (!virBitmapIsBitSet(online_cpus_map, cpu))
            continue;

        /* Parse socket */
        if ((sock = virHostCPUParseSocket(node, arch, cpu)) < 0)
            goto cleanup;
        if (sock > ID_MAX) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Socket %d can't be handled (max socket is %d)"),
                           sock, ID_MAX);
            goto cleanup;
        }

        if (virBitmapSetBit(sockets_map, sock) < 0)
            goto cleanup;

        if (sock > sock_max)
            sock_max = sock;
    }

    if (direrr < 0)
        goto cleanup;

    sock_max++;

    /* allocate cores maps for each socket */
    if (VIR_ALLOC_N(cores_maps, sock_max) < 0)
        goto cleanup;

    for (i = 0; i < sock_max; i++)
        if (!(cores_maps[i] = virBitmapNew(ID_MAX + 1)))
            goto cleanup;

    /* Iterate over all CPUs in the node, in ascending order */
    for (cpu = 0; cpu < npresent_cpus; cpu++) {

        /* Skip CPUs that are not part of the current node */
        if (!virBitmapIsBitSet(node_cpus_map, cpu))
            continue;

        if (!virBitmapIsBitSet(online_cpus_map, cpu)) {
            if (threads_per_subcore > 0 &&
                cpu % threads_per_subcore != 0 &&
                virBitmapIsBitSet(online_cpus_map,
                                  cpu - (cpu % threads_per_subcore))) {
                /* Secondary offline threads are counted as online when
                 * subcores are in use and the corresponding primary
                 * thread is online */
                processors++;
            } else {
                /* But they are counted as offline otherwise */
                (*offline)++;
            }
            continue;
        }

        processors++;

        /* Parse socket */
        if ((sock = virHostCPUParseSocket(node, arch, cpu)) < 0)
            goto cleanup;
        if (!virBitmapIsBitSet(sockets_map, sock)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("CPU socket topology has changed"));
            goto cleanup;
        }

        /* Parse core */
        if (ARCH_IS_S390(arch)) {
            /* logical cpu is equivalent to a core on s390 */
            core = cpu;
        } else {
            if ((core = virHostCPUGetValue(node, cpu,
                                           "topology/core_id", 0)) < 0)
                goto cleanup;
        }
        if (core > ID_MAX) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Core %d can't be handled (max core is %d)"),
                           core, ID_MAX);
            goto cleanup;
        }

        if (virBitmapSetBit(cores_maps[sock], core) < 0)
            goto cleanup;

        if (!(siblings = virHostCPUCountThreadSiblings(node, cpu)))
            goto cleanup;

        if (siblings > *threads)
            *threads = siblings;
    }

    /* finalize the returned data */
    *sockets = virBitmapCountBits(sockets_map);

    for (i = 0; i < sock_max; i++) {
        if (!virBitmapIsBitSet(sockets_map, i))
            continue;

        core = virBitmapCountBits(cores_maps[i]);
        if (core > *cores)
            *cores = core;
    }

    if (threads_per_subcore > 0) {
        /* The thread count ignores offline threads, which means that only
         * only primary threads have been considered so far. If subcores
         * are in use, we need to also account for secondary threads */
        *threads *= threads_per_subcore;
    }
    ret = processors;

 cleanup:
    /* don't shadow a more serious error */
    if (cpudir && closedir(cpudir) < 0 && ret >= 0) {
        virReportSystemError(errno, _("problem closing %s"), node);
        ret = -1;
    }
    if (cores_maps)
        for (i = 0; i < sock_max; i++)
            virBitmapFree(cores_maps[i]);
    VIR_FREE(cores_maps);
    virBitmapFree(sockets_map);
    virBitmapFree(node_cpus_map);

    return ret;
}
Exemplo n.º 21
0
/*
 * Workaround older glibc. While kernel may support the setns
 * syscall, the glibc wrapper might not exist. If that's the
 * case, use our own.
 */
# ifndef __NR_setns
#  if defined(__x86_64__)
#   define __NR_setns 308
#  elif defined(__i386__)
#   define __NR_setns 346
#  elif defined(__arm__)
#   define __NR_setns 375
#  elif defined(__aarch64__)
#   define __NR_setns 375
#  elif defined(__powerpc__)
#   define __NR_setns 350
#  elif defined(__s390__)
#   define __NR_setns 339
#  endif
# endif

# ifndef HAVE_SETNS
#  if defined(__NR_setns)
#   include <sys/syscall.h>

static inline int setns(int fd, int nstype)
{
    return syscall(__NR_setns, fd, nstype);
}
#  else /* !__NR_setns */
#   error Please determine the syscall number for setns on your architecture
#  endif
# endif
#else /* !__linux__ */
static inline int setns(int fd ATTRIBUTE_UNUSED, int nstype ATTRIBUTE_UNUSED)
{
    virReportSystemError(ENOSYS, "%s",
                         _("Namespaces are not supported on this platform."));
    return -1;
}
Exemplo n.º 22
0
int
virHostCPUGetInfoPopulateLinux(FILE *cpuinfo,
                               virArch arch,
                               unsigned int *cpus,
                               unsigned int *mhz,
                               unsigned int *nodes,
                               unsigned int *sockets,
                               unsigned int *cores,
                               unsigned int *threads)
{
    virBitmapPtr present_cpus_map = NULL;
    virBitmapPtr online_cpus_map = NULL;
    char line[1024];
    DIR *nodedir = NULL;
    struct dirent *nodedirent = NULL;
    int nodecpus, nodecores, nodesockets, nodethreads, offline = 0;
    int threads_per_subcore = 0;
    unsigned int node;
    int ret = -1;
    char *sysfs_nodedir = NULL;
    char *sysfs_cpudir = NULL;
    int direrr;

    *mhz = 0;
    *cpus = *nodes = *sockets = *cores = *threads = 0;

    /* Start with parsing CPU clock speed from /proc/cpuinfo */
    while (fgets(line, sizeof(line), cpuinfo) != NULL) {
        if (ARCH_IS_X86(arch)) {
            char *buf = line;
            if (STRPREFIX(buf, "cpu MHz")) {
                char *p;
                unsigned int ui;

                buf += 7;
                while (*buf && c_isspace(*buf))
                    buf++;

                if (*buf != ':' || !buf[1]) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("parsing cpu MHz from cpuinfo"));
                    goto cleanup;
                }

                if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 &&
                    /* Accept trailing fractional part.  */
                    (*p == '\0' || *p == '.' || c_isspace(*p)))
                    *mhz = ui;
            }
        } else if (ARCH_IS_PPC(arch)) {
            char *buf = line;
            if (STRPREFIX(buf, "clock")) {
                char *p;
                unsigned int ui;

                buf += 5;
                while (*buf && c_isspace(*buf))
                    buf++;

                if (*buf != ':' || !buf[1]) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("parsing cpu MHz from cpuinfo"));
                    goto cleanup;
                }

                if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 &&
                    /* Accept trailing fractional part.  */
                    (*p == '\0' || *p == '.' || c_isspace(*p)))
                    *mhz = ui;
                /* No other interesting infos are available in /proc/cpuinfo.
                 * However, there is a line identifying processor's version,
                 * identification and machine, but we don't want it to be caught
                 * and parsed in next iteration, because it is not in expected
                 * format and thus lead to error. */
            }
        } else if (ARCH_IS_ARM(arch)) {
            char *buf = line;
            if (STRPREFIX(buf, "BogoMIPS")) {
                char *p;
                unsigned int ui;

                buf += 8;
                while (*buf && c_isspace(*buf))
                    buf++;

                if (*buf != ':' || !buf[1]) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("parsing cpu MHz from cpuinfo"));
                    goto cleanup;
                }

                if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0
                    /* Accept trailing fractional part.  */
                    && (*p == '\0' || *p == '.' || c_isspace(*p)))
                    *mhz = ui;
            }
        } else if (ARCH_IS_S390(arch)) {
            /* s390x has no realistic value for CPU speed,
             * assign a value of zero to signify this */
            *mhz = 0;
        } else {
            VIR_WARN("Parser for /proc/cpuinfo needs to be adapted for your architecture");
            break;
        }
    }

    /* Get information about what CPUs are present in the host and what
     * CPUs are online, so that we don't have to so for each node */
    present_cpus_map = virHostCPUGetPresentBitmap();
    if (!present_cpus_map)
        goto cleanup;
    online_cpus_map = virHostCPUGetOnlineBitmap();
    if (!online_cpus_map)
        goto cleanup;

    /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the
     * core, node, socket, thread and topology information from /sys
     */
    if (virAsprintf(&sysfs_nodedir, "%s/node", sysfs_system_path) < 0)
        goto cleanup;

    if (!(nodedir = opendir(sysfs_nodedir))) {
        /* the host isn't probably running a NUMA architecture */
        goto fallback;
    }

    /* PPC-KVM needs the secondary threads of a core to be offline on the
     * host. The kvm scheduler brings the secondary threads online in the
     * guest context. Moreover, P8 processor has split-core capability
     * where, there can be 1,2 or 4 subcores per core. The primaries of the
     * subcores alone will be online on the host for a subcore in the
     * host. Even though the actual threads per core for P8 processor is 8,
     * depending on the subcores_per_core = 1, 2 or 4, the threads per
     * subcore will vary accordingly to 8, 4 and 2 repectively.
     * So, On host threads_per_core what is arrived at from sysfs in the
     * current logic is actually the subcores_per_core. Threads per subcore
     * can only be obtained from the kvm device. For example, on P8 wih 1
     * core having 8 threads, sub_cores_percore=4, the threads 0,2,4 & 6
     * will be online. The sysfs reflects this and in the current logic
     * variable 'threads' will be 4 which is nothing but subcores_per_core.
     * If the user tampers the cpu online/offline states using chcpu or other
     * means, then it is an unsupported configuration for kvm.
     * The code below tries to keep in mind
     *  - when the libvirtd is run inside a KVM guest or Phyp based guest.
     *  - Or on the kvm host where user manually tampers the cpu states to
     *    offline/online randomly.
     * On hosts other than POWER this will be 0, in which case a simpler
     * thread-counting logic will be used  */
    if ((threads_per_subcore = virHostCPUGetThreadsPerSubcore(arch)) < 0)
        goto cleanup;

    /* If the subcore configuration is not valid, just pretend subcores
     * are not in use and count threads one by one */
    if (!virHostCPUHasValidSubcoreConfiguration(threads_per_subcore))
        threads_per_subcore = 0;

    while ((direrr = virDirRead(nodedir, &nodedirent, sysfs_nodedir)) > 0) {
        if (sscanf(nodedirent->d_name, "node%u", &node) != 1)
            continue;

        (*nodes)++;

        if (virAsprintf(&sysfs_cpudir, "%s/node/%s",
                        sysfs_system_path, nodedirent->d_name) < 0)
            goto cleanup;

        if ((nodecpus = virHostCPUParseNode(sysfs_cpudir, arch,
                                            present_cpus_map,
                                            online_cpus_map,
                                            threads_per_subcore,
                                            &nodesockets, &nodecores,
                                            &nodethreads, &offline)) < 0)
            goto cleanup;

        VIR_FREE(sysfs_cpudir);

        *cpus += nodecpus;

        if (nodesockets > *sockets)
            *sockets = nodesockets;

        if (nodecores > *cores)
            *cores = nodecores;

        if (nodethreads > *threads)
            *threads = nodethreads;
    }

    if (direrr < 0)
        goto cleanup;

    if (*cpus && *nodes)
        goto done;

 fallback:
    VIR_FREE(sysfs_cpudir);

    if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_system_path) < 0)
        goto cleanup;

    if ((nodecpus = virHostCPUParseNode(sysfs_cpudir, arch,
                                        present_cpus_map,
                                        online_cpus_map,
                                        threads_per_subcore,
                                        &nodesockets, &nodecores,
                                        &nodethreads, &offline)) < 0)
        goto cleanup;

    *nodes = 1;
    *cpus = nodecpus;
    *sockets = nodesockets;
    *cores = nodecores;
    *threads = nodethreads;

 done:
    /* There should always be at least one cpu, socket, node, and thread. */
    if (*cpus == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no CPUs found"));
        goto cleanup;
    }

    if (*sockets == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found"));
        goto cleanup;
    }

    if (*threads == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found"));
        goto cleanup;
    }

    /* Now check if the topology makes sense. There are machines that don't
     * expose their real number of nodes or for example the AMD Bulldozer
     * architecture that exposes their Clustered integer core modules as both
     * threads and cores. This approach throws off our detection. Unfortunately
     * the nodeinfo structure isn't designed to carry the full topology so
     * we're going to lie about the detected topology to notify the user
     * to check the host capabilities for the actual topology. */
    if ((*nodes *
         *sockets *
         *cores *
         *threads) != (*cpus + offline)) {
        *nodes = 1;
        *sockets = 1;
        *cores = *cpus + offline;
        *threads = 1;
    }

    ret = 0;

 cleanup:
    /* don't shadow a more serious error */
    if (nodedir && closedir(nodedir) < 0 && ret >= 0) {
        virReportSystemError(errno, _("problem closing %s"), sysfs_nodedir);
        ret = -1;
    }

    virBitmapFree(present_cpus_map);
    virBitmapFree(online_cpus_map);
    VIR_FREE(sysfs_nodedir);
    VIR_FREE(sysfs_cpudir);
    return ret;
}
Exemplo n.º 23
0
int virProcessSetAffinity(pid_t pid, virBitmapPtr map)
{
    size_t i;
    VIR_DEBUG("Set process affinity on %lld", (long long)pid);
# ifdef CPU_ALLOC
    /* New method dynamically allocates cpu mask, allowing unlimted cpus */
    int numcpus = 1024;
    size_t masklen;
    cpu_set_t *mask;

    /* Not only may the statically allocated cpu_set_t be too small,
     * but there is no way to ask the kernel what size is large enough.
     * So you have no option but to pick a size, try, catch EINVAL,
     * enlarge, and re-try.
     *
     * http://lkml.org/lkml/2009/7/28/620
     */
 realloc:
    masklen = CPU_ALLOC_SIZE(numcpus);
    mask = CPU_ALLOC(numcpus);

    if (!mask) {
        virReportOOMError();
        return -1;
    }

    CPU_ZERO_S(masklen, mask);
    for (i = 0; i < virBitmapSize(map); i++) {
        if (virBitmapIsBitSet(map, i))
            CPU_SET_S(i, masklen, mask);
    }

    if (sched_setaffinity(pid, masklen, mask) < 0) {
        CPU_FREE(mask);
        if (errno == EINVAL &&
            numcpus < (1024 << 8)) { /* 262144 cpus ought to be enough for anyone */
            numcpus = numcpus << 2;
            goto realloc;
        }
        virReportSystemError(errno,
                             _("cannot set CPU affinity on process %d"), pid);
        return -1;
    }
    CPU_FREE(mask);
# else
    /* Legacy method uses a fixed size cpu mask, only allows up to 1024 cpus */
    cpu_set_t mask;

    CPU_ZERO(&mask);
    for (i = 0; i < virBitmapSize(map); i++) {
        if (virBitmapIsBitSet(map, i))
            CPU_SET(i, &mask);
    }

    if (sched_setaffinity(pid, sizeof(mask), &mask) < 0) {
        virReportSystemError(errno,
                             _("cannot set CPU affinity on process %d"), pid);
        return -1;
    }
# endif

    return 0;
}
Exemplo n.º 24
0
static int
virHostCPUGetStatsFreeBSD(int cpuNum,
                          virNodeCPUStatsPtr params,
                          int *nparams)
{
    const char *sysctl_name;
    long *cpu_times;
    struct clockinfo clkinfo;
    size_t i, j, cpu_times_size, clkinfo_size;
    int cpu_times_num, offset, hz, stathz, ret = -1;
    struct field_cpu_map {
        const char *field;
        int idx[CPUSTATES];
    } cpu_map[] = {
        {VIR_NODE_CPU_STATS_KERNEL, {CP_SYS}},
        {VIR_NODE_CPU_STATS_USER, {CP_USER, CP_NICE}},
        {VIR_NODE_CPU_STATS_IDLE, {CP_IDLE}},
        {VIR_NODE_CPU_STATS_INTR, {CP_INTR}},
        {NULL, {0}}
    };

    if ((*nparams) == 0) {
        *nparams = BSD_CPU_STATS_ALL;
        return 0;
    }

    if ((*nparams) != BSD_CPU_STATS_ALL) {
        virReportInvalidArg(*nparams,
                            _("nparams in %s must be equal to %d"),
                            __FUNCTION__, BSD_CPU_STATS_ALL);
        return -1;
    }

    clkinfo_size = sizeof(clkinfo);
    if (sysctlbyname("kern.clockrate", &clkinfo, &clkinfo_size, NULL, 0) < 0) {
        virReportSystemError(errno,
                             _("sysctl failed for '%s'"),
                             "kern.clockrate");
        return -1;
    }

    stathz = clkinfo.stathz;
    hz = clkinfo.hz;

    if (cpuNum == VIR_NODE_CPU_STATS_ALL_CPUS) {
        sysctl_name = "kern.cp_time";
        cpu_times_num = 1;
        offset = 0;
    } else {
        sysctl_name = "kern.cp_times";
        cpu_times_num = virHostCPUGetCountAppleFreeBSD();

        if (cpuNum >= cpu_times_num) {
            virReportInvalidArg(cpuNum,
                                _("Invalid cpuNum in %s"),
                                __FUNCTION__);
            return -1;
        }

        offset = cpu_times_num * CPUSTATES;
    }

    cpu_times_size = sizeof(long) * cpu_times_num * CPUSTATES;

    if (VIR_ALLOC_N(cpu_times, cpu_times_num * CPUSTATES) < 0)
        goto cleanup;

    if (sysctlbyname(sysctl_name, cpu_times, &cpu_times_size, NULL, 0) < 0) {
        virReportSystemError(errno,
                             _("sysctl failed for '%s'"),
                             sysctl_name);
        goto cleanup;
    }

    for (i = 0; cpu_map[i].field != NULL; i++) {
        virNodeCPUStatsPtr param = &params[i];

        if (virStrcpyStatic(param->field, cpu_map[i].field) == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Field '%s' too long for destination"),
                           cpu_map[i].field);
            goto cleanup;
        }

        param->value = 0;
        for (j = 0; j < ARRAY_CARDINALITY(cpu_map[i].idx); j++)
            param->value += cpu_times[offset + cpu_map[i].idx[j]] * TICK_TO_NSEC;
    }

    ret = 0;

 cleanup:
    VIR_FREE(cpu_times);

    return ret;
}
Exemplo n.º 25
0
static int
SELinuxLXCInitialize(virSecurityManagerPtr mgr)
{
    virConfValuePtr scon = NULL;
    virConfValuePtr tcon = NULL;
    virConfValuePtr dcon = NULL;
    virConfPtr selinux_conf;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    selinux_conf = virConfReadFile(selinux_lxc_contexts_path(), 0);
    if (!selinux_conf) {
        virReportSystemError(errno,
                             _("cannot open SELinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
        return -1;
    }

    scon = virConfGetValue(selinux_conf, "process");
    if (! scon || scon->type != VIR_CONF_STRING || (! scon->str)) {
        virReportSystemError(errno,
                             _("cannot read 'process' value from selinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
        goto error;
    }

    tcon = virConfGetValue(selinux_conf, "file");
    if (! tcon || tcon->type != VIR_CONF_STRING || (! tcon->str)) {
        virReportSystemError(errno,
                             _("cannot read 'file' value from selinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
        goto error;
    }

    dcon = virConfGetValue(selinux_conf, "content");
    if (! dcon || dcon->type != VIR_CONF_STRING || (! dcon->str)) {
        virReportSystemError(errno,
                             _("cannot read 'file' value from selinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
        goto error;
    }

    data->domain_context = strdup(scon->str);
    data->file_context = strdup(tcon->str);
    data->content_context = strdup(dcon->str);
    if (!data->domain_context ||
        !data->file_context ||
        !data->content_context) {
        virReportSystemError(errno,
                             _("cannot allocate memory for LXC SELinux contexts '%s'"),
                             selinux_lxc_contexts_path());
        goto error;
    }
    virConfFree(selinux_conf);
    return 0;

error:
    virConfFree(selinux_conf);
    VIR_FREE(data->domain_context);
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);
    return -1;
}
Exemplo n.º 26
0
static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr,
                                       virSocketAddrPtr remoteAddr,
                                       bool isClient,
                                       int fd, int errfd, pid_t pid)
{
    virNetSocketPtr sock;
    int no_slow_start = 1;

    VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%d",
              localAddr, remoteAddr,
              fd, errfd, pid);

    if (virSetCloseExec(fd) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to set close-on-exec flag"));
       return NULL;
    }
    if (virSetNonBlock(fd) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to enable non-blocking flag"));
        return NULL;
    }

    if (VIR_ALLOC(sock) < 0) {
        virReportOOMError();
        return NULL;
    }

    if (virMutexInit(&sock->lock) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to initialize mutex"));
        VIR_FREE(sock);
        return NULL;
    }
    sock->refs = 1;

    if (localAddr)
        sock->localAddr = *localAddr;
    if (remoteAddr)
        sock->remoteAddr = *remoteAddr;
    sock->fd = fd;
    sock->errfd = errfd;
    sock->pid = pid;

    /* Disable nagle for TCP sockets */
    if (sock->localAddr.data.sa.sa_family == AF_INET ||
        sock->localAddr.data.sa.sa_family == AF_INET6) {
        if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
                       &no_slow_start,
                       sizeof(no_slow_start)) < 0) {
            virReportSystemError(errno, "%s",
                                 _("Unable to disable nagle algorithm"));
            goto error;
        }
    }


    if (localAddr &&
        !(sock->localAddrStr = virSocketFormatAddrFull(localAddr, true, ";")))
        goto error;

    if (remoteAddr &&
        !(sock->remoteAddrStr = virSocketFormatAddrFull(remoteAddr, true, ";")))
        goto error;

    sock->client = isClient;

    PROBE(RPC_SOCKET_NEW,
          "sock=%p refs=%d fd=%d errfd=%d pid=%d localAddr=%s, remoteAddr=%s",
          sock, sock->refs, fd, errfd,
          pid, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr));

    return sock;

error:
    sock->fd = sock->errfd = -1; /* Caller owns fd/errfd on failure */
    virNetSocketFree(sock);
    return NULL;
}
Exemplo n.º 27
0
int qemudLoadDriverConfig(struct qemud_driver *driver,
                          const char *filename) {
    virConfPtr conf;
    virConfValuePtr p;
    char *user;
    char *group;
    int i;

    /* Setup critical defaults */
    driver->dynamicOwnership = 1;
    driver->clearEmulatorCapabilities = 1;

    if (!(driver->vncListen = strdup("127.0.0.1"))) {
        virReportOOMError();
        return -1;
    }
    if (!(driver->vncTLSx509certdir = strdup(SYSCONFDIR "/pki/libvirt-vnc"))) {
        virReportOOMError();
        return -1;
    }

    if (!(driver->spiceListen = strdup("127.0.0.1"))) {
        virReportOOMError();
        return -1;
    }
    if (!(driver->spiceTLSx509certdir
          = strdup(SYSCONFDIR "/pki/libvirt-spice"))) {
        virReportOOMError();
        return -1;
    }

#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
    /* For privileged driver, try and find hugepage mount automatically.
     * Non-privileged driver requires admin to create a dir for the
     * user, chown it, and then let user configure it manually */
    if (driver->privileged &&
        !(driver->hugetlbfs_mount = virFileFindMountPoint("hugetlbfs"))) {
        if (errno != ENOENT) {
            virReportSystemError(errno, "%s",
                                 _("unable to find hugetlbfs mountpoint"));
            return -1;
        }
    }
#endif


    /* Just check the file is readable before opening it, otherwise
     * libvirt emits an error.
     */
    if (access (filename, R_OK) == -1) {
        VIR_INFO("Could not read qemu config file %s", filename);
        return 0;
    }

    conf = virConfReadFile (filename, 0);
    if (!conf) {
        return -1;
    }


#define CHECK_TYPE(name,typ) if (p && p->type != (typ)) {               \
        qemuReportError(VIR_ERR_INTERNAL_ERROR,                         \
                        "%s: %s: expected type " #typ,                  \
                        filename, (name));                              \
        virConfFree(conf);                                              \
        return -1;                                                      \
    }

    p = virConfGetValue (conf, "vnc_auto_unix_socket");
    CHECK_TYPE ("vnc_auto_unix_socket", VIR_CONF_LONG);
    if (p) driver->vncAutoUnixSocket = p->l;

    p = virConfGetValue (conf, "vnc_tls");
    CHECK_TYPE ("vnc_tls", VIR_CONF_LONG);
    if (p) driver->vncTLS = p->l;

    p = virConfGetValue (conf, "vnc_tls_x509_verify");
    CHECK_TYPE ("vnc_tls_x509_verify", VIR_CONF_LONG);
    if (p) driver->vncTLSx509verify = p->l;

    p = virConfGetValue (conf, "vnc_tls_x509_cert_dir");
    CHECK_TYPE ("vnc_tls_x509_cert_dir", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->vncTLSx509certdir);
        if (!(driver->vncTLSx509certdir = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "vnc_listen");
    CHECK_TYPE ("vnc_listen", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->vncListen);
        if (!(driver->vncListen = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "vnc_password");
    CHECK_TYPE ("vnc_password", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->vncPassword);
        if (!(driver->vncPassword = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "security_driver");
    CHECK_TYPE ("security_driver", VIR_CONF_STRING);
    if (p && p->str) {
        if (!(driver->securityDriverName = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "vnc_sasl");
    CHECK_TYPE ("vnc_sasl", VIR_CONF_LONG);
    if (p) driver->vncSASL = p->l;

    p = virConfGetValue (conf, "vnc_sasl_dir");
    CHECK_TYPE ("vnc_sasl_dir", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->vncSASLdir);
        if (!(driver->vncSASLdir = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "spice_tls");
    CHECK_TYPE ("spice_tls", VIR_CONF_LONG);
    if (p) driver->spiceTLS = p->l;

    p = virConfGetValue (conf, "spice_tls_x509_cert_dir");
    CHECK_TYPE ("spice_tls_x509_cert_dir", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->spiceTLSx509certdir);
        if (!(driver->spiceTLSx509certdir = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "spice_listen");
    CHECK_TYPE ("spice_listen", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->spiceListen);
        if (!(driver->spiceListen = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "spice_password");
    CHECK_TYPE ("spice_password", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->spicePassword);
        if (!(driver->spicePassword = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "user");
    CHECK_TYPE ("user", VIR_CONF_STRING);
    if (!(user = strdup(p && p->str ? p->str : QEMU_USER))) {
        virReportOOMError();
        virConfFree(conf);
        return -1;
    }
    if (virGetUserID(user, &driver->user) < 0) {
        VIR_FREE(user);
        virConfFree(conf);
        return -1;
    }
    VIR_FREE(user);


    p = virConfGetValue (conf, "group");
    CHECK_TYPE ("group", VIR_CONF_STRING);
    if (!(group = strdup(p && p->str ? p->str : QEMU_GROUP))) {
        virReportOOMError();
        virConfFree(conf);
        return -1;
    }
    if (virGetGroupID(group, &driver->group) < 0) {
        VIR_FREE(group);
        virConfFree(conf);
        return -1;
    }
    VIR_FREE(group);


    p = virConfGetValue (conf, "dynamic_ownership");
    CHECK_TYPE ("dynamic_ownership", VIR_CONF_LONG);
    if (p) driver->dynamicOwnership = p->l;


    p = virConfGetValue (conf, "cgroup_controllers");
    CHECK_TYPE ("cgroup_controllers", VIR_CONF_LIST);
    if (p) {
        virConfValuePtr pp;
        for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
            int ctl;
            if (pp->type != VIR_CONF_STRING) {
                VIR_ERROR0(_("cgroup_controllers must be a list of strings"));
                virConfFree(conf);
                return -1;
            }
            ctl = virCgroupControllerTypeFromString(pp->str);
            if (ctl < 0) {
                VIR_ERROR(_("Unknown cgroup controller '%s'"), pp->str);
                virConfFree(conf);
                return -1;
            }
            driver->cgroupControllers |= (1 << ctl);
        }
    } else {
        driver->cgroupControllers =
            (1 << VIR_CGROUP_CONTROLLER_CPU) |
            (1 << VIR_CGROUP_CONTROLLER_DEVICES) |
            (1 << VIR_CGROUP_CONTROLLER_MEMORY) |
            (1 << VIR_CGROUP_CONTROLLER_BLKIO);
    }
    for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
        if (driver->cgroupControllers & (1 << i)) {
            VIR_INFO("Configured cgroup controller '%s'",
                     virCgroupControllerTypeToString(i));
        }
    }

    p = virConfGetValue (conf, "cgroup_device_acl");
    CHECK_TYPE ("cgroup_device_acl", VIR_CONF_LIST);
    if (p) {
        int len = 0;
        virConfValuePtr pp;
        for (pp = p->list; pp; pp = pp->next)
            len++;
        if (VIR_ALLOC_N(driver->cgroupDeviceACL, 1+len) < 0) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
        for (i = 0, pp = p->list; pp; ++i, pp = pp->next) {
            if (pp->type != VIR_CONF_STRING) {
                VIR_ERROR0(_("cgroup_device_acl must be a list of strings"));
                virConfFree(conf);
                return -1;
            }
            driver->cgroupDeviceACL[i] = strdup (pp->str);
            if (driver->cgroupDeviceACL[i] == NULL) {
                virReportOOMError();
                virConfFree(conf);
                return -1;
            }

        }
        driver->cgroupDeviceACL[i] = NULL;
    }

    p = virConfGetValue (conf, "save_image_format");
    CHECK_TYPE ("save_image_format", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->saveImageFormat);
        if (!(driver->saveImageFormat = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "dump_image_format");
    CHECK_TYPE ("dump_image_format", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->dumpImageFormat);
        if (!(driver->dumpImageFormat = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

    p = virConfGetValue (conf, "auto_dump_path");
    CHECK_TYPE ("auto_dump_path", VIR_CONF_STRING);
    if (p && p->str) {
        VIR_FREE(driver->autoDumpPath);
        if (!(driver->autoDumpPath = strdup(p->str))) {
            virReportOOMError();
            virConfFree(conf);
            return -1;
        }
    }

     p = virConfGetValue (conf, "hugetlbfs_mount");
     CHECK_TYPE ("hugetlbfs_mount", VIR_CONF_STRING);
     if (p && p->str) {
         VIR_FREE(driver->hugetlbfs_mount);
         if (!(driver->hugetlbfs_mount = strdup(p->str))) {
             virReportOOMError();
             virConfFree(conf);
             return -1;
         }
     }

    p = virConfGetValue (conf, "mac_filter");
    CHECK_TYPE ("mac_filter", VIR_CONF_LONG);
    if (p && p->l) {
        driver->macFilter = p->l;
        if (!(driver->ebtables = ebtablesContextNew("qemu"))) {
            driver->macFilter = 0;
            virReportSystemError(errno,
                                 _("failed to enable mac filter in '%s'"),
                                 __FILE__);
        }

        if ((errno = networkDisableAllFrames(driver))) {
            virReportSystemError(errno,
                         _("failed to add rule to drop all frames in '%s'"),
                                 __FILE__);
        }
    }

    p = virConfGetValue (conf, "relaxed_acs_check");
    CHECK_TYPE ("relaxed_acs_check", VIR_CONF_LONG);
    if (p) driver->relaxedACS = p->l;

    p = virConfGetValue (conf, "vnc_allow_host_audio");
    CHECK_TYPE ("vnc_allow_host_audio", VIR_CONF_LONG);
    if (p) driver->vncAllowHostAudio = p->l;

    p = virConfGetValue (conf, "clear_emulator_capabilities");
    CHECK_TYPE ("clear_emulator_capabilities", VIR_CONF_LONG);
    if (p) driver->clearEmulatorCapabilities = p->l;

    p = virConfGetValue (conf, "allow_disk_format_probing");
    CHECK_TYPE ("allow_disk_format_probing", VIR_CONF_LONG);
    if (p) driver->allowDiskFormatProbing = p->l;

    p = virConfGetValue (conf, "set_process_name");
    CHECK_TYPE ("set_process_name", VIR_CONF_LONG);
    if (p) driver->setProcessName = p->l;

    p = virConfGetValue(conf, "max_processes");
    CHECK_TYPE("max_processes", VIR_CONF_LONG);
    if (p) driver->maxProcesses = p->l;

    virConfFree (conf);
    return 0;
}
Exemplo n.º 28
0
int virNetSocketNewListenTCP(const char *nodename,
                             const char *service,
                             virNetSocketPtr **retsocks,
                             size_t *nretsocks)
{
    virNetSocketPtr *socks = NULL;
    size_t nsocks = 0;
    struct addrinfo *ai = NULL;
    struct addrinfo hints;
    int fd = -1;
    int i;
    int addrInUse = false;

    *retsocks = NULL;
    *nretsocks = 0;

    memset(&hints, 0, sizeof hints);
    hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
    hints.ai_socktype = SOCK_STREAM;

    int e = getaddrinfo(nodename, service, &hints, &ai);
    if (e != 0) {
        virNetError(VIR_ERR_SYSTEM_ERROR,
                    _("Unable to resolve address '%s' service '%s': %s"),
                    nodename, service, gai_strerror(e));
        return -1;
    }

    struct addrinfo *runp = ai;
    while (runp) {
        virSocketAddr addr;

        memset(&addr, 0, sizeof(addr));

        if ((fd = socket(runp->ai_family, runp->ai_socktype,
                         runp->ai_protocol)) < 0) {
            virReportSystemError(errno, "%s", _("Unable to create socket"));
            goto error;
        }

        int opt = 1;
        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) < 0) {
            virReportSystemError(errno, "%s", _("Unable to enable port reuse"));
            goto error;
        }

#ifdef IPV6_V6ONLY
        if (runp->ai_family == PF_INET6) {
            int on = 1;
            /*
             * Normally on Linux an INET6 socket will bind to the INET4
             * address too. If getaddrinfo returns results with INET4
             * first though, this will result in INET6 binding failing.
             * We can trivially cope with multiple server sockets, so
             * we force it to only listen on IPv6
             */
            if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
                           (void*)&on, sizeof on) < 0) {
                virReportSystemError(errno, "%s",
                                     _("Unable to force bind to IPv6 only"));
                goto error;
            }
        }
#endif

        if (bind(fd, runp->ai_addr, runp->ai_addrlen) < 0) {
            if (errno != EADDRINUSE) {
                virReportSystemError(errno, "%s", _("Unable to bind to port"));
                goto error;
            }
            addrInUse = true;
            VIR_FORCE_CLOSE(fd);
            runp = runp->ai_next;
            continue;
        }

        addr.len = sizeof(addr.data);
        if (getsockname(fd, &addr.data.sa, &addr.len) < 0) {
            virReportSystemError(errno, "%s", _("Unable to get local socket name"));
            goto error;
        }

        VIR_DEBUG("%p f=%d f=%d", &addr, runp->ai_family, addr.data.sa.sa_family);

        if (VIR_EXPAND_N(socks, nsocks, 1) < 0) {
            virReportOOMError();
            goto error;
        }

        if (!(socks[nsocks-1] = virNetSocketNew(&addr, NULL, false, fd, -1, 0)))
            goto error;
        runp = runp->ai_next;
        fd = -1;
    }

    if (nsocks == 0 &&
        addrInUse) {
        virReportSystemError(EADDRINUSE, "%s", _("Unable to bind to port"));
        goto error;
    }

    freeaddrinfo(ai);

    *retsocks = socks;
    *nretsocks = nsocks;
    return 0;

error:
    for (i = 0 ; i < nsocks ; i++)
        virNetSocketFree(socks[i]);
    VIR_FREE(socks);
    freeaddrinfo(ai);
    VIR_FORCE_CLOSE(fd);
    return -1;
}
Exemplo n.º 29
0
int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
                             const char *sysfs_dir,
                             virNodeInfoPtr nodeinfo)
{
    char line[1024];
    DIR *nodedir = NULL;
    struct dirent *nodedirent = NULL;
    int cpus, cores, socks, threads, offline = 0;
    unsigned int node;
    int ret = -1;
    char *sysfs_nodedir = NULL;
    char *sysfs_cpudir = NULL;

    /* Start with parsing CPU clock speed from /proc/cpuinfo */
    while (fgets(line, sizeof(line), cpuinfo) != NULL) {
# if defined(__x86_64__) || \
    defined(__amd64__)  || \
    defined(__i386__)
        char *buf = line;
        if (STRPREFIX(buf, "cpu MHz")) {
            char *p;
            unsigned int ui;

            buf += 7;
            while (*buf && c_isspace(*buf))
                buf++;

            if (*buf != ':' || !buf[1]) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("parsing cpu MHz from cpuinfo"));
                goto cleanup;
            }

            if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 &&
                /* Accept trailing fractional part.  */
                (*p == '\0' || *p == '.' || c_isspace(*p)))
                nodeinfo->mhz = ui;
        }

# elif defined(__powerpc__) || \
      defined(__powerpc64__)
        char *buf = line;
        if (STRPREFIX(buf, "clock")) {
            char *p;
            unsigned int ui;

            buf += 5;
            while (*buf && c_isspace(*buf))
                buf++;

            if (*buf != ':' || !buf[1]) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("parsing cpu MHz from cpuinfo"));
                goto cleanup;
            }

            if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0 &&
                /* Accept trailing fractional part.  */
                (*p == '\0' || *p == '.' || c_isspace(*p)))
                nodeinfo->mhz = ui;
            /* No other interesting infos are available in /proc/cpuinfo.
             * However, there is a line identifying processor's version,
             * identification and machine, but we don't want it to be caught
             * and parsed in next iteration, because it is not in expected
             * format and thus lead to error. */
        }
# elif defined(__arm__)
        char *buf = line;
        if (STRPREFIX(buf, "BogoMIPS")) {
            char *p;
            unsigned int ui;

            buf += 8;
            while (*buf && c_isspace(*buf))
                buf++;

            if (*buf != ':' || !buf[1]) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("parsing cpu MHz from cpuinfo"));
                goto cleanup;
            }

            if (virStrToLong_ui(buf+1, &p, 10, &ui) == 0
                /* Accept trailing fractional part.  */
                && (*p == '\0' || *p == '.' || c_isspace(*p)))
                nodeinfo->mhz = ui;
        }
# elif defined(__s390__) || \
      defined(__s390x__)
        /* s390x has no realistic value for CPU speed,
         * assign a value of zero to signify this */
        nodeinfo->mhz = 0;
# else
#  warning Parser for /proc/cpuinfo needs to be adapted for your architecture
# endif
    }

    /* OK, we've parsed clock speed out of /proc/cpuinfo. Get the
     * core, node, socket, thread and topology information from /sys
     */
    if (virAsprintf(&sysfs_nodedir, "%s/node", sysfs_dir) < 0)
        goto cleanup;

    if (!(nodedir = opendir(sysfs_nodedir))) {
        /* the host isn't probably running a NUMA architecture */
        goto fallback;
    }

    errno = 0;
    while ((nodedirent = readdir(nodedir))) {
        if (sscanf(nodedirent->d_name, "node%u", &node) != 1)
            continue;

        nodeinfo->nodes++;

        if (virAsprintf(&sysfs_cpudir, "%s/node/%s",
                        sysfs_dir, nodedirent->d_name) < 0)
            goto cleanup;

        if ((cpus = virNodeParseNode(sysfs_cpudir, &socks, &cores,
                                     &threads, &offline)) < 0)
            goto cleanup;

        VIR_FREE(sysfs_cpudir);

        nodeinfo->cpus += cpus;

        if (socks > nodeinfo->sockets)
            nodeinfo->sockets = socks;

        if (cores > nodeinfo->cores)
            nodeinfo->cores = cores;

        if (threads > nodeinfo->threads)
            nodeinfo->threads = threads;

        errno = 0;
    }

    if (errno) {
        virReportSystemError(errno, _("problem reading %s"), sysfs_nodedir);
        goto cleanup;
    }

    if (nodeinfo->cpus && nodeinfo->nodes)
        goto done;

fallback:
    VIR_FREE(sysfs_cpudir);

    if (virAsprintf(&sysfs_cpudir, "%s/cpu", sysfs_dir) < 0)
        goto cleanup;

    if ((cpus = virNodeParseNode(sysfs_cpudir, &socks, &cores,
                                 &threads, &offline)) < 0)
        goto cleanup;

    nodeinfo->nodes = 1;
    nodeinfo->cpus = cpus;
    nodeinfo->sockets = socks;
    nodeinfo->cores = cores;
    nodeinfo->threads = threads;

done:
    /* There should always be at least one cpu, socket, node, and thread. */
    if (nodeinfo->cpus == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no CPUs found"));
        goto cleanup;
    }

    if (nodeinfo->sockets == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no sockets found"));
        goto cleanup;
    }

    if (nodeinfo->threads == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("no threads found"));
        goto cleanup;
    }

    /* Now check if the topology makes sense. There are machines that don't
     * expose their real number of nodes or for example the AMD Bulldozer
     * architecture that exposes their Clustered integer core modules as both
     * threads and cores. This approach throws off our detection. Unfortunately
     * the nodeinfo structure isn't designed to carry the full topology so
     * we're going to lie about the detected topology to notify the user
     * to check the host capabilities for the actual topology. */
    if ((nodeinfo->nodes *
         nodeinfo->sockets *
         nodeinfo->cores *
         nodeinfo->threads) != (nodeinfo->cpus + offline)) {
        nodeinfo->nodes = 1;
        nodeinfo->sockets = 1;
        nodeinfo->cores = nodeinfo->cpus + offline;
        nodeinfo->threads = 1;
    }

    ret = 0;

cleanup:
    /* don't shadow a more serious error */
    if (nodedir && closedir(nodedir) < 0 && ret >= 0) {
        virReportSystemError(errno, _("problem closing %s"), sysfs_nodedir);
        ret = -1;
    }

    VIR_FREE(sysfs_nodedir);
    VIR_FREE(sysfs_cpudir);
    return ret;
}
Exemplo n.º 30
0
static int virLockManagerSanlockCreateLease(struct sanlk_resource *res)
{
    int fd = -1;
    struct stat st;
    int rv;

    if (stat(res->disks[0].path, &st) < 0) {
        VIR_DEBUG("Lockspace %s does not yet exist", res->disks[0].path);
        if ((fd = open(res->disks[0].path, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) {
            if (errno != EEXIST) {
                virReportSystemError(errno,
                                     _("Unable to create lockspace %s"),
                                     res->disks[0].path);
                return -1;
            }
            VIR_DEBUG("Someone else just created lockspace %s", res->disks[0].path);
        } else {
            /* chown() the path to make sure sanlock can access it */
            if ((driver->user != (uid_t) -1 || driver->group != (gid_t) -1) &&
                    (fchown(fd, driver->user, driver->group) < 0)) {
                virReportSystemError(errno,
                                     _("cannot chown '%s' to (%u, %u)"),
                                     res->disks[0].path,
                                     (unsigned int) driver->user,
                                     (unsigned int) driver->group);
                goto error_unlink;
            }

            if ((rv = sanlock_align(&res->disks[0])) < 0) {
                if (rv <= -200)
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to query sector size %s: error %d"),
                                   res->disks[0].path, rv);
                else
                    virReportSystemError(-rv,
                                         _("Unable to query sector size %s"),
                                         res->disks[0].path);
                goto error_unlink;
            }

            /*
             * Pre allocate enough data for 1 block of leases at preferred alignment
             */
            if (safezero(fd, 0, rv) < 0) {
                virReportSystemError(errno,
                                     _("Unable to allocate lease %s"),
                                     res->disks[0].path);
                goto error_unlink;
            }

            if (VIR_CLOSE(fd) < 0) {
                virReportSystemError(errno,
                                     _("Unable to save lease %s"),
                                     res->disks[0].path);
                goto error_unlink;
            }

            if ((rv = sanlock_init(NULL, res, 0, 0)) < 0) {
                if (rv <= -200)
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Unable to initialize lease %s: error %d"),
                                   res->disks[0].path, rv);
                else
                    virReportSystemError(-rv,
                                         _("Unable to initialize lease %s"),
                                         res->disks[0].path);
                goto error_unlink;
            }
            VIR_DEBUG("Lease %s has been initialized", res->disks[0].path);
        }
    }

    return 0;

error_unlink:
    unlink(res->disks[0].path);
    VIR_FORCE_CLOSE(fd);
    return -1;
}