fio: fix dlopen refcounting of dynamic engines
authorEric Sandeen <sandeen@redhat.com>
Mon, 25 Jan 2021 19:23:48 +0000 (13:23 -0600)
committerJens Axboe <axboe@kernel.dk>
Mon, 25 Jan 2021 21:03:58 +0000 (14:03 -0700)
ioengine_load() will dlclose the dynamic library if it matches one
that we've already got open, but this defeats the built-in refcounting
done by dlopen/dlclose.  As each thread exits, it calls free_ioengine(),
and this may do a final dlclose on a dynamic ioengine that is still
in use if we don't have the proper reference count.

Fix this by dropping the explicit dlclose of a "matching" dlopened
dynamic engine library, and let each dlclose decrement the refcount
on the engine library as is normal.

This also adds/modifies a couple of debug messages to help track this.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
init.c
ioengines.c

diff --git a/init.c b/init.c
index ab38b334a9195b089d686785c9ec0d0d02d17dc4..d6dbaf7cb437d894ab990fa4531bd44ef05872c7 100644 (file)
--- a/init.c
+++ b/init.c
@@ -1109,11 +1109,8 @@ int ioengine_load(struct thread_data *td)
                if (!ops)
                        goto fail;
 
-               if (ops == td->io_ops && dlhandle == td->io_ops->dlhandle) {
-                       if (dlhandle)
-                               dlclose(dlhandle);
+               if (ops == td->io_ops && dlhandle == td->io_ops->dlhandle)
                        return 0;
-               }
 
                if (dlhandle && dlhandle != td->io_ops->dlhandle)
                        dlclose(dlhandle);
index dcc9496dd4ddab6fe0c79612e13684e7b790441f..f88b0537f1e622f963919b4be9679164e98c7c59 100644 (file)
@@ -95,6 +95,7 @@ static void *dlopen_external(struct thread_data *td, const char *engine)
 
        sprintf(engine_path, "%s/fio-%s.so", FIO_EXT_ENG_DIR, engine);
 
+       dprint(FD_IO, "dlopen external %s\n", engine_path);
        dlhandle = dlopen(engine_path, RTLD_LAZY);
        if (!dlhandle)
                log_info("Engine %s not found; Either name is invalid, was not built, or fio-engine-%s package is missing.\n",
@@ -116,7 +117,7 @@ static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
            !strncmp(engine_lib, "aio", 3))
                engine_lib = "libaio";
 
-       dprint(FD_IO, "dload engine %s\n", engine_lib);
+       dprint(FD_IO, "dlopen engine %s\n", engine_lib);
 
        dlerror();
        dlhandle = dlopen(engine_lib, RTLD_LAZY);
@@ -194,7 +195,9 @@ struct ioengine_ops *load_ioengine(struct thread_data *td)
         * so as not to break job files not using the prefix.
         */
        ops = __load_ioengine(td->o.ioengine);
-       if (!ops)
+
+       /* We do re-dlopen existing handles, for reference counting */
+       if (!ops || ops->dlhandle)
                ops = dlopen_ioengine(td, name);
 
        /*
@@ -229,6 +232,7 @@ void free_ioengine(struct thread_data *td)
        }
 
        if (td->io_ops->dlhandle) {
+               dprint(FD_IO, "dlclose ioengine %s\n", td->io_ops->name);
                dlclose(td->io_ops->dlhandle);
                td->io_ops->dlhandle = NULL;
        }