[PATCH V4] DevicePool, reimplement get_diskpool_config with libvirt

Original implemetion may return pools with NULL name if some pool disappear between two libvirt pool API call. And caller of this function consider number = 0 as error only but it original return negative value when error before. This patch fix it. V2: Use for instead of while in clean up. Treat zero pool returned from libvirt as normal instead of error. Rebased. v3: fix wrong i++ in for while. v4: changed the function prototype to return negative when error, not return the pool number anymore. In this way code of caller and function in no-use-libvirt-pool case were also changed. Return false in get_disk_parent() when strdup fail. Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- src/Virt_DevicePool.c | 176 +++++++++++++++++++++++++++++++++--------------- 1 files changed, 121 insertions(+), 55 deletions(-) diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index 79dc108..bf3dd3b 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -51,6 +51,21 @@ struct tmp_disk_pool { bool primordial; }; +static void free_diskpool(struct tmp_disk_pool *pools, int count) +{ + int i; + + if (pools == NULL) + return; + + for (i = 0; i < count; i++) { + free(pools[i].tag); + free(pools[i].path); + } + + free(pools); +} + /* * Right now, detect support and use it, if available. * Later, this can be a configure option if needed @@ -78,6 +93,10 @@ static bool get_disk_parent(struct tmp_disk_pool **_pools, } pools[count].tag = strdup("0"); + if (pools[count].tag == NULL) { + count++; + goto free; + } pools[count].path = NULL; pools[count].primordial = true; count++; @@ -85,12 +104,17 @@ static bool get_disk_parent(struct tmp_disk_pool **_pools, *_count = count; *_pools = pools; ret = true; + goto out; + free: + free_diskpool(pools, count); + /* old pool is invalid, update it */ + *_count = 0; + *_pools = NULL; out: return ret; } - #if VIR_USE_LIBVIRT_STORAGE int get_disk_pool(virStoragePoolPtr poolptr, struct virt_pool **pool) { @@ -117,52 +141,85 @@ int get_disk_pool(virStoragePoolPtr poolptr, struct virt_pool **pool) return ret; } +/* This function returns 0 on sucess, negative on fail. */ static int get_diskpool_config(virConnectPtr conn, - struct tmp_disk_pool **_pools) + struct tmp_disk_pool **_pools, + int *_count) { - int count = 0; + int count = 0, realcount = 0; int i; char ** names = NULL; struct tmp_disk_pool *pools = NULL; + int ret = 0; + bool bret; count = virConnectNumOfStoragePools(conn); - if (count <= 0) + if (count < 0) { + ret = count; goto out; + } else if (count == 0) { + goto set_parent; + } names = calloc(count, sizeof(char *)); if (names == NULL) { CU_DEBUG("Failed to alloc space for %i pool names", count); - count = 0; + ret = -1; goto out; } - if (virConnectListStoragePools(conn, names, count) == -1) { - CU_DEBUG("Failed to get storage pools"); - count = 0; - goto out; + realcount = virConnectListStoragePools(conn, names, count); + if (realcount < 0) { + CU_DEBUG("Failed to get storage pools, return %d.", realcount); + ret = realcount; + goto free_names; + } + if (realcount == 0) { + CU_DEBUG("Zero pools got, but prelist is %d.", count); + goto set_parent; } - pools = calloc(count, sizeof(*pools)); + pools = calloc(realcount, sizeof(*pools)); if (pools == NULL) { - CU_DEBUG("Failed to alloc space for %i pool structs", count); - goto out; + CU_DEBUG("Failed to alloc space for %i pool structs", realcount); + ret = -2; + goto free_names; } - for (i = 0; i < count; i++) { + for (i = 0; i < realcount; i++) { pools[i].tag = strdup(names[i]); + if (pools[i].tag == NULL) { + CU_DEBUG("Failed in strdup for name '%s'.", names[i]); + ret = -3; + goto free_pools; + } pools[i].primordial = false; } - out: - for (i = 0; i < count; i++) - free(names[i]); - free(names); - - get_disk_parent(&pools, &count); + set_parent: + bret = get_disk_parent(&pools, &realcount); + if (bret != true) { + CU_DEBUG("Failed in adding parentpool."); + ret = -4; + goto free_pools; + } + /* succeed */ *_pools = pools; + *_count = realcount; + goto free_names; + + free_pools: + free_diskpool(pools, realcount); - return count; + free_names: + for (i = 0; i < count; i++) { + free(names[i]); + } + free(names); + + out: + return ret; } static bool diskpool_set_capacity(virConnectPtr conn, @@ -294,42 +351,59 @@ static int parse_diskpool_line(struct tmp_disk_pool *pool, return (ret == 2); } +/* return 0 on sucess, negative on fail. */ static int get_diskpool_config(virConnectPtr conn, - struct tmp_disk_pool **_pools) + struct tmp_disk_pool **_pools, + int *_count) { const char *path = DISK_POOL_CONFIG; FILE *config; char *line = NULL; size_t len = 0; - int count = 0; - struct tmp_disk_pool *pools = NULL; + int count = 0, ret = 0; + struct tmp_disk_pool *pools = NULL, *new_pools = NULL; + bool bret; config = fopen(path, "r"); if (config == NULL) { CU_DEBUG("Failed to open %s: %m", path); - return 0; + ret = -1; + goto out; } while (getline(&line, &len, config) > 0) { - pools = realloc(pools, - (count + 1) * (sizeof(*pools))); - if (pools == NULL) { + new_pools = realloc(pools, + (count + 1) * (sizeof(*pools))); + if (new_pools == NULL) { CU_DEBUG("Failed to alloc new pool"); - goto out; + ret = -2; + goto free_pools; } + pools = new_pools; if (parse_diskpool_line(&pools[count], line)) count++; } + bret = get_disk_parent(&pools, &count); + if (bret != true) { + CU_DEBUG("Failed in adding parentpool."); + ret = -3; + goto free_pools; + } - get_disk_parent(&pools, &count); - out: - free(line); + /* succeed */ *_pools = pools; - fclose(config); + *_count = count; + goto clean; - return count; + free_pools: + free_diskpool(pools, count); + clean: + free(line); + fclose(config); + out: + return ret; } static bool diskpool_set_capacity(virConnectPtr conn, @@ -367,39 +441,23 @@ static bool diskpool_set_capacity(virConnectPtr conn, } static bool _diskpool_is_member(virConnectPtr conn, - const struct disk_pool *pool, + const struct tmp_disk_pool *pool, const char *file) { return STARTS_WITH(file, pool->path); } #endif -static void free_diskpool(struct tmp_disk_pool *pools, int count) -{ - int i; - - if (pools == NULL) - return; - - for (i = 0; i < count; i++) { - free(pools[i].tag); - free(pools[i].path); - } - - free(pools); -} - static char *_diskpool_member_of(virConnectPtr conn, const char *file) { struct tmp_disk_pool *pools = NULL; int count; - int i; + int i, ret; char *pool = NULL; - count = get_diskpool_config(conn, &pools); - if (count == 0) { - free(pools); + ret = get_diskpool_config(conn, &pools, &count); + if (ret < 0) { return NULL; } @@ -1084,9 +1142,17 @@ static CMPIStatus diskpool_instance(virConnectPtr conn, CMPIStatus s = {CMPI_RC_OK, NULL}; struct tmp_disk_pool *pools = NULL; int count = 0; - int i; + int i, ret; - count = get_diskpool_config(conn, &pools); + ret = get_diskpool_config(conn, &pools, &count); + if (ret < 0) { + CU_DEBUG("Failed to get diskpool config, return is %d.", ret); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get diskpool config, return is %d.", + ret); + return s; + } if ((id == NULL) && (count == 0)) { CU_DEBUG("No defined DiskPools"); free(pools); -- 1.7.1

If user delete a VS and enum VSSD at the sametime, it may have chance to report error, but actually it succeed just with some VS not found. Root cause is race condition between libvirt API for get domain's name&count and the API for get domain's xml. This Patch fixed it. It will continue if found one VS is missing in enum. v2: Rebased and better document. v3: Rebased. v4: changed CU_DEBUG information when met error in instance_from_dom(). Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- src/Virt_VSSD.c | 71 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/Virt_VSSD.c b/src/Virt_VSSD.c index 499b157..0781c8f 100644 --- a/src/Virt_VSSD.c +++ b/src/Virt_VSSD.c @@ -36,6 +36,8 @@ #include "Virt_VSSD.h" +#define VSSD_ERROR_RECOVERABLE (2) + const static CMPIBroker *_BROKER; static CMPIStatus _set_fv_prop(const CMPIBroker *broker, @@ -181,8 +183,18 @@ static int instance_from_dom(const CMPIBroker *broker, struct domain *dominfo = NULL; ret = get_dominfo(dom, &dominfo); - if (!ret) + if (!ret) { + int active = virDomainIsActive(dom); + if (active < 0) { + /* ret > 1 indicate that it is recoverable */ + CU_DEBUG("Failed to get dominfo, " + "domain may not be active anymore."); + ret = VSSD_ERROR_RECOVERABLE; + } else { + CU_DEBUG("Failed to get dominfo."); + } goto out; + } op = CMGetObjectPath(inst, NULL); pfx = class_prefix_name(CLASSNAME(op)); @@ -246,6 +258,8 @@ static int instance_from_dom(const CMPIBroker *broker, s = _set_fv_prop(broker, dominfo, inst); if (s.rc != CMPI_RC_OK) { ret = 0; + CU_DEBUG("Failed to set full virtual prop for %d dom.", + dominfo->type); goto out; } } @@ -260,6 +274,7 @@ static int instance_from_dom(const CMPIBroker *broker, if (asprintf(&vsid, "%s:%s", pfx, dominfo->name) == -1) { ret = 0; + CU_DEBUG("Failed in asprintf vsid."); goto out; } @@ -278,7 +293,8 @@ static CMPIInstance *_get_vssd(const CMPIBroker *broker, const CMPIObjectPath *reference, virConnectPtr conn, virDomainPtr dom, - CMPIStatus *s) + CMPIStatus *s, + int *error_below) { CMPIInstance *inst = NULL; @@ -294,10 +310,18 @@ static CMPIInstance *_get_vssd(const CMPIBroker *broker, goto out; } - if (instance_from_dom(broker, dom, inst) != 1) { - cu_statusf(broker, s, - CMPI_RC_ERR_FAILED, - "Unable to get VSSD instance from Domain"); + *error_below = instance_from_dom(broker, dom, inst); + if (*error_below != 1) { + if (*error_below == VSSD_ERROR_RECOVERABLE) { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to get VSSD instance from Domain, " + "Domain may not exist at this moment."); + } else { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to get VSSD instance from Domain"); + } } out: @@ -312,6 +336,7 @@ static CMPIStatus return_enum_vssd(const CMPIObjectPath *reference, virDomainPtr *list; int count; int i; + int error_below; CMPIStatus s = {CMPI_RC_OK, NULL}; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); @@ -327,14 +352,33 @@ static CMPIStatus return_enum_vssd(const CMPIObjectPath *reference, } else if (count == 0) goto out; + int fail_count = 0; for (i = 0; i < count; i++) { CMPIInstance *inst = NULL; - - inst = _get_vssd(_BROKER, reference, conn, list[i], &s); - + + inst = _get_vssd(_BROKER, reference, conn, list[i], + &s, &error_below); + virDomainFree(list[i]); - if (inst == NULL) - continue; + + if ((inst == NULL) || (s.rc != CMPI_RC_OK)) { + fail_count++; + CU_DEBUG("VSSD got %d fail instance, total %d," + " error %d.", + fail_count, count, error_below); + if (error_below == VSSD_ERROR_RECOVERABLE) { + cu_statusf(_BROKER, &s, + CMPI_RC_OK, + "%d/%d VSSD not got," + " some VS may not exist now", + fail_count, count); + CU_DEBUG("Continue to next VSSD for enum."); + continue; + } else { + CU_DEBUG("Met unrecoverable error."); + break; + } + } if (names_only) cu_return_instance_name(results, inst); @@ -358,7 +402,8 @@ CMPIStatus get_vssd_by_name(const CMPIBroker *broker, virDomainPtr dom; CMPIStatus s = {CMPI_RC_OK, NULL}; CMPIInstance *inst = NULL; - + int error_below; + conn = connect_by_classname(broker, CLASSNAME(reference), &s); if (conn == NULL) { cu_statusf(broker, &s, @@ -377,7 +422,7 @@ CMPIStatus get_vssd_by_name(const CMPIBroker *broker, goto out; } - inst = _get_vssd(broker, reference, conn, dom, &s); + inst = _get_vssd(broker, reference, conn, dom, &s, &error_below); virDomainFree(dom); -- 1.7.1
participants (1)
-
Wenchao Xia