static int xenFormatXLDiskSrc(virStorageSourcePtr src, char **srcstr) { int actualType = virStorageSourceGetActualType(src); *srcstr = NULL; if (virStorageSourceIsEmpty(src)) return 0; switch ((virStorageType) actualType) { case VIR_STORAGE_TYPE_BLOCK: case VIR_STORAGE_TYPE_FILE: case VIR_STORAGE_TYPE_DIR: if (VIR_STRDUP(*srcstr, src->path) < 0) return -1; break; case VIR_STORAGE_TYPE_NETWORK: if (!(*srcstr = xenFormatXLDiskSrcNet(src))) return -1; break; case VIR_STORAGE_TYPE_VOLUME: case VIR_STORAGE_TYPE_NONE: case VIR_STORAGE_TYPE_LAST: break; } return 0; }
/** * qemuBlockJobEmitEvents: * * Emits the VIR_DOMAIN_EVENT_ID_BLOCK_JOB and VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2 * for a block job. The former event is emitted only for local disks. */ static void qemuBlockJobEmitEvents(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainDiskDefPtr disk, virDomainBlockJobType type, virConnectDomainEventBlockJobStatus status) { virObjectEventPtr event = NULL; virObjectEventPtr event2 = NULL; /* don't emit events for internal jobs and states */ if (type >= VIR_DOMAIN_BLOCK_JOB_TYPE_LAST || status >= VIR_DOMAIN_BLOCK_JOB_LAST) return; if (virStorageSourceIsLocalStorage(disk->src) && !virStorageSourceIsEmpty(disk->src)) { event = virDomainEventBlockJobNewFromObj(vm, virDomainDiskGetSource(disk), type, status); virObjectEventStateQueue(driver->domainEventState, event); } event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type, status); virObjectEventStateQueue(driver->domainEventState, event2); }
/* 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; size_t i; int ndisks; 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))) 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 (virBitmapIsBitSet(map, idx)) { 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->src->path && disk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("file '%s' for disk '%s' requires " "use of external snapshot mode"), disk->src->path, disk->name); goto cleanup; } if (STRNEQ(disk->name, def->dom->disks[idx]->dst)) { VIR_FREE(disk->name); if (VIR_STRDUP(disk->name, def->dom->disks[idx]->dst) < 0) 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) goto cleanup; for (i = 0; i < def->dom->ndisks; i++) { virDomainSnapshotDiskDefPtr disk; if (virBitmapIsBitSet(map, i)) continue; disk = &def->disks[ndisks++]; if (VIR_ALLOC(disk->src) < 0) goto cleanup; if (VIR_STRDUP(disk->name, def->dom->disks[i]->dst) < 0) goto cleanup; disk->index = i; /* Don't snapshot empty drives */ if (virStorageSourceIsEmpty(def->dom->disks[i]->src)) disk->snapshot = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE; else disk->snapshot = def->dom->disks[i]->snapshot; disk->src->type = VIR_STORAGE_TYPE_FILE; 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->src->path) { const char *original = virDomainDiskGetSource(def->dom->disks[i]); const char *tmp; struct stat sb; if (disk->src->type != VIR_STORAGE_TYPE_FILE) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("cannot generate external snapshot name " "for disk '%s' on a '%s' device"), disk->name, virStorageTypeToString(disk->src->type)); goto cleanup; } 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, '/')) { if (virAsprintf(&disk->src->path, "%s.%s", original, def->name) < 0) goto cleanup; } else { if ((tmp - original) > INT_MAX) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("integer overflow")); goto cleanup; } if (virAsprintf(&disk->src->path, "%.*s.%s", (int) (tmp - original), original, def->name) < 0) goto cleanup; } } } ret = 0; cleanup: virBitmapFree(map); return ret; }