From a8650b64ede7330e83e84226cccd77ba8e05fa29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= <marko.makela@mariadb.com>
Date: Wed, 10 Mar 2021 19:33:09 +0200
Subject: [PATCH] MDEV-25110 [FATAL] InnoDB: Trying to write ... outside the
 bounds

In commit 118e258aaac5da75a2ac4556201aaea3688fac67 (part of MDEV-23855)
we inadvertently broke crash recovery, reintroducing MDEV-11556.

fil_system_t::extend_to_recv_size(): Extend all open tablespace files
to the recovered size.

recv_sys_t::apply(): Invoke fil_system.extend_to_recv_size() at the
start of each batch. In this way, any fil_space_t::recv_size
changes that were parsed after the file was opened will be applied.
---
 storage/innobase/fil/fil0fil.cc    | 27 +++++++++++++++++++++++++++
 storage/innobase/include/fil0fil.h |  5 ++++-
 storage/innobase/log/log0recv.cc   |  2 ++
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index d000bc471d9..e245076a822 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -1305,6 +1305,33 @@ void fil_system_t::close()
 #endif /* UNIV_LINUX */
 }
 
+/** Extend all open data files to the recovered size */
+ATTRIBUTE_COLD void fil_system_t::extend_to_recv_size()
+{
+  ut_ad(is_initialised());
+  mutex_enter(&mutex);
+  for (fil_space_t *space= UT_LIST_GET_FIRST(fil_system.space_list); space;
+       space= UT_LIST_GET_NEXT(space_list, space))
+  {
+    const uint32_t size= space->recv_size;
+
+    if (size > space->size)
+    {
+      if (space->is_closing())
+        continue;
+      space->reacquire();
+      bool success;
+      while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain),
+                                         size, &success))
+        mutex_enter(&mutex);
+      /* Crash recovery requires the file extension to succeed. */
+      ut_a(success);
+      space->release();
+    }
+  }
+  mutex_exit(&mutex);
+}
+
 /** Close all tablespace files at shutdown */
 void fil_space_t::close_all()
 {
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index f011eb6af69..f4ca4e9a73e 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -1,7 +1,7 @@
 /*****************************************************************************
 
 Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2020, MariaDB Corporation.
+Copyright (c) 2013, 2021, 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
@@ -1422,6 +1422,9 @@ public:
   @retval NULL if this was the last */
   inline fil_space_t* keyrotate_next(fil_space_t *space, bool recheck,
                                      bool encrypt);
+
+  /** Extend all open data files to the recovered size */
+  ATTRIBUTE_COLD void extend_to_recv_size();
 };
 
 /** The tablespace memory cache. */
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 7c9d8af0859..67ac088f629 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -2662,6 +2662,8 @@ void recv_sys_t::apply(bool last_batch)
         trim(page_id_t(id + srv_undo_space_id_start, t.pages), t.lsn);
     }
 
+    fil_system.extend_to_recv_size();
+
     buf_block_t *free_block= buf_LRU_get_free_block(false);
 
     for (map::iterator p= pages.begin(); p != pages.end(); )