Description:
Please run the attached mtr testcase on debug build and see that server crashes with assertion ut_a(err == DB_SUCCESS) on recovery.
Note that the assertion is release build assertion. The assertion fails because server cannot decrypt an encrypted page on async io (aio) read during recovery.
Multiple issues exist:
1. Server can write encrypted pages before Page 0 is flushed (the core)
2. Server writes an un-encrypted copy in dblwr but writes encrypted in actual tablespace
3. Server cannot recover after a crash
Thread 1 (Thread 0x7fb51ffff700 (LWP 117897)):
#0 __pthread_kill (threadid=<optimized out>, signo=6) at ../sysdeps/unix/sysv/linux/pthread_kill.c:56
#1 0x0000558282d36b19 in my_write_core (sig=6) at /home/satya/WORK/mysql-8.0/mysys/stacktrace.cc:308
#2 0x000055828175d92b in handle_fatal_signal (sig=6) at /home/satya/WORK/mysql-8.0/sql/signal_handler.cc:171
#3 <signal handler called>
#4 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#5 0x00007fb53f618859 in __GI_abort () at abort.c:79
#6 0x000055828320034e in ut_dbg_assertion_failed (expr=0x558285016b0d "err == DB_SUCCESS", file=0x5582850165b0 "/home/satya/WORK/mysql-8.0/storage/innobase/fil/fil0fil.cc", line=8192) at /home/satya/WORK/mysql-8.0/storage/innobase/ut/ut0dbg.cc:98
#7 0x00005582833e994a in fil_aio_wait (segment=5) at /home/satya/WORK/mysql-8.0/storage/innobase/fil/fil0fil.cc:8192
#8 0x00005582831616f3 in io_handler_thread (segment=5) at /home/satya/WORK/mysql-8.0/storage/innobase/srv/srv0start.cc:278
#9 0x000055828317ceb8 in std::__invoke_impl<void, void (*&)(unsigned long), unsigned long&> (__f=@0x7fb51fffeb90: 0x558283161699 <io_handler_thread(ulint)>) at /usr/include/c++/9/bits/invoke.h:60
#10 0x000055828317cdfc in std::__invoke<void (*&)(unsigned long), unsigned long&> (__fn=@0x7fb51fffeb90: 0x558283161699 <io_handler_thread(ulint)>) at /usr/include/c++/9/bits/invoke.h:95
#11 0x000055828317cd27 in std::_Bind<void (*(unsigned long))(unsigned long)>::__call<void, , 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) (this=0x7fb51fffeb90, __args=...) at /usr/include/c++/9/functional:400
#12 0x000055828317cc4d in std::_Bind<void (*(unsigned long))(unsigned long)>::operator()<, void>() (this=0x7fb51fffeb90) at /usr/include/c++/9/functional:484
#13 0x000055828317cb84 in Runnable::operator()<void (*)(unsigned long), unsigned long> (this=0x7fb53446d2d8, f=@0x7fb53446d2d0: 0x558283161699 <io_handler_thread(ulint)>) at /home/satya/WORK/mysql-8.0/storage/innobase/include/os0thread-create.h:101
#14 0x000055828317ca60 in std::__invoke_impl<void, Runnable, void (*)(unsigned long), unsigned long> (__f=...) at /usr/include/c++/9/bits/invoke.h:60
#15 0x000055828317c983 in std::__invoke<Runnable, void (*)(unsigned long), unsigned long> (__fn=...) at /usr/include/c++/9/bits/invoke.h:95
#16 0x000055828317c893 in std::thread::_Invoker<std::tuple<Runnable, void (*)(unsigned long), unsigned long> >::_M_invoke<0ul, 1ul, 2ul> (this=0x7fb53446d2c8) at /usr/include/c++/9/thread:244
#17 0x000055828317c819 in std::thread::_Invoker<std::tuple<Runnable, void (*)(unsigned long), unsigned long> >::operator() (this=0x7fb53446d2c8) at /usr/include/c++/9/thread:251
#18 0x000055828317c7ea in std::thread::_State_impl<std::thread::_Invoker<std::tuple<Runnable, void (*)(unsigned long), unsigned long> > >::_M_run (this=0x7fb53446d2c0) at /usr/include/c++/9/thread:195
#19 0x00007fb53fa25d84 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#20 0x00007fb53ffd7609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#21 0x00007fb53f715293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
How to repeat:
On debug build
./mtr --mem main.encryption_crash
Suggested fix:
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 2325af7769e..ebcdb860785 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -4262,16 +4262,6 @@ static dberr_t init_before_encrypt_processing(fil_space_t *space,
space_id, space->flags, 0, Encryption::ENCRYPT_IN_PROGRESS, true, &mtr);
mtr_commit(&mtr);
- /* Set encryption for tablespace */
- rw_lock_x_lock(&space->latch);
- err = fil_set_encryption(space_id, Encryption::AES, key, iv);
- rw_lock_x_unlock(&space->latch);
-
- if (err != DB_SUCCESS) {
- ut_ad(false);
- return err;
- }
-
/* Make sure encryption information is persisted on disk. Following scenario:
[1] Encryption key is written on page 0 but Page 0 is not flushed.
[2] page P is encrypted with K1 and flushed on disk.
@@ -4282,6 +4272,16 @@ static dberr_t init_before_encrypt_processing(fil_space_t *space,
buf_LRU_flush_or_remove_pages(space_id, BUF_REMOVE_FLUSH_WRITE, nullptr,
false);
+ /* Set encryption for tablespace */
+ rw_lock_x_lock(&space->latch);
+ err = fil_set_encryption(space_id, Encryption::AES, key, iv);
+ rw_lock_x_unlock(&space->latch);
+
+ if (err != DB_SUCCESS) {
+ ut_ad(false);
+ return err;
+ }
+
/* Set encryption operation in progress flag */