On Wed, Dec 16, 2020 at 06:34:05PM +0100, Martin Wilck wrote: > On Fri, 2020-10-16 at 12:44 +0200, mwilck@xxxxxxxx wrote: > > From: Martin Wilck <mwilck@xxxxxxxx> > > > > There were two leaks in check_path_valid(): if path status was > > successfully determined before calling store_pathvec(), free_path() > > wasn't called. Also, if an error exit occured, neither cleanup > > function was called. > > > > This patch fixes both, at the cost of using "static" for the pp and > > pathvec variables. > > Looking at this again after 2 months, I think the on_exit() part of > this patch is wrong. First, we can't use on_exit() on every platform, > as e.g. musl libc doesn't have it. To replace this by the more portable > atexit(), we'd need to declare the two variables "pp" and "pathvec" > with file scope, which is very ugly. But more importantly, using static > variables here causes check_path_valid() to be non-reentrant. While it > doesn't have to be, it's still a coding pattern we haven't been using > anywhere else, just to avoid a "memory leak" for an irregular exit, > which isn't a real memory leak, actually. A while ago, we had a conversation where we talked about not adding too much complexity to deal with issues on shutdown, that will just go away when multipathd stops. I still think that we shouldn't worry too much about making sure we always free everything when it will automatically get freed by the system anyway. -Ben > > One day we should remove the exit() calls somewhere deep down in our > libraries, and deal with the respective errors cleanly. > > @lixiaokeng, I hope this is ok for you, as you brought the issue up > originally ("[QUESTION] memory leak in main (multipath)"). > > Regards > Martin > > > > > Reviewed-by: Benjamin Marzinski <bmarzins@xxxxxxxxxx> > > Signed-off-by: Martin Wilck <mwilck@xxxxxxxx> > > --- > > multipath/main.c | 55 +++++++++++++++++++++++++++++++++++++--------- > > -- > > 1 file changed, 43 insertions(+), 12 deletions(-) > > > > diff --git a/multipath/main.c b/multipath/main.c > > index 049a36f..9974993 100644 > > --- a/multipath/main.c > > +++ b/multipath/main.c > > @@ -93,7 +93,7 @@ void rcu_register_thread_memb(void) {} > > void rcu_unregister_thread_memb(void) {} > > > > static int > > -filter_pathvec (vector pathvec, char * refwwid) > > +filter_pathvec (vector pathvec, const char *refwwid) > > { > > int i; > > struct path * pp; > > @@ -592,12 +592,37 @@ out: > > return r; > > } > > > > +static void cleanup_pathvec(__attribute__((unused)) int dummy, void > > *arg) > > +{ > > + vector *ppv = arg; > > + > > + if (ppv && *ppv) { > > + free_pathvec(*ppv, FREE_PATHS); > > + *ppv = NULL; > > + } > > +} > > + > > +static void cleanup_path(__attribute__((unused)) int dummy, void > > *arg) > > +{ > > + struct path **ppp = arg; > > + > > + if (ppp && *ppp) { > > + free_path(*ppp); > > + *ppp = NULL; > > + } > > +} > > + > > static int > > check_path_valid(const char *name, struct config *conf, bool > > is_uevent) > > { > > int fd, r = PATH_IS_ERROR; > > - struct path *pp = NULL; > > - vector pathvec = NULL; > > + static struct path *pp = NULL; > > + static vector pathvec = NULL; > > + const char *wwid; > > + > > + /* register these as exit handlers in case we exit irregularly > > */ > > + on_exit(cleanup_path, &pp); > > + on_exit(cleanup_pathvec, &pathvec); > > > > pp = alloc_path(); > > if (!pp) > > @@ -667,13 +692,17 @@ check_path_valid(const char *name, struct > > config *conf, bool is_uevent) > > if (store_path(pathvec, pp) != 0) { > > free_path(pp); > > goto fail; > > + } else { > > + /* make sure path isn't freed twice */ > > + wwid = pp->wwid; > > + pp = NULL; > > } > > > > /* For find_multipaths = SMART, if there is more than one path > > * matching the refwwid, then the path is valid */ > > if (path_discovery(pathvec, DI_SYSFS | DI_WWID) < 0) > > goto fail; > > - filter_pathvec(pathvec, pp->wwid); > > + filter_pathvec(pathvec, wwid); > > if (VECTOR_SIZE(pathvec) > 1) > > r = PATH_IS_VALID; > > else > > @@ -681,21 +710,23 @@ check_path_valid(const char *name, struct > > config *conf, bool is_uevent) > > > > out: > > r = print_cmd_valid(r, pathvec, conf); > > - free_pathvec(pathvec, FREE_PATHS); > > /* > > * multipath -u must exit with status 0, otherwise udev won't > > * import its output. > > */ > > if (!is_uevent && r == PATH_IS_NOT_VALID) > > - return RTVL_FAIL; > > - return RTVL_OK; > > + r = RTVL_FAIL; > > + else > > + r = RTVL_OK; > > + goto cleanup; > > > > fail: > > - if (pathvec) > > - free_pathvec(pathvec, FREE_PATHS); > > - else > > - free_path(pp); > > - return RTVL_FAIL; > > + r = RTVL_FAIL; > > + > > +cleanup: > > + cleanup_path(0, &pp); > > + cleanup_pathvec(0, &pathvec); > > + return r; > > } > > > > static int > -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel