summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-10-20 18:31:56 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2020-10-20 19:55:16 +0300
commit832a6acb72027ee1cf2fbf9be224a8cd65cfd6fc (patch)
tree1f533e11bc834a8584ff04e01a8cd7d09c87f0ad /storage
parentd1af93a5e84c416833b5f77719db36a976ebde50 (diff)
downloadmariadb-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.cc12
-rw-r--r--storage/innobase/include/sync0types.h8
-rw-r--r--storage/innobase/include/ut0mutex.h16
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;
+ }
}
}