diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-10-20 18:31:56 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-10-20 19:55:16 +0300 |
commit | 832a6acb72027ee1cf2fbf9be224a8cd65cfd6fc (patch) | |
tree | 1f533e11bc834a8584ff04e01a8cd7d09c87f0ad /storage | |
parent | d1af93a5e84c416833b5f77719db36a976ebde50 (diff) | |
download | mariadb-git-832a6acb72027ee1cf2fbf9be224a8cd65cfd6fc.tar.gz |
MDEV-23996 Race conditions in SHOW ENGINE INNODB MUTEX
The function innodb_show_mutex_status() is the only ultimate caller of
LatchCounter::iterate() via MutexMonitor::iterate(). Because the call
is not protected by LatchCounter::m_mutex, any mutex_create() or
mutex_free() that is invoked concurrently during the execution, bad
things such as a crash could happen.
The most likely way for this to happen is buffer pool resizing,
which could cause buf_block_t::mutex (which existed before MDEV-15053)
to be created or freed. We could also register InnoDB mutexes in
TrxFactory::init() if trx_pools needs to grow.
The view INFORMATION_SCHEMA.INNODB_MUTEXES is not affected, because it
only displays information about rw-locks, not mutexes.
This commit intentionally touches also MutexMonitor::iterate()
and the only code that interfaces with LatchCounter::iterate()
to make it clearer for future readers that the scattered code
that is obfuscated by templates belongs together.
This is based on
mysql/mysql-server@273a93396f49c7e0a8b07b260128d9a990c2b154
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 12 | ||||
-rw-r--r-- | storage/innobase/include/sync0types.h | 8 | ||||
-rw-r--r-- | storage/innobase/include/ut0mutex.h | 16 |
3 files changed, 13 insertions, 23 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c408b1a1d30..637c66612ce 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -16332,8 +16332,7 @@ struct ShowStatus { /** Collect the latch metrics. Ignore entries where the spins and waits are zero. @param[in] count The latch metrics */ - void operator()(Count* count) - UNIV_NOTHROW + void operator()(Count* count) const UNIV_NOTHROW { if (count->m_spins > 0 || count->m_waits > 0) { @@ -16361,13 +16360,8 @@ struct ShowStatus { bool operator()(latch_meta_t& latch_meta) UNIV_NOTHROW { - latch_meta_t::CounterType* counter; - - counter = latch_meta.get_counter(); - - GetCount get_count(latch_meta.get_name(), &m_values); - - counter->iterate(get_count); + latch_meta.get_counter()->iterate( + GetCount(latch_meta.get_name(), &m_values)); return(true); } diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index ca8291f666a..563176f4abe 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -659,10 +659,10 @@ public: } /** Iterate over the counters */ - template <typename Callback> - void iterate(Callback& callback) const - UNIV_NOTHROW + template<typename C> void iterate(const C& callback) UNIV_NOTHROW { + m_mutex.enter(); + Counters::const_iterator end = m_counters.end(); for (Counters::const_iterator it = m_counters.begin(); @@ -671,6 +671,8 @@ public: callback(*it); } + + m_mutex.exit(); } /** Disable the monitoring */ diff --git a/storage/innobase/include/ut0mutex.h b/storage/innobase/include/ut0mutex.h index 1f99ee17a24..5375be0ed71 100644 --- a/storage/innobase/include/ut0mutex.h +++ b/storage/innobase/include/ut0mutex.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2012, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -142,16 +142,10 @@ public: /* Some of the slots will be null in non-debug mode */ - if (*it == NULL) { - continue; - } - - latch_meta_t* latch_meta = *it; - - bool ret = callback(*latch_meta); - - if (!ret) { - return(ret); + if (latch_meta_t* l= *it) { + if (!callback(*l)) { + return false; + } } } |