MFV r337184: 9457 libzfs_import.c:add_config() has a memory leak

A memory leak occurs on lines 209 and 213 because the config is not freed
in the error case.  The interface to add_config() seems less than ideal -
it would be better if it copied any data necessary from the config and the
caller freed it.

illumos/illumos-gate@ddfe901b12

Reviewed by: Matt Ahrens <matt@delphix.com>
Reviewed by: Serapheim Dimitropoulos <serapheim.dimitro@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Author:     sara hartse <sara.hartse@delphix.com>
This commit is contained in:
Alexander Motin 2018-08-02 21:25:32 +00:00
commit d49e9be14f

View file

@ -33,7 +33,7 @@
* ZFS label of each device. If we successfully read the label, then we
* organize the configuration information in the following hierarchy:
*
* pool guid -> toplevel vdev guid -> label txg
* pool guid -> toplevel vdev guid -> label txg
*
* Duplicate entries matching this same tuple will be discarded. Once we have
* examined every device, we pick the best label txg config for each toplevel
@ -245,7 +245,6 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
ne->ne_next = pl->names;
pl->names = ne;
nvlist_free(config);
return (0);
}
@ -265,7 +264,6 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
&top_guid) != 0 ||
nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
&txg) != 0 || txg == 0) {
nvlist_free(config);
return (0);
}
@ -280,7 +278,6 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
if (pe == NULL) {
if ((pe = zfs_alloc(hdl, sizeof (pool_entry_t))) == NULL) {
nvlist_free(config);
return (-1);
}
pe->pe_guid = pool_guid;
@ -299,7 +296,6 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
if (ve == NULL) {
if ((ve = zfs_alloc(hdl, sizeof (vdev_entry_t))) == NULL) {
nvlist_free(config);
return (-1);
}
ve->ve_guid = top_guid;
@ -319,15 +315,12 @@ add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
if (ce == NULL) {
if ((ce = zfs_alloc(hdl, sizeof (config_entry_t))) == NULL) {
nvlist_free(config);
return (-1);
}
ce->ce_txg = txg;
ce->ce_config = config;
ce->ce_config = fnvlist_dup(config);
ce->ce_next = ve->ve_configs;
ve->ve_configs = ce;
} else {
nvlist_free(config);
}
/*
@ -1396,9 +1389,7 @@ skipdir:
&this_guid) == 0 &&
iarg->guid == this_guid;
}
if (!matched) {
nvlist_free(config);
} else {
if (matched) {
/*
* use the non-raw path for the config
*/
@ -1408,6 +1399,7 @@ skipdir:
config) != 0)
config_failed = B_TRUE;
}
nvlist_free(config);
}
free(slice->rn_name);
free(slice);