static int lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties) { VIR_AUTOFREE(char *) value = NULL; virBitmapPtr nodeset = NULL; if (virConfGetValueString(properties, "lxc.cgroup.cpuset.cpus", &value) > 0) { if (virBitmapParse(value, &def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) return -1; def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC; VIR_FREE(value); } if (virConfGetValueString(properties, "lxc.cgroup.cpuset.mems", &value) > 0) { if (virBitmapParse(value, &nodeset, VIR_DOMAIN_CPUMASK_LEN) < 0) return -1; if (virDomainNumatuneSet(def->numa, def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC, VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC, VIR_DOMAIN_NUMATUNE_MEM_STRICT, nodeset) < 0) { virBitmapFree(nodeset); return -1; } virBitmapFree(nodeset); } return 0; }
static int lxcSetCpusetTune(virDomainDefPtr def, virConfPtr properties) { virConfValuePtr value; virBitmapPtr nodeset = NULL; if ((value = virConfGetValue(properties, "lxc.cgroup.cpuset.cpus")) && value->str) { if (virBitmapParse(value->str, 0, &def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) return -1; def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC; } if ((value = virConfGetValue(properties, "lxc.cgroup.cpuset.mems")) && value->str) { if (virBitmapParse(value->str, 0, &nodeset, VIR_DOMAIN_CPUMASK_LEN) < 0) return -1; if (virDomainNumatuneSet(def->numa, def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC, VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC, VIR_DOMAIN_NUMATUNE_MEM_STRICT, nodeset) < 0) { virBitmapFree(nodeset); return -1; } virBitmapFree(nodeset); } return 0; }
void virDomainNumatuneFree(virDomainNumatunePtr numatune) { size_t i = 0; if (!numatune) return; virBitmapFree(numatune->memory.nodeset); for (i = 0; i < numatune->nmem_nodes; i++) virBitmapFree(numatune->mem_nodes[i].nodeset); VIR_FREE(numatune->mem_nodes); VIR_FREE(numatune); }
static void virPortAllocatorDispose(void *obj) { virPortAllocatorPtr pa = obj; virBitmapFree(pa->bitmap); }
/* * Linux maintains cpu bit map. For example, if cpuid=5's flag is not set * and max cpu is 7. The map file shows 0-4,6-7. This function parses * it and returns cpumap. */ static virBitmapPtr linuxParseCPUmap(int *max_cpuid, const char *path) { virBitmapPtr map = NULL; char *str = NULL; int max_id = 0, i; if (virFileReadAll(path, 5 * VIR_DOMAIN_CPUMASK_LEN, &str) < 0) { virReportOOMError(); goto error; } if (virBitmapParse(str, 0, &map, VIR_DOMAIN_CPUMASK_LEN) < 0) { goto error; } i = -1; while ((i = virBitmapNextSetBit(map, i)) >= 0) { max_id = i; } *max_cpuid = max_id; VIR_FREE(str); return map; error: VIR_FREE(str); virBitmapFree(map); return NULL; }
int virQEMUBuildCommandLineJSONArrayBitmap(const char *key, virJSONValuePtr array, virBufferPtr buf) { ssize_t pos = -1; ssize_t end; virBitmapPtr bitmap = NULL; if (virJSONValueGetArrayAsBitmap(array, &bitmap) < 0) return -1; while ((pos = virBitmapNextSetBit(bitmap, pos)) > -1) { if ((end = virBitmapNextClearBit(bitmap, pos)) < 0) end = virBitmapLastSetBit(bitmap) + 1; if (end - 1 > pos) { virBufferAsprintf(buf, "%s=%zd-%zd,", key, pos, end - 1); pos = end; } else { virBufferAsprintf(buf, "%s=%zd,", key, pos); } } virBitmapFree(bitmap); return 0; }
/* Check whether the host subcore configuration is valid. * * A valid configuration is one where no secondary thread is online; * the primary thread in a subcore is always the first one */ static bool virHostCPUHasValidSubcoreConfiguration(int threads_per_subcore) { virBitmapPtr online_cpus = NULL; int cpu = -1; bool ret = false; /* No point in checking if subcores are not in use */ if (threads_per_subcore <= 0) goto cleanup; if (!(online_cpus = virHostCPUGetOnlineBitmap())) goto cleanup; while ((cpu = virBitmapNextSetBit(online_cpus, cpu)) >= 0) { /* A single online secondary thread is enough to * make the configuration invalid */ if (cpu % threads_per_subcore != 0) goto cleanup; } ret = true; cleanup: virBitmapFree(online_cpus); return ret; }
static void dnsmasqCapsDispose(void *obj) { dnsmasqCapsPtr caps = obj; virBitmapFree(caps->flags); VIR_FREE(caps->binaryPath); }
void virDomainNumaFree(virDomainNumaPtr numa) { size_t i = 0; if (!numa) return; virBitmapFree(numa->memory.nodeset); for (i = 0; i < numa->nmem_nodes; i++) { virBitmapFree(numa->mem_nodes[i].cpumask); virBitmapFree(numa->mem_nodes[i].nodeset); } VIR_FREE(numa->mem_nodes); VIR_FREE(numa); }
static void virDomainVirtioSerialControllerFree(virDomainVirtioSerialControllerPtr cont) { if (cont) { virBitmapFree(cont->ports); VIR_FREE(cont); } }
int virNumaGetNodeCPUs(int node, virBitmapPtr *cpus) { unsigned long *mask = NULL; unsigned long *allonesmask = NULL; virBitmapPtr cpumap = NULL; int ncpus = 0; int max_n_cpus = virNumaGetMaxCPUs(); int mask_n_bytes = max_n_cpus / 8; size_t i; int ret = -1; *cpus = NULL; if (VIR_ALLOC_N(mask, mask_n_bytes / sizeof(*mask)) < 0) goto cleanup; if (VIR_ALLOC_N(allonesmask, mask_n_bytes / sizeof(*mask)) < 0) goto cleanup; memset(allonesmask, 0xff, mask_n_bytes); /* The first time this returns -1, ENOENT if node doesn't exist... */ if (numa_node_to_cpus(node, mask, mask_n_bytes) < 0) { VIR_WARN("NUMA topology for cell %d is not available, ignoring", node); ret = -2; goto cleanup; } /* second, third... times it returns an all-1's mask */ if (memcmp(mask, allonesmask, mask_n_bytes) == 0) { VIR_DEBUG("NUMA topology for cell %d is invalid, ignoring", node); ret = -2; goto cleanup; } if (!(cpumap = virBitmapNew(max_n_cpus))) goto cleanup; for (i = 0; i < max_n_cpus; i++) { if (MASK_CPU_ISSET(mask, i)) { ignore_value(virBitmapSetBit(cpumap, i)); ncpus++; } } *cpus = cpumap; cpumap = NULL; ret = ncpus; cleanup: VIR_FREE(mask); VIR_FREE(allonesmask); virBitmapFree(cpumap); return ret; }
/* * To be run while still single threaded */ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) { int hostcpus, maxcpu = CPU_SETSIZE; virNodeInfo nodeinfo; virBitmapPtr cpumap, cpumapToSet; VIR_DEBUG("Setting CPU affinity"); if (nodeGetInfo(NULL, &nodeinfo) < 0) return -1; /* setaffinity fails if you set bits for CPUs which * aren't present, so we have to limit ourselves */ hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo); if (maxcpu > hostcpus) maxcpu = hostcpus; cpumap = virBitmapNew(maxcpu); if (!cpumap) return -1; cpumapToSet = cpumap; if (ctrl->def->cpumask) { cpumapToSet = ctrl->def->cpumask; } else { /* You may think this is redundant, but we can't assume libvirtd * itself is running on all pCPUs, so we need to explicitly set * the spawned LXC instance to all pCPUs if no map is given in * its config file */ virBitmapSetAll(cpumap); } /* We are presuming we are running between fork/exec of LXC * so use '0' to indicate our own process ID. No threads are * running at this point */ if (virProcessInfoSetAffinity(0 /* Self */, cpumapToSet) < 0) { virBitmapFree(cpumap); return -1; } virBitmapFree(cpumap); return 0; }
bool virNumaNodeIsAvailable(int node) { bool ret = false; virBitmapPtr map = NULL; if (virFileReadValueBitmap(&map, "%s/node/online", SYSFS_SYSTEM_PATH) < 0) return false; ret = virBitmapIsBitSet(map, node); virBitmapFree(map); return ret; }
int virNumaGetMaxNode(void) { int ret = -1; virBitmapPtr map = NULL; if (virFileReadValueBitmap(&map, "%s/node/online", SYSFS_SYSTEM_PATH) < 0) return -1; ret = virBitmapLastSetBit(map); virBitmapFree(map); return ret; }
/** * virBitmapNewCopy: * @src: the source bitmap. * * Makes a copy of bitmap @src. * * returns the copied bitmap on success, or NULL otherwise. Caller * should call virBitmapFree to free the returned bitmap. */ virBitmapPtr virBitmapNewCopy(virBitmapPtr src) { virBitmapPtr dst; if ((dst = virBitmapNew(src->max_bit)) == NULL) return NULL; if (virBitmapCopy(dst, src) != 0) { virBitmapFree(dst); return NULL; } return dst; }
void virCapabilitiesClearHostNUMACellCPUTopology(virCapsHostNUMACellCPUPtr cpus, size_t ncpus) { size_t i; if (!cpus) return; for (i = 0; i < ncpus; i++) { virBitmapFree(cpus[i].siblings); cpus[i].siblings = NULL; } }
static int nodeDeviceUpdateCaps(virNodeDeviceDefPtr def) { virNodeDevCapsDefPtr cap = def->caps; while (cap) { switch (cap->data.type) { case VIR_NODE_DEV_CAP_SCSI_HOST: nodeDeviceSysfsGetSCSIHostCaps(&cap->data.scsi_host); break; case VIR_NODE_DEV_CAP_SCSI_TARGET: nodeDeviceSysfsGetSCSITargetCaps(def->sysfs_path, &cap->data.scsi_target); break; case VIR_NODE_DEV_CAP_NET: if (virNetDevGetLinkInfo(cap->data.net.ifname, &cap->data.net.lnk) < 0) return -1; virBitmapFree(cap->data.net.features); if (virNetDevGetFeatures(cap->data.net.ifname, &cap->data.net.features) < 0) return -1; break; case VIR_NODE_DEV_CAP_PCI_DEV: if (nodeDeviceSysfsGetPCIRelatedDevCaps(def->sysfs_path, &cap->data.pci_dev) < 0) return -1; break; /* all types that (supposedly) don't require any updates * relative to what's in the cache. */ case VIR_NODE_DEV_CAP_DRM: case VIR_NODE_DEV_CAP_SYSTEM: case VIR_NODE_DEV_CAP_USB_DEV: case VIR_NODE_DEV_CAP_USB_INTERFACE: case VIR_NODE_DEV_CAP_SCSI: case VIR_NODE_DEV_CAP_STORAGE: case VIR_NODE_DEV_CAP_FC_HOST: case VIR_NODE_DEV_CAP_VPORTS: case VIR_NODE_DEV_CAP_SCSI_GENERIC: case VIR_NODE_DEV_CAP_MDEV_TYPES: case VIR_NODE_DEV_CAP_MDEV: case VIR_NODE_DEV_CAP_CCW_DEV: case VIR_NODE_DEV_CAP_LAST: break; } cap = cap->next; } return 0; }
void virCPUDefFree(virCPUDefPtr def) { unsigned int i; if (!def) return; VIR_FREE(def->arch); virCPUDefFreeModel(def); for (i = 0 ; i < def->ncells ; i++) { virBitmapFree(def->cells[i].cpumask); VIR_FREE(def->cells[i].cpustr); } VIR_FREE(def->cells); VIR_FREE(def); }
void virCPUDefFree(virCPUDefPtr def) { size_t i; if (!def) return; virCPUDefFreeModel(def); for (i = 0; i < def->ncells; i++) { virBitmapFree(def->cells[i].cpumask); VIR_FREE(def->cells[i].cpustr); } VIR_FREE(def->cells); VIR_FREE(def->vendor_id); VIR_FREE(def); }
/* * Linux maintains cpu bit map under cpu/online. For example, if * cpuid=5's flag is not set and max cpu is 7, the map file shows * 0-4,6-7. This function parses it and returns cpumap. */ static virBitmapPtr linuxParseCPUmap(int max_cpuid, const char *path) { virBitmapPtr map = NULL; char *str = NULL; if (virFileReadAll(path, 5 * VIR_DOMAIN_CPUMASK_LEN, &str) < 0) goto error; if (virBitmapParse(str, 0, &map, max_cpuid) < 0) goto error; VIR_FREE(str); return map; error: VIR_FREE(str); virBitmapFree(map); return NULL; }
/* * Linux maintains cpu bit map under cpu/online. For example, if * cpuid=5's flag is not set and max cpu is 7, the map file shows * 0-4,6-7. This function parses it and returns cpumap. */ static virBitmapPtr virHostCPUParseMapLinux(int max_cpuid, const char *path) { virBitmapPtr map = NULL; char *str = NULL; if (virFileReadAll(path, 5 * VIR_HOST_CPU_MASK_LEN, &str) < 0) goto error; if (virBitmapParse(str, 0, &map, max_cpuid) < 0) goto error; VIR_FREE(str); return map; error: VIR_FREE(str); virBitmapFree(map); return NULL; }
virBitmapPtr virCapabilitiesGetCpusForNodemask(virCapsPtr caps, virBitmapPtr nodemask) { virBitmapPtr ret = NULL; unsigned int maxcpu = virCapabilitiesGetHostMaxcpu(caps); ssize_t node = -1; if (!(ret = virBitmapNew(maxcpu + 1))) return NULL; while ((node = virBitmapNextSetBit(nodemask, node)) >= 0) { if (virCapabilitiesGetCpusForNode(caps, node, ret) < 0) { virBitmapFree(ret); return NULL; } } return ret; }
/** * qemuCgroupEmulatorAllNodesAllow: * @cgroup: domain cgroup pointer * @retData: filled with structure used to roll back the operation * * Allows all NUMA nodes for the qemu emulator thread temporarily. This is * necessary when hotplugging cpus since it requires memory allocated in the * DMA region. Afterwards the operation can be reverted by * qemuCgroupEmulatorAllNodesRestore. * * Returns 0 on success -1 on error */ int qemuCgroupEmulatorAllNodesAllow(virCgroupPtr cgroup, qemuCgroupEmulatorAllNodesDataPtr *retData) { qemuCgroupEmulatorAllNodesDataPtr data = NULL; char *all_nodes_str = NULL; virBitmapPtr all_nodes = NULL; int ret = -1; if (!virNumaIsAvailable() || !virCgroupHasController(cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) return 0; if (!(all_nodes = virNumaGetHostMemoryNodeset())) goto cleanup; if (!(all_nodes_str = virBitmapFormat(all_nodes))) goto cleanup; if (VIR_ALLOC(data) < 0) goto cleanup; if (virCgroupNewThread(cgroup, VIR_CGROUP_THREAD_EMULATOR, 0, false, &data->emulatorCgroup) < 0) goto cleanup; if (virCgroupGetCpusetMems(data->emulatorCgroup, &data->emulatorMemMask) < 0 || virCgroupSetCpusetMems(data->emulatorCgroup, all_nodes_str) < 0) goto cleanup; VIR_STEAL_PTR(*retData, data); ret = 0; cleanup: VIR_FREE(all_nodes_str); virBitmapFree(all_nodes); qemuCgroupEmulatorAllNodesDataFree(data); return ret; }
/** * virBitmapParse: * @str: points to a string representing a human-readable bitmap * @terminator: character separating the bitmap to parse * @bitmap: a bitmap created from @str * @bitmapSize: the upper limit of num of bits in created bitmap * * This function is the counterpart of virBitmapFormat. This function creates * a bitmap, in which bits are set according to the content of @str. * * @str is a comma separated string of fields N, which means a number of bit * to set, and ^N, which means to unset the bit, and N-M for ranges of bits * to set. * * To allow parsing of bitmaps within larger strings it is possible to set * a termination character in the argument @terminator. When the character * in @terminator is encountered in @str, the parsing of the bitmap stops. * Pass 0 as @terminator if it is not needed. Whitespace characters may not * be used as terminators. * * Returns the number of bits set in @bitmap, or -1 in case of error. */ int virBitmapParse(const char *str, char terminator, virBitmapPtr *bitmap, size_t bitmapSize) { bool neg = false; const char *cur = str; char *tmp; size_t i; int start, last; if (!(*bitmap = virBitmapNew(bitmapSize))) return -1; if (!str) goto error; virSkipSpaces(&cur); if (*cur == '\0') goto error; while (*cur != 0 && *cur != terminator) { /* * 3 constructs are allowed: * - N : a single CPU number * - N-M : a range of CPU numbers with N < M * - ^N : remove a single CPU number from the current set */ if (*cur == '^') { cur++; neg = true; } if (!c_isdigit(*cur)) goto error; if (virStrToLong_i(cur, &tmp, 10, &start) < 0) goto error; if (start < 0) goto error; cur = tmp; virSkipSpaces(&cur); if (*cur == ',' || *cur == 0 || *cur == terminator) { if (neg) { if (virBitmapClearBit(*bitmap, start) < 0) goto error; } else { if (virBitmapSetBit(*bitmap, start) < 0) goto error; } } else if (*cur == '-') { if (neg) goto error; cur++; virSkipSpaces(&cur); if (virStrToLong_i(cur, &tmp, 10, &last) < 0) goto error; if (last < start) goto error; cur = tmp; for (i = start; i <= last; i++) { if (virBitmapSetBit(*bitmap, i) < 0) goto error; } virSkipSpaces(&cur); } if (*cur == ',') { cur++; virSkipSpaces(&cur); neg = false; } else if (*cur == 0 || *cur == terminator) { break; } else { goto error; } } if (virBitmapIsAllClear(*bitmap)) goto error; return virBitmapCountBits(*bitmap); error: virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse bitmap '%s'"), str); virBitmapFree(*bitmap); *bitmap = NULL; return -1; }
int virDomainNumatuneSet(virDomainNumaPtr numa, bool placement_static, int placement, int mode, virBitmapPtr nodeset) { int ret = -1; /* No need to do anything in this case */ if (mode == -1 && placement == -1 && !nodeset) return 0; if (!numa->memory.specified) { if (mode == -1) mode = VIR_DOMAIN_NUMATUNE_MEM_STRICT; if (placement == -1) placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_DEFAULT; } /* Range checks */ if (mode != -1 && (mode < 0 || mode >= VIR_DOMAIN_NUMATUNE_MEM_LAST)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported numatune mode '%d'"), mode); goto cleanup; } if (placement != -1 && (placement < 0 || placement >= VIR_DOMAIN_NUMATUNE_PLACEMENT_LAST)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported numatune placement '%d'"), mode); goto cleanup; } if (mode != -1) numa->memory.mode = mode; if (nodeset) { virBitmapFree(numa->memory.nodeset); if (!(numa->memory.nodeset = virBitmapNewCopy(nodeset))) goto cleanup; if (placement == -1) placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC; } if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_DEFAULT) { if (numa->memory.nodeset || placement_static) placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC; else placement = VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO; } if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_STATIC && !numa->memory.nodeset) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("nodeset for NUMA memory tuning must be set " "if 'placement' is 'static'")); goto cleanup; } /* setting nodeset when placement auto is invalid */ if (placement == VIR_DOMAIN_NUMATUNE_PLACEMENT_AUTO && numa->memory.nodeset) { virBitmapFree(numa->memory.nodeset); numa->memory.nodeset = NULL; } if (placement != -1) numa->memory.placement = placement; numa->memory.specified = true; ret = 0; cleanup: return ret; }
/* Align def->disks to def->domain. Sort the list of def->disks, * filling in any missing disks or snapshot state defaults given by * the domain, with a fallback to a passed in default. Convert paths * to disk targets for uniformity. Issue an error and return -1 if * any def->disks[n]->name appears more than once or does not map to * dom->disks. If require_match, also ensure that there is no * conflicting requests for both internal and external snapshots. */ int virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def, int default_snapshot, bool require_match) { int ret = -1; virBitmapPtr map = NULL; int i; int ndisks; bool inuse; if (!def->dom) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing domain in snapshot")); goto cleanup; } if (def->ndisks > def->dom->ndisks) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("too many disk snapshot requests for domain")); goto cleanup; } /* Unlikely to have a guest without disks but technically possible. */ if (!def->dom->ndisks) { ret = 0; goto cleanup; } if (!(map = virBitmapNew(def->dom->ndisks))) { virReportOOMError(); goto cleanup; } /* Double check requested disks. */ for (i = 0; i < def->ndisks; i++) { virDomainSnapshotDiskDefPtr disk = &def->disks[i]; int idx = virDomainDiskIndexByName(def->dom, disk->name, false); int disk_snapshot; if (idx < 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("no disk named '%s'"), disk->name); goto cleanup; } if (virBitmapGetBit(map, idx, &inuse) < 0 || inuse) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("disk '%s' specified twice"), disk->name); goto cleanup; } ignore_value(virBitmapSetBit(map, idx)); disk->index = idx; disk_snapshot = def->dom->disks[idx]->snapshot; if (!disk->snapshot) { if (disk_snapshot && (!require_match || disk_snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)) disk->snapshot = disk_snapshot; else disk->snapshot = default_snapshot; } else if (require_match && disk->snapshot != default_snapshot && !(disk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE && disk_snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)) { const char *tmp; tmp = virDomainSnapshotLocationTypeToString(default_snapshot); virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("disk '%s' must use snapshot mode '%s'"), disk->name, tmp); goto cleanup; } if (disk->file && disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("file '%s' for disk '%s' requires " "use of external snapshot mode"), disk->file, disk->name); goto cleanup; } if (STRNEQ(disk->name, def->dom->disks[idx]->dst)) { VIR_FREE(disk->name); if (!(disk->name = strdup(def->dom->disks[idx]->dst))) { virReportOOMError(); goto cleanup; } } } /* Provide defaults for all remaining disks. */ ndisks = def->ndisks; if (VIR_EXPAND_N(def->disks, def->ndisks, def->dom->ndisks - def->ndisks) < 0) { virReportOOMError(); goto cleanup; } for (i = 0; i < def->dom->ndisks; i++) { virDomainSnapshotDiskDefPtr disk; ignore_value(virBitmapGetBit(map, i, &inuse)); if (inuse) continue; disk = &def->disks[ndisks++]; if (!(disk->name = strdup(def->dom->disks[i]->dst))) { virReportOOMError(); goto cleanup; } disk->index = i; disk->snapshot = def->dom->disks[i]->snapshot; if (!disk->snapshot) disk->snapshot = default_snapshot; } qsort(&def->disks[0], def->ndisks, sizeof(def->disks[0]), disksorter); /* Generate any default external file names, but only if the * backing file is a regular file. */ for (i = 0; i < def->ndisks; i++) { virDomainSnapshotDiskDefPtr disk = &def->disks[i]; if (disk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL && !disk->file) { const char *original = def->dom->disks[i]->src; const char *tmp; struct stat sb; if (!original) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("cannot generate external snapshot name " "for disk '%s' without source"), disk->name); goto cleanup; } if (stat(original, &sb) < 0 || !S_ISREG(sb.st_mode)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("source for disk '%s' is not a regular " "file; refusing to generate external " "snapshot name"), disk->name); goto cleanup; } tmp = strrchr(original, '.'); if (!tmp || strchr(tmp, '/')) { ignore_value(virAsprintf(&disk->file, "%s.%s", original, def->name)); } else { if ((tmp - original) > INT_MAX) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("integer overflow")); goto cleanup; } ignore_value(virAsprintf(&disk->file, "%.*s.%s", (int) (tmp - original), original, def->name)); } if (!disk->file) { virReportOOMError(); goto cleanup; } } } ret = 0; cleanup: virBitmapFree(map); return ret; }
int virBitmapParse(const char *str, char sep, virBitmapPtr *bitmap, size_t bitmapSize) { int ret = 0; bool neg = false; const char *cur; char *tmp; int i, start, last; if (!str) return -1; cur = str; virSkipSpaces(&cur); if (*cur == 0) return -1; *bitmap = virBitmapNew(bitmapSize); if (!*bitmap) return -1; while (*cur != 0 && *cur != sep) { /* * 3 constructs are allowed: * - N : a single CPU number * - N-M : a range of CPU numbers with N < M * - ^N : remove a single CPU number from the current set */ if (*cur == '^') { cur++; neg = true; } if (!c_isdigit(*cur)) goto parse_error; if (virStrToLong_i(cur, &tmp, 10, &start) < 0) goto parse_error; if (start < 0) goto parse_error; cur = tmp; virSkipSpaces(&cur); if (*cur == ',' || *cur == 0 || *cur == sep) { if (neg) { if (virBitmapIsSet(*bitmap, start)) { ignore_value(virBitmapClearBit(*bitmap, start)); ret--; } } else { if (!virBitmapIsSet(*bitmap, start)) { ignore_value(virBitmapSetBit(*bitmap, start)); ret++; } } } else if (*cur == '-') { if (neg) goto parse_error; cur++; virSkipSpaces(&cur); if (virStrToLong_i(cur, &tmp, 10, &last) < 0) goto parse_error; if (last < start) goto parse_error; cur = tmp; for (i = start; i <= last; i++) { if (!virBitmapIsSet(*bitmap, i)) { ignore_value(virBitmapSetBit(*bitmap, i)); ret++; } } virSkipSpaces(&cur); } if (*cur == ',') { cur++; virSkipSpaces(&cur); neg = false; } else if(*cur == 0 || *cur == sep) { break; } else { goto parse_error; } } return ret; parse_error: virBitmapFree(*bitmap); *bitmap = NULL; return -1; }
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; }
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, backingStore, backingStoreFormat))) { ret = -1; goto error; } } VIR_FORCE_CLOSE(fd); if (meta && *backingStore && *backingStoreFormat == VIR_STORAGE_FILE_AUTO && virStorageIsFile(*backingStore)) { 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 { 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; }
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; }