diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c index 589f486fe7..6137278950 100644 --- a/src/storage/storage_backend_logical.c +++ b/src/storage/storage_backend_logical.c @@ -62,13 +62,22 @@ virStorageBackendLogicalSetActive(virStoragePoolObjPtr pool, } +#define VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED "striped" + static int virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool, char **const groups, void *data) { virStorageVolDefPtr vol = NULL; + bool is_new_vol = false; unsigned long long offset, size, length; + const char *regex_unit = "(\\S+)\\((\\S+)\\)"; + char *regex = NULL; + regex_t *reg = NULL; + regmatch_t *vars = NULL; + char *p = NULL; + int i, err, nextents, nvars, ret = -1; /* See if we're only looking for a specific volume */ if (data != NULL) { @@ -88,19 +97,18 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool, return -1; } + is_new_vol = true; vol->type = VIR_STORAGE_VOL_BLOCK; if ((vol->name = strdup(groups[0])) == NULL) { virReportOOMError(); - virStorageVolDefFree(vol); - return -1; + goto cleanup; } if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1)) { virReportOOMError(); - virStorageVolDefFree(vol); - return -1; + goto cleanup; } pool->volumes.objs[pool->volumes.count++] = vol; } @@ -109,8 +117,7 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool, if (virAsprintf(&vol->target.path, "%s/%s", pool->def->target.path, vol->name) < 0) { virReportOOMError(); - virStorageVolDefFree(vol); - return -1; + goto cleanup; } } @@ -118,8 +125,7 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool, if (virAsprintf(&vol->backingStore.path, "%s/%s", pool->def->target.path, groups[1]) < 0) { virReportOOMError(); - virStorageVolDefFree(vol); - return -1; + goto cleanup; } vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2; @@ -128,47 +134,127 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool, if (vol->key == NULL && (vol->key = strdup(groups[2])) == NULL) { virReportOOMError(); - return -1; + goto cleanup; } if (virStorageBackendUpdateVolInfo(vol, 1) < 0) - return -1; + goto cleanup; + nextents = 1; + if (STREQ(groups[4], VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED)) { + if (virStrToLong_i(groups[5], NULL, 10, &nextents) < 0) { + virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed volume extent stripes value")); + goto cleanup; + } + } /* Finally fill in extents information */ if (VIR_REALLOC_N(vol->source.extents, - vol->source.nextent + 1) < 0) { + vol->source.nextent + nextents) < 0) { virReportOOMError(); - return -1; + goto cleanup; } - if ((vol->source.extents[vol->source.nextent].path = - strdup(groups[3])) == NULL) { - virReportOOMError(); - return -1; - } - - if (virStrToLong_ull(groups[4], NULL, 10, &offset) < 0) { - virStorageReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("malformed volume extent offset value")); - return -1; - } - if (virStrToLong_ull(groups[5], NULL, 10, &length) < 0) { + if (virStrToLong_ull(groups[6], NULL, 10, &length) < 0) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed volume extent length value")); - return -1; + goto cleanup; } - if (virStrToLong_ull(groups[6], NULL, 10, &size) < 0) { + if (virStrToLong_ull(groups[7], NULL, 10, &size) < 0) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed volume extent size value")); - return -1; + goto cleanup; } - vol->source.extents[vol->source.nextent].start = offset * size; - vol->source.extents[vol->source.nextent].end = (offset * size) + length; - vol->source.nextent++; + /* Now parse the "devices" feild seperately */ + regex = strdup(regex_unit); - return 0; + for (i = 1; i < nextents; i++) { + if (VIR_REALLOC_N(regex, strlen(regex) + strlen(regex_unit) + 2) < 0) { + virReportOOMError(); + goto cleanup; + } + /* "," is the seperator of "devices" field */ + strcat(regex, ","); + strncat(regex, regex_unit, strlen(regex_unit)); + } + + if (VIR_ALLOC(reg) < 0) { + virReportOOMError(); + goto cleanup; + } + + /* Each extent has a "path:offset" pair, and vars[0] will + * be the whole matched string. + */ + nvars = (nextents * 2) + 1; + if (VIR_ALLOC_N(vars, nvars) < 0) { + virReportOOMError(); + goto cleanup; + } + + err = regcomp(reg, regex, REG_EXTENDED); + if (err != 0) { + char error[100]; + regerror(err, reg, error, sizeof(error)); + virStorageReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to compile regex %s"), + error); + goto cleanup; + } + + if (regexec(reg, groups[3], nvars, vars, 0) != 0) { + virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed volume extent devices value")); + goto cleanup; + } + + p = groups[3]; + + /* vars[0] is skipped */ + for (i = 0; i < nextents; i++) { + int j, len; + const char *offset_str = NULL; + + j = (i * 2) + 1; + len = vars[j].rm_eo - vars[j].rm_so; + p[vars[j].rm_eo] = '\0'; + + if ((vol->source.extents[vol->source.nextent].path = + strndup(p + vars[j].rm_so, len)) == NULL) { + virReportOOMError(); + goto cleanup; + } + + len = vars[j + 1].rm_eo - vars[j + 1].rm_so; + if (!(offset_str = strndup(p + vars[j + 1].rm_so, len))) { + virReportOOMError(); + goto cleanup; + } + + if (virStrToLong_ull(offset_str, NULL, 10, &offset) < 0) { + virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed volume extent offset value")); + goto cleanup; + } + + VIR_FREE(offset_str); + + vol->source.extents[vol->source.nextent].start = offset * size; + vol->source.extents[vol->source.nextent].end = (offset * size) + length; + vol->source.nextent++; + } + + ret = 0; + +cleanup: + VIR_FREE(regex); + VIR_FREE(reg); + VIR_FREE(vars); + if (is_new_vol && (ret == -1)) + virStorageVolDefFree(vol); + return ret; } static int @@ -191,17 +277,19 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool, * * NB Encrypted logical volumes can print ':' in their name, so it is * not a suitable separator (rhbz 470693). + * NB "devices" field has multiple device paths and "," if the volume is + * striped, so "," is not a suitable separator either (rhbz 727474). */ const char *regexes[] = { - "^\\s*(\\S+),(\\S*),(\\S+),(\\S+)\\((\\S+)\\),(\\S+),([0-9]+),?\\s*$" + "^\\s*(\\S+)#(\\S*)#(\\S+)#(\\S+)#(\\S+)#([0-9]+)#(\\S+)#([0-9]+)#?\\s*$" }; int vars[] = { - 7 + 8 }; const char *prog[] = { - LVS, "--separator", ",", "--noheadings", "--units", "b", + LVS, "--separator", "#", "--noheadings", "--units", "b", "--unbuffered", "--nosuffix", "--options", - "lv_name,origin,uuid,devices,seg_size,vg_extent_size", + "lv_name,origin,uuid,devices,segtype,stripes,seg_size,vg_extent_size", pool->def->source.name, NULL };