[dm-devel] [PATCH 10/19] libmultipath: devmapper: refactor libdm version determination
Martin Wilck
mwilck at suse.com
Mon Sep 21 08:35:34 UTC 2020
On Sat, 2020-09-19 at 17:14 -0500, Benjamin Marzinski wrote:
> On Wed, Sep 16, 2020 at 05:37:09PM +0200, mwilck at suse.com wrote:
> > From: Martin Wilck <mwilck at suse.com>
> >
> > As one step towards bundling all possibly racy libdm init calls
> > into a single
> > function, split the code for determining and checking versions of
> > libdm and kernel components. Provide a generic helper
> > libmp_get_version() that makes sure the versions are "lazily"
> > initialized.
> > Note that retrieving the versions requires libdm calls, thus the
> > version initialization calls libdm initialization, which might call
> > version initialization recursively. But that's not an issue, as
> > the initialization is protected by pthread_once().
>
> This is confusing me. dm_tgt_version will call
> DM_DEVICE_LIST_VERSIONS,
> but it doesn't call libmp_dm_task_create(), so I don't see the
> recursion
> possiblity.
You are right, I was confused.
The callstack for "lazy" initialization looks like this:
libmp_dm_task_create
pthread_once(&dm_initialized, libmp_dm_init);
libmp_dm_init()
=> dm_prereq()
init_versions
pthread_once(&versions_initialized, _init_versions);
_init_versions()
init_dm_library_version()
init_dm_drv_version()
init_dm_mpath_version()
dm_tgt_version
** dm_task_create
libmp_task_run()
pthread_mutex_lock(&libmp_dm_lock);
dm_task_run()
(If an application called dm_prereq() explicitly, it would enter
the stack at "=>", which would be less of a problem).
I suppose I should add a comment at "**" saying that we must not call
libmp_dm_task_create() there to avoid recursion. I also notice that my
function naming I used is inconsistent; it should be
libmp_dm_task_run() rather than just libmp_task_run().
> That's good because according to the man page:
>
> "If you specify a routine that directly or indirectly results in a
> recursive call to pthread_once(3) and that specifies the same routine
> argument, the recursive call can result in a deadlock."
Thanks for pointing this out. I had missed that indeed.
I see this paragraph only in some old DECThreads man pages on the web.
There's a slighly different "APPLICATION USAGE" statement under
https://pubs.opengroup.org/onlinepubs/9699919799/. The pragraph is
missing in https://man7.org/linux/man-pages/man3/pthread_once.3p.html,
which is still based on POSIX.1-2008, 2013 edition - that's why I
missed it.
Anyway, it makes sense, because pthread_once() guarantees that the init
routine has _finished_ when it returns, which can't work with recursive
calls.
Anyway, I'll send a v2.
Regards
Martin
More information about the dm-devel
mailing list