Commit 065ba53c authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-12711 mariabackup --backup is refused for multi-file system tablespace

Before MDEV-12113 (MariaDB Server 10.1.25), on shutdown InnoDB would write
the current LSN to the first page of each file of the system tablespace.
This is incompatible with MariaDB's InnoDB table encryption, because
encryption repurposed the field for an encryption key ID and checksum.

buf_page_is_corrupted(): For the InnoDB system tablespace, skip
FIL_PAGE_FILE_FLUSH_LSN when checking if a page is all zero,
because the first page of each file in the system tablespace can
contain nonzero bytes in the field.
parent 6fbbb085
--innodb --innodb-data-home-dir= --innodb-data-file-path=$MYSQLTEST_VARDIR/tmp/absolute_path_ibdata1:3M;ibdata_second:1M:autoextend
\ No newline at end of file
--innodb --innodb-data-home-dir= --innodb-data-file-path=$MYSQLTEST_VARDIR/tmp/absolute_path_ibdata1:6M;ibdata_second:1M:autoextend
......@@ -2,12 +2,32 @@
# Innodb system tablespace is specified with absolute path in the .opt file
CREATE TABLE t(i INT) ENGINE INNODB;
INSERT INTO t VALUES(1);
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
let MYSQLD_DATADIR= `SELECT @@datadir`;
--source include/shutdown_mysqld.inc
perl;
my $file= "$ENV{MYSQLD_DATADIR}/ibdata_second";
open(FILE, "+<", $file) or die "Unable to open $file\n";
binmode FILE;
my $ps= $ENV{INNODB_PAGE_SIZE};
my $page;
my $pos = $ps * 0;
sysseek(FILE, $pos, 0) || die "Unable to seek $file\n";
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
substr($page,26,8) = pack("NN", 1, 1);
sysseek(FILE, $pos, 0) || die "Unable to rewind $file\n";
syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n";
close(FILE) || die "Unable to close $file\n";
EOF
--source include/start_mysqld.inc
echo # xtrabackup backup;
let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
let $_innodb_data_file_path=`select @@innodb_data_file_path`;
let $_innodb_data_home_dir=`select @@innodb_data_home_dir`;
let $_datadir= `SELECT @@datadir`;
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir;
......@@ -16,11 +36,11 @@ exec $XTRABACKUP --prepare --target-dir=$targetdir;
--source include/shutdown_mysqld.inc
echo # remove datadir;
rmdir $_datadir;
rmdir $MYSQLD_DATADIR;
#remove out-of-datadir ibdata1
remove_file $MYSQLTEST_VARDIR/tmp/absolute_path_ibdata1;
echo # xtrabackup copy back;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --copy-back --datadir=$_datadir --target-dir=$targetdir "--innodb_data_file_path=$_innodb_data_file_path" --innodb_data_home_dir=$_innodb_data_home_dir;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --copy-back --datadir=$MYSQLD_DATADIR --target-dir=$targetdir "--innodb_data_file_path=$_innodb_data_file_path" --innodb_data_home_dir=$_innodb_data_home_dir;
echo # restart server;
--source include/start_mysqld.inc
--enable_result_log
......
......@@ -946,18 +946,31 @@ buf_page_is_corrupted(
#error "FIL_PAGE_LSN must be 64 bit aligned"
#endif
/* declare empty pages non-corrupted */
if (checksum_field1 == 0 && checksum_field2 == 0
&& *reinterpret_cast<const ib_uint64_t*>(read_buf +
FIL_PAGE_LSN) == 0) {
/* make sure that the page is really empty */
for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) {
if (read_buf[i] != 0) {
return(true);
/* A page filled with NUL bytes is considered not corrupted.
The FIL_PAGE_FILE_FLUSH_LSN field may be written nonzero for
the first page of each file of the system tablespace.
Ignore it for the system tablespace. */
if (!checksum_field1 && !checksum_field2) {
ulint i = 0;
do {
if (read_buf[i]) {
return true;
}
}
} while (++i < FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
return(false);
#ifndef UNIV_INNOCHECKSUM
if (!space || !space->id) {
/* Skip FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
in the system tablespace. */
i += 8;
}
#endif
do {
if (read_buf[i]) {
return true;
}
} while (++i < srv_page_size);
return false;
}
switch (curr_algo) {
......
......@@ -945,18 +945,29 @@ buf_page_is_corrupted(
#error "FIL_PAGE_LSN must be 64 bit aligned"
#endif
/* declare empty pages non-corrupted */
if (checksum_field1 == 0 && checksum_field2 == 0
&& *reinterpret_cast<const ib_uint64_t*>(read_buf +
FIL_PAGE_LSN) == 0) {
/* make sure that the page is really empty */
for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) {
if (read_buf[i] != 0) {
return(true);
/* A page filled with NUL bytes is considered not corrupted.
The FIL_PAGE_FILE_FLUSH_LSN field may be written nonzero for
the first page of each file of the system tablespace.
Ignore it for the system tablespace. */
if (!checksum_field1 && !checksum_field2) {
ulint i = 0;
do {
if (read_buf[i]) {
return true;
}
}
} while (++i < FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
return(false);
if (!space || !space->id) {
/* Skip FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
in the system tablespace. */
i += 8;
}
do {
if (read_buf[i]) {
return true;
}
} while (++i < srv_page_size);
return false;
}
switch (curr_algo) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment