summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2017-03-01 16:14:29 +0200
committerJan Lindström <jan.lindstrom@mariadb.com>2017-03-01 16:14:29 +0200
commitdc166632ca30071d83c4a1c14de9b322c9510f6e (patch)
treec9b26c16c1a9271e5206eec5b3730198433eeaef
parentec4cf111c0d8599c63c486dd96b180d5e7cff8ea (diff)
downloadmariadb-git-bb-10.1-MDEV-11759.tar.gz
MDEV-11759: Encryption code in MariaDB 10.1/10.2 causes compatibilitybb-10.1-MDEV-11759
problems. Problem was that bpage was referenced after it was already freed from LRU. Fixed by adding a new variable encrypted that is passed down to buf_page_check_corrupt() and used in buf_page_get_gen() to stop processing page read. btr_cur_open_at_index_side_func(), btr_cur_open_at_rnd_pos_func(): Avoid referencing block that is NULL. buf_page_get_zip(): Issue error if page read fails. buf_page_get_gen(): Use dberr_t for error detection and do not reference bpage after we hare freed it. buf_mark_space_corrupt(): remove bpage from LRU also when it is encrypted. buf_page_check_corrupt(): @return DB_SUCCESS if page has been read and is not corrupted, DB_PAGE_CORRUPTED if page based on checksum check is corrupted, DB_DECRYPTION_FAILED if page post encryption checksum matches but after decryption normal page checksum does not match. buf_page_io_complete(): use dberr_t for error handling. buf_flush_write_block_low(), buf_read_ahead_random(), buf_read_page_async(), buf_read_ahead_linear(), buf_read_ibuf_merge_pages(), buf_read_recv_pages(), fil_aio_wait(): Issue error if page read fails.
-rw-r--r--mysql-test/suite/encryption/r/innodb-bad-key-change.result5
-rw-r--r--mysql-test/suite/encryption/r/innodb-compressed-blob.result23
-rw-r--r--mysql-test/suite/encryption/r/innodb-force-corrupt.result55
-rw-r--r--mysql-test/suite/encryption/t/innodb-compressed-blob.opt4
-rw-r--r--mysql-test/suite/encryption/t/innodb-compressed-blob.test84
-rw-r--r--mysql-test/suite/encryption/t/innodb-force-corrupt.test131
-rw-r--r--mysql-test/suite/innodb/r/innodb_bug14147491.result1
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug14147491.test1
-rw-r--r--storage/innobase/btr/btr0cur.cc6
-rw-r--r--storage/innobase/buf/buf0buf.cc280
-rw-r--r--storage/innobase/buf/buf0flu.cc9
-rw-r--r--storage/innobase/buf/buf0rea.cc209
-rw-r--r--storage/innobase/fil/fil0fil.cc10
-rw-r--r--storage/innobase/include/buf0buf.h28
-rw-r--r--storage/innobase/include/buf0rea.h36
-rw-r--r--storage/innobase/include/db0err.h2
-rw-r--r--storage/xtradb/btr/btr0cur.cc8
-rw-r--r--storage/xtradb/buf/buf0buf.cc269
-rw-r--r--storage/xtradb/buf/buf0flu.cc9
-rw-r--r--storage/xtradb/buf/buf0rea.cc225
-rw-r--r--storage/xtradb/fil/fil0fil.cc21
-rw-r--r--storage/xtradb/include/buf0buf.h22
-rw-r--r--storage/xtradb/include/buf0rea.h41
-rw-r--r--storage/xtradb/include/db0err.h2
-rw-r--r--storage/xtradb/os/os0file.cc4
25 files changed, 932 insertions, 553 deletions
diff --git a/mysql-test/suite/encryption/r/innodb-bad-key-change.result b/mysql-test/suite/encryption/r/innodb-bad-key-change.result
index 82bbd60f59f..5c4f43f028b 100644
--- a/mysql-test/suite/encryption/r/innodb-bad-key-change.result
+++ b/mysql-test/suite/encryption/r/innodb-bad-key-change.result
@@ -40,13 +40,8 @@ Warning 192 Table test/t1 in tablespace is encrypted but encryption service or
Warning 192 Table test/t1 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1296 Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
DROP TABLE t1;
-Warnings:
-Warning 192 Table in tablespace encrypted.However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match. Can't continue opening the table.
-Warning 192 Table in tablespace encrypted.However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match. Can't continue opening the table.
SHOW WARNINGS;
Level Code Message
-Warning 192 Table in tablespace encrypted.However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match. Can't continue opening the table.
-Warning 192 Table in tablespace encrypted.However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match. Can't continue opening the table.
# Start server with keys.txt
CREATE TABLE t2 (c VARCHAR(8), id int not null primary key, b int, key(b)) ENGINE=InnoDB ENCRYPTED=YES;
INSERT INTO t2 VALUES ('foobar',1,2);
diff --git a/mysql-test/suite/encryption/r/innodb-compressed-blob.result b/mysql-test/suite/encryption/r/innodb-compressed-blob.result
new file mode 100644
index 00000000000..a19707d8f77
--- /dev/null
+++ b/mysql-test/suite/encryption/r/innodb-compressed-blob.result
@@ -0,0 +1,23 @@
+call mtr.add_suppression("InnoDB: Block in space_id .* in file .* encrypted.");
+call mtr.add_suppression("InnoDB: However key management plugin or used key_version 1 is not found or used encryption algorithm or method does not match.");
+call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+set GLOBAL innodb_default_encryption_key_id=4;
+create table t1(a int not null primary key, b blob) engine=innodb row_format=compressed;
+create table t2(a int not null primary key, b blob) engine=innodb row_format=compressed encrypted=yes;
+create table t3(a int not null primary key, b blob) engine=innodb row_format=compressed encrypted=no;
+CREATE INDEX test ON t1 (b(10));
+CREATE INDEX test ON t2 (b(10));
+CREATE INDEX test ON t3 (b(10));
+insert into t1 values (1, repeat('secret',6000));
+insert into t2 values (1, repeat('secret',6000));
+insert into t3 values (1, repeat('secret',6000));
+select count(*) from t1 FORCE INDEX (test) where b like 'secret%';
+ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
+select count(*) from t2 FORCE INDEX (test) where b like 'secret%';
+ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
+select count(*) from t3 FORCE INDEX (test) where b like 'secret%';
+count(*)
+1
+drop table t1,t2,t3;
diff --git a/mysql-test/suite/encryption/r/innodb-force-corrupt.result b/mysql-test/suite/encryption/r/innodb-force-corrupt.result
new file mode 100644
index 00000000000..0b9d39161f7
--- /dev/null
+++ b/mysql-test/suite/encryption/r/innodb-force-corrupt.result
@@ -0,0 +1,55 @@
+call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
+call mtr.add_suppression("InnoDB: Corruption: Block in space_id .* in file .* corrupted.");
+call mtr.add_suppression("InnoDB: Based on page type .*");
+call mtr.add_suppression("InnoDB: Unable to read tablespace .* page no .* into the buffer pool after .* attempts");
+CALL mtr.add_suppression("InnoDB: Error: Unable to read tablespace .* page no .* into the buffer pool after 100 attempts");
+CALL mtr.add_suppression("InnoDB: Database page corruption on disk or a failed");
+CALL mtr.add_suppression("InnoDB: Space .* file test/t1 read of page .*");
+CALL mtr.add_suppression("InnoDB: You may have to recover from a backup.");
+CALL mtr.add_suppression("InnoDB: It is also possible that your operatingsystem has corrupted its own file cache.");
+CALL mtr.add_suppression("InnoDB: and rebooting your computer removes the error.");
+CALL mtr.add_suppression("InnoDB: If the corrupt page is an index page you can also try to");
+CALL mtr.add_suppression("InnoDB: fix the corruption by dumping, dropping, and reimporting");
+CALL mtr.add_suppression("InnoDB: the corrupt table. You can use CHECK");
+CALL mtr.add_suppression("InnoDB: TABLE to scan your table for corruption.");
+CALL mtr.add_suppression("InnoDB: See also .* about forcing recovery.");
+CALL mtr.add_suppression("InnoDB: However key management plugin or used key_version 3221605118 is not found or used encryption algorithm or method does not match.");
+CALL mtr.add_suppression("Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
+CALL mtr.add_suppression("InnoDB: Block in space_id .* in file .* encrypted.");
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+set global innodb_compression_algorithm = 1;
+# Create and populate tables to be corrupted
+CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT,c char(200)) ENGINE=InnoDB encrypted=yes;
+CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT,c char(200)) ENGINE=InnoDB row_format=compressed encrypted=yes;
+CREATE TABLE t3 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT, c char(200)) ENGINE=InnoDB page_compressed=yes encrypted=yes;
+INSERT INTO t1 (b,c) VALUES ('corrupt me','secret');
+INSERT INTO t1 (b,c) VALUES ('corrupt me','moresecretmoresecret');
+INSERT INTO t2 select * from t1;
+INSERT INTO t3 select * from t1;
+# Backup tables before corrupting
+# Corrupt tables
+# Write file to make mysql-test-run.pl expect the "crash", but don't
+# start it until it's told to
+# The below SELECT query will crash the server because some pages
+# on the disk are corrupted
+SELECT * FROM t1;
+ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
+SELECT * FROM t2;
+a b c
+1 corrupt me secret
+2 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+3 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+4 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+5 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+6 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+7 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+8 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+9 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+10 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+11 abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc secretsecret
+12 corrupt me moresecretmoresecret
+SELECT * FROM t3;
+ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
+# Restore the original t1.ibd
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/suite/encryption/t/innodb-compressed-blob.opt b/mysql-test/suite/encryption/t/innodb-compressed-blob.opt
new file mode 100644
index 00000000000..36dcb6c6f26
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-compressed-blob.opt
@@ -0,0 +1,4 @@
+--innodb-tablespaces-encryption
+--innodb-encrypt-tables=on
+--innodb-encryption-threads=2
+--max_allowed_packet=64K
diff --git a/mysql-test/suite/encryption/t/innodb-compressed-blob.test b/mysql-test/suite/encryption/t/innodb-compressed-blob.test
new file mode 100644
index 00000000000..5d6fbf56e2b
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-compressed-blob.test
@@ -0,0 +1,84 @@
+-- source include/have_innodb.inc
+-- source include/have_file_key_management_plugin.inc
+
+# embedded does not support restart
+-- source include/not_embedded.inc
+
+call mtr.add_suppression("InnoDB: Block in space_id .* in file .* encrypted.");
+call mtr.add_suppression("InnoDB: However key management plugin or used key_version 1 is not found or used encryption algorithm or method does not match.");
+call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
+
+--disable_query_log
+let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
+let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
+--enable_query_log
+
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--shutdown_server
+--source include/wait_until_disconnected.inc
+
+--write_file $MYSQLTEST_VARDIR/keys1.txt
+1;770A8A65DA156D24EE2A093277530142
+4;770A8A65DA156D24EE2A093277530143
+EOF
+
+--exec echo "restart:--innodb-encrypt-tables --innodb-stats-persistent --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+
+set GLOBAL innodb_default_encryption_key_id=4;
+create table t1(a int not null primary key, b blob) engine=innodb row_format=compressed;
+create table t2(a int not null primary key, b blob) engine=innodb row_format=compressed encrypted=yes;
+create table t3(a int not null primary key, b blob) engine=innodb row_format=compressed encrypted=no;
+CREATE INDEX test ON t1 (b(10));
+CREATE INDEX test ON t2 (b(10));
+CREATE INDEX test ON t3 (b(10));
+
+
+insert into t1 values (1, repeat('secret',6000));
+insert into t2 values (1, repeat('secret',6000));
+insert into t3 values (1, repeat('secret',6000));
+
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--shutdown_server
+--source include/wait_until_disconnected.inc
+
+--write_file $MYSQLTEST_VARDIR/keys2.txt
+1;770A8A65DA156D24EE2A093277530142
+4;770A8A65DA156D24EE2A093277530144
+EOF
+
+--exec echo "restart:--innodb-encrypt-tables --innodb-stats-persistent --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys2.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+--source include/restart_mysqld.inc
+
+--error 1296
+select count(*) from t1 FORCE INDEX (test) where b like 'secret%';
+--error 1296
+select count(*) from t2 FORCE INDEX (test) where b like 'secret%';
+select count(*) from t3 FORCE INDEX (test) where b like 'secret%';
+
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--shutdown_server
+--source include/wait_until_disconnected.inc
+
+--remove_file $MYSQLTEST_VARDIR/keys1.txt
+--remove_file $MYSQLTEST_VARDIR/keys2.txt
+
+--write_file $MYSQLTEST_VARDIR/keys1.txt
+1;770A8A65DA156D24EE2A093277530142
+4;770A8A65DA156D24EE2A093277530143
+EOF
+
+--exec echo "restart:--innodb-encrypt-tables --innodb-stats-persistent --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+drop table t1,t2,t3;
+
+--remove_file $MYSQLTEST_VARDIR/keys1.txt
diff --git a/mysql-test/suite/encryption/t/innodb-force-corrupt.test b/mysql-test/suite/encryption/t/innodb-force-corrupt.test
new file mode 100644
index 00000000000..1f05726830b
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-force-corrupt.test
@@ -0,0 +1,131 @@
+#
+# MDEV-11759: Encryption code in MariaDB 10.1/10.2 causes compatibility problems
+#
+
+-- source include/have_innodb.inc
+-- source include/have_file_key_management_plugin.inc
+# Don't test under valgrind, memory leaks will occur
+source include/not_valgrind.inc;
+# Avoid CrashReporter popup on Mac
+source include/not_crashrep.inc;
+# Don't test under embedded
+source include/not_embedded.inc;
+# Require InnoDB
+source include/have_innodb.inc;
+# Test could open crash reporter on Windows
+# if compiler set up
+source include/not_windows.inc;
+
+call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
+call mtr.add_suppression("InnoDB: Corruption: Block in space_id .* in file .* corrupted.");
+call mtr.add_suppression("InnoDB: Based on page type .*");
+call mtr.add_suppression("InnoDB: Unable to read tablespace .* page no .* into the buffer pool after .* attempts");
+CALL mtr.add_suppression("InnoDB: Error: Unable to read tablespace .* page no .* into the buffer pool after 100 attempts");
+CALL mtr.add_suppression("InnoDB: Database page corruption on disk or a failed");
+CALL mtr.add_suppression("InnoDB: Space .* file test/t1 read of page .*");
+CALL mtr.add_suppression("InnoDB: You may have to recover from a backup.");
+CALL mtr.add_suppression("InnoDB: It is also possible that your operatingsystem has corrupted its own file cache.");
+CALL mtr.add_suppression("InnoDB: and rebooting your computer removes the error.");
+CALL mtr.add_suppression("InnoDB: If the corrupt page is an index page you can also try to");
+CALL mtr.add_suppression("InnoDB: fix the corruption by dumping, dropping, and reimporting");
+CALL mtr.add_suppression("InnoDB: the corrupt table. You can use CHECK");
+CALL mtr.add_suppression("InnoDB: TABLE to scan your table for corruption.");
+CALL mtr.add_suppression("InnoDB: See also .* about forcing recovery.");
+CALL mtr.add_suppression("InnoDB: However key management plugin or used key_version 3221605118 is not found or used encryption algorithm or method does not match.");
+CALL mtr.add_suppression("Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
+CALL mtr.add_suppression("InnoDB: Block in space_id .* in file .* encrypted.");
+
+--disable_warnings
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+set global innodb_compression_algorithm = 1;
+--enable_warnings
+
+--echo # Create and populate tables to be corrupted
+CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT,c char(200)) ENGINE=InnoDB encrypted=yes;
+CREATE TABLE t2 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT,c char(200)) ENGINE=InnoDB row_format=compressed encrypted=yes;
+CREATE TABLE t3 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT, c char(200)) ENGINE=InnoDB page_compressed=yes encrypted=yes;
+
+INSERT INTO t1 (b,c) VALUES ('corrupt me','secret');
+--disable_query_log
+--let $i = 10
+while ($i)
+{
+ INSERT INTO t1 (b,c) VALUES (REPEAT('abcabcabc', 100),'secretsecret');
+ dec $i;
+}
+--enable_query_log
+
+INSERT INTO t1 (b,c) VALUES ('corrupt me','moresecretmoresecret');
+INSERT INTO t2 select * from t1;
+INSERT INTO t3 select * from t1;
+
+let $MYSQLD_DATADIR=`select @@datadir`;
+let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
+let MYSQLD_DATADIR=`select @@datadir`;
+
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+
+--source include/shutdown_mysqld.inc
+--source include/wait_until_disconnected.inc
+
+--echo # Backup tables before corrupting
+--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t1.ibd.backup
+--copy_file $MYSQLD_DATADIR/test/t2.ibd $MYSQLD_DATADIR/test/t2.ibd.backup
+--copy_file $MYSQLD_DATADIR/test/t3.ibd $MYSQLD_DATADIR/test/t3.ibd.backup
+
+--echo # Corrupt tables
+
+perl;
+open(FILE, "+<", "$ENV{MYSQLD_DATADIR}/test/t1.ibd") or die "open";
+binmode FILE;
+seek(FILE, $ENV{'INNODB_PAGE_SIZE'} * 3 + 26, SEEK_SET) or die "seek";
+print FILE pack("H*", "c00lcafedeadb017");
+close FILE or die "close";
+EOF
+
+perl;
+open(FILE, "+<", "$ENV{MYSQLD_DATADIR}/test/t2.ibd") or die "open";
+binmode FILE;
+seek(FILE, $ENV{'INNODB_PAGE_SIZE'} * 3 + 26, SEEK_SET) or die "seek";
+print FILE pack("H*", "c00lcafedeadb017");
+close FILE or die "close";
+EOF
+
+perl;
+open(FILE, "+<", "$ENV{MYSQLD_DATADIR}/test/t3.ibd") or die "open";
+binmode FILE;
+seek(FILE, $ENV{'INNODB_PAGE_SIZE'} * 3 + 26, SEEK_SET) or die "seek";
+print FILE pack("H*", "c00lcafedeadb017");
+close FILE or die "close";
+EOF
+
+--source include/start_mysqld.inc
+
+--echo # Write file to make mysql-test-run.pl expect the "crash", but don't
+--echo # start it until it's told to
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+
+--echo # The below SELECT query will crash the server because some pages
+--echo # on the disk are corrupted
+
+--error 1296
+SELECT * FROM t1;
+SELECT * FROM t2;
+--error 1296
+SELECT * FROM t3;
+
+--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+
+--source include/shutdown_mysqld.inc
+--source include/wait_until_disconnected.inc
+
+--echo # Restore the original t1.ibd
+--remove_file $MYSQLD_DATADIR/test/t1.ibd
+--move_file $MYSQLD_DATADIR/test/t1.ibd.backup $MYSQLD_DATADIR/test/t1.ibd
+--move_file $MYSQLD_DATADIR/test/t2.ibd.backup $MYSQLD_DATADIR/test/t2.ibd
+--move_file $MYSQLD_DATADIR/test/t3.ibd.backup $MYSQLD_DATADIR/test/t3.ibd
+
+--source include/start_mysqld.inc
+
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/suite/innodb/r/innodb_bug14147491.result b/mysql-test/suite/innodb/r/innodb_bug14147491.result
index ea725dda257..8fdbcc86d8a 100644
--- a/mysql-test/suite/innodb/r/innodb_bug14147491.result
+++ b/mysql-test/suite/innodb/r/innodb_bug14147491.result
@@ -1,6 +1,7 @@
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
call mtr.add_suppression("InnoDB: Corruption: Block in space_id .* in file .* corrupted.");
call mtr.add_suppression("InnoDB: Based on page type .*");
+call mtr.add_suppression("InnoDB: Unable to read tablespace .* page no .* into the buffer pool after .* attempts");
CALL mtr.add_suppression("InnoDB: Error: Unable to read tablespace .* page no .* into the buffer pool after 100 attempts");
CALL mtr.add_suppression("InnoDB: Database page corruption on disk or a failed");
CALL mtr.add_suppression("InnoDB: Space .* file test/t1 read of page .*");
diff --git a/mysql-test/suite/innodb/t/innodb_bug14147491.test b/mysql-test/suite/innodb/t/innodb_bug14147491.test
index 5776b2c2e37..d16a44e8a55 100644
--- a/mysql-test/suite/innodb/t/innodb_bug14147491.test
+++ b/mysql-test/suite/innodb/t/innodb_bug14147491.test
@@ -7,6 +7,7 @@
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
call mtr.add_suppression("InnoDB: Corruption: Block in space_id .* in file .* corrupted.");
call mtr.add_suppression("InnoDB: Based on page type .*");
+call mtr.add_suppression("InnoDB: Unable to read tablespace .* page no .* into the buffer pool after .* attempts");
# Don't test under valgrind, memory leaks will occur
source include/not_valgrind.inc;
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index 77b915bce92..56fdf268428 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -916,7 +916,7 @@ btr_cur_open_at_index_side_func(
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr, &err);
- if (err != DB_SUCCESS) {
+ if (!block || err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
@@ -1073,7 +1073,7 @@ btr_cur_open_at_rnd_pos_func(
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr, &err);
- if (err != DB_SUCCESS) {
+ if (!block || err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
@@ -3669,7 +3669,7 @@ btr_estimate_n_rows_in_range_on_level(
NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr, &err);
- if (err != DB_SUCCESS) {
+ if (!block || err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 0730683a2d3..d27097a46c6 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -2358,7 +2358,18 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
- buf_read_page(space, zip_size, offset, NULL);
+ dberr_t err = buf_read_page(space, zip_size, offset);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Reading compressed page " ULINTPF
+ " from tablespace " ULINTPF
+ " failed with error: %d.",
+ offset, space, err);
+
+ goto err_exit;
+ }
+
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2916,7 +2927,6 @@ loop:
}
if (block == NULL) {
- buf_page_t* bpage=NULL;
/* Page not in buf_pool: needs to be read from file */
@@ -2950,7 +2960,18 @@ loop:
return(NULL);
}
- if (buf_read_page(space, zip_size, offset, &bpage)) {
+ /* Call path is buf_read_page() -> buf_read_page_low()
+ (_fil_io()) -> buf_page_io_complete() ->
+ buf_decrypt_after_read() here fil_space_t* is used
+ and we decrypt -> buf_page_check_corrupt() where
+ page checksums are compared. Decryption/decompression
+ is handled lower level, error handling is handled on lower
+ level, here we need only to know is page really corrupted
+ or encrypted page with correct checksum. */
+
+ dberr_t local_err = buf_read_page(space, zip_size, offset);
+
+ if (local_err == DB_SUCCESS) {
buf_read_ahead_random(space, zip_size, offset,
ibuf_inside(mtr));
@@ -2958,87 +2979,44 @@ loop:
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
- }
-
- /* Do not try again for encrypted pages */
- if (corrupted && bpage->encrypted) {
- ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
-
- buf_pool = buf_pool_from_bpage(bpage);
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(pmutex);
- buf_LRU_free_page(bpage, true);
- buf_pool_mutex_exit(buf_pool);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
-
- return (NULL);
- }
-
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
+ if (*err) {
+ *err = local_err;
+ }
+
+ /* Encrypted pages that are not corrupted are marked
+ as encrypted and that fact is later pushed to
+ user thread. */
+ if (local_err == DB_DECRYPTION_FAILED) {
+ return (NULL);
+ }
+
+ /* Try to set table as corrupted instead of
+ asserting. */
+ if (space > TRX_SYS_SPACE &&
+ dict_set_corrupted_by_space(space)) {
+ return (NULL);
}
- if (corrupted && !bpage->encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR, "Unable"
- " to read tablespace %lu page no"
- " %lu into the buffer pool after"
- " %lu attempts\n"
- "InnoDB: The most probable cause"
- " of this error may be that the"
- " table has been corrupted.\n"
- "InnoDB: You can try to fix this"
- " problem by using"
- " innodb_force_recovery.\n"
- "InnoDB: Please see reference manual"
- " for more details.\n"
- "InnoDB: Aborting...\n",
- space, offset,
- BUF_PAGE_READ_MAX_RETRIES);
-
- ut_error;
- } else {
- ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
-
- buf_pool = buf_pool_from_bpage(bpage);
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(pmutex);
- buf_LRU_free_page(bpage, true);
- buf_pool_mutex_exit(buf_pool);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
-
- return (NULL);
- }
+ ib_logf(IB_LOG_LEVEL_FATAL, "Unable"
+ " to read tablespace %lu page no"
+ " %lu into the buffer pool after"
+ " %lu attempts\n"
+ "InnoDB: The most probable cause"
+ " of this error may be that the"
+ " table has been corrupted.\n"
+ "InnoDB: You can try to fix this"
+ " problem by using"
+ " innodb_force_recovery.\n"
+ "InnoDB: Please see reference manual"
+ " for more details.\n"
+ "InnoDB: Aborting...\n",
+ space, offset,
+ BUF_PAGE_READ_MAX_RETRIES);
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -4414,55 +4392,48 @@ buf_page_monitor(
/********************************************************************//**
Mark a table with the specified space pointed by bpage->space corrupted.
Also remove the bpage from LRU list.
-@return TRUE if successful */
++@param[in,out] bpage Block */
static
-ibool
+void
buf_mark_space_corrupt(
-/*===================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
+ buf_page_t* bpage)
{
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
const ibool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
ulint space = bpage->space;
- ibool ret = TRUE;
-
- if (!bpage->encrypted) {
- /* First unfix and release lock on the bpage */
- buf_pool_mutex_enter(buf_pool);
- mutex_enter(buf_page_get_mutex(bpage));
- ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
- ut_ad(bpage->buf_fix_count == 0);
- /* Set BUF_IO_NONE before we remove the block from LRU list */
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ /* First unfix and release lock on the bpage */
+ buf_pool_mutex_enter(buf_pool);
+ mutex_enter(buf_page_get_mutex(bpage));
+ ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
+ ut_ad(bpage->buf_fix_count == 0);
- if (uncompressed) {
- rw_lock_x_unlock_gen(
- &((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
- }
+ /* Set BUF_IO_NONE before we remove the block from LRU list */
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
- mutex_exit(buf_page_get_mutex(bpage));
+ if (uncompressed) {
+ rw_lock_x_unlock_gen(
+ &((buf_block_t*) bpage)->lock,
+ BUF_IO_READ);
}
- /* Find the table with specified space id, and mark it corrupted */
- if (dict_set_corrupted_by_space(space)) {
- if (!bpage->encrypted) {
- buf_LRU_free_one_page(bpage);
- }
- } else {
- ret = FALSE;
- }
+ mutex_exit(buf_page_get_mutex(bpage));
+ /* If block is not encrypted find the table with specified
+ space id, and mark it corrupted. Encrypted tables
+ are marked unusable later e.g. in ::open(). */
if (!bpage->encrypted) {
- ut_ad(buf_pool->n_pend_reads > 0);
- buf_pool->n_pend_reads--;
-
- buf_pool_mutex_exit(buf_pool);
+ dict_set_corrupted_by_space(space);
}
- return(ret);
+ /* After this point bpage can't be referenced. */
+ buf_LRU_free_one_page(bpage);
+
+ ut_ad(buf_pool->n_pend_reads > 0);
+ buf_pool->n_pend_reads--;
+
+ buf_pool_mutex_exit(buf_pool);
}
/********************************************************************//**
@@ -4470,9 +4441,12 @@ Check if page is maybe compressed, encrypted or both when we encounter
corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
@param[in,out] bpage Page
-@return true if page corrupted, false if not */
-UNIV_INTERN
-bool
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
+static
+dberr_t
buf_page_check_corrupt(
buf_page_t* bpage)
{
@@ -4483,6 +4457,7 @@ buf_page_check_corrupt(
fil_space_t* space = fil_space_found_by_id(space_id);
fil_space_crypt_t* crypt_data = space->crypt_data;
bool still_encrypted = false;
+ dberr_t err = DB_SUCCESS;
bool corrupted = false;
ulint page_type = mach_read_from_2(dst_frame + FIL_PAGE_TYPE);
@@ -4504,6 +4479,8 @@ buf_page_check_corrupt(
if (!corrupted) {
bpage->encrypted = false;
+ } else {
+ err = DB_PAGE_CORRUPTED;
}
}
@@ -4519,15 +4496,15 @@ buf_page_check_corrupt(
fil_get_page_type_name(page_type), page_type);
} else if (still_encrypted || (bpage->encrypted && corrupted)) {
bpage->encrypted = true;
- corrupted = true;
+ err = DB_DECRYPTION_FAILED;
ib_logf(IB_LOG_LEVEL_ERROR,
"Block in space_id " ULINTPF " in file %s encrypted.",
space_id, space->name ? space->name : "NULL");
ib_logf(IB_LOG_LEVEL_ERROR,
- "However key management plugin or used key_version %u is not found or"
- " used encryption algorithm or method does not match.",
- bpage->key_version);
+ "However key management plugin or used key_version %u is not found or"
+ " used encryption algorithm or method does not match.",
+ bpage->key_version);
if (space_id > TRX_SYS_SPACE) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Marking tablespace as missing. You may drop this table or"
@@ -4535,29 +4512,32 @@ buf_page_check_corrupt(
}
}
- return corrupted;
+ return (err);
}
/********************************************************************//**
Completes an asynchronous read or write request of a file page to or from
the buffer pool.
-@return true if successful */
+@param[in,out] bpage Page to complete
+@param[in] evict whether or not to evict the page
+ from LRU list.
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-bool
+dberr_t
buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage, /*!< in: pointer to the block in question */
- bool evict) /*!< in: whether or not to evict the page
- from LRU list. */
-
+ buf_page_t* bpage,
+ bool evict)
{
enum buf_io_fix io_type;
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
const ibool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
fil_space_t* space = NULL;
- byte* frame = NULL;
- bool corrupted = false;
+ byte* frame = NULL;
+ dberr_t err = DB_SUCCESS;
ut_a(buf_page_in_file(bpage));
@@ -4595,6 +4575,8 @@ buf_page_io_complete(
"Page %u in tablespace %u zip_decompress failure.",
bpage->offset, bpage->space);
+ err = DB_PAGE_CORRUPTED;
+
goto database_corrupted;
}
buf_pool->n_pend_unzip--;
@@ -4641,25 +4623,26 @@ buf_page_io_complete(
bpage->offset);
}
- corrupted = buf_page_check_corrupt(bpage);
+ err = buf_page_check_corrupt(bpage);
database_corrupted:
- if (corrupted) {
+ if (err != DB_SUCCESS) {
/* Not a real corruption if it was triggered by
error injection */
DBUG_EXECUTE_IF("buf_page_is_corrupt_failure",
- if (bpage->space > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
+ if (bpage->space > TRX_SYS_SPACE) {
+ buf_mark_space_corrupt(bpage);
ib_logf(IB_LOG_LEVEL_INFO,
"Simulated page corruption");
- return(true);
+ return(err);
}
+ err = DB_SUCCESS;
goto page_not_corrupt;
);
- if (!bpage->encrypted) {
+ if (err == DB_PAGE_CORRUPTED) {
fil_system_enter();
space = fil_space_get_by_id(bpage->space);
fil_system_exit();
@@ -4701,31 +4684,12 @@ database_corrupted:
/* If page space id is larger than TRX_SYS_SPACE
(0), we will attempt to mark the corresponding
table as corrupted instead of crashing server */
- if (bpage->space > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
- return(false);
+ if (bpage->space > TRX_SYS_SPACE) {
+ buf_mark_space_corrupt(bpage);
+ return(err);
} else {
- if (!bpage->encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Ending processing because of a corrupt database page.");
-
- ut_error;
- }
-
- ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED,
- "Table in tablespace %lu encrypted."
- "However key management plugin or used key_id %lu is not found or"
- " used encryption algorithm or method does not match."
- " Can't continue opening the table.",
- bpage->space, bpage->key_version);
-
- if (bpage->encrypted && bpage->space > TRX_SYS_SPACE) {
- buf_mark_space_corrupt(bpage);
- } else {
- ut_error;
- }
-
- return(false);
+ ib_logf(IB_LOG_LEVEL_FATAL,
+ "Ending processing because of a corrupt database page.");
}
}
}
@@ -4854,7 +4818,7 @@ database_corrupted:
buf_pool_mutex_exit(buf_pool);
- return(true);
+ return(err);
}
/*********************************************************************//**
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 97dee779bcc..cdc32bd1e4b 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -956,7 +956,14 @@ buf_flush_write_block_low(
/* true means we want to evict this page from the
LRU list as well. */
- buf_page_io_complete(bpage, true);
+ dberr_t err = buf_page_io_complete(bpage, true);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Page encrypted while evicting a page %u"
+ " from space %u from LRU.",
+ bpage->offset, bpage->space);
+ }
}
/* Increment the counter of I/O operations used
diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc
index 285fc465160..3d2dfb2f10b 100644
--- a/storage/innobase/buf/buf0rea.cc
+++ b/storage/innobase/buf/buf0rea.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015. MariaDB Corporation.
+Copyright (c) 2015, 2017, 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
@@ -100,28 +100,39 @@ flag is cleared and the x-lock released by an i/o-handler thread.
in buf_pool, or if the page is in the doublewrite buffer blocks in
which case it is never read into the pool, or if the tablespace does
not exist or is being dropped
+
+@param[out] err DB_SUCCESS, DB_TABLESPACE_DELETED if we are
+ trying to read from a non-existent tablespace, or a
+ tablespace which is just now being dropped,
+ DB_PAGE_CORRUPTED if page based on checksum
+ check is corrupted, or DB_DECRYPTION_FAILED
+ if page post encryption checksum matches but
+ after decryption normal page checksum does not match.
+@param[in] sync true if synchronous aio is desired
+@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...,
+ ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
+ at read-ahead functions)
+@param[in] space space id
+@param[in] zip_size compressed page size, or 0
+@param[in] unzip TRUE=request uncompressed page
+@param[in] tablespace_version if the space memory object has
+ this timestamp different from what we are giving here,
+ treat the tablespace as dropped; this is a timestamp we
+ use to stop dangling page reads from a tablespace
+ which we have DISCARDed + IMPORTed back
+@param[in] offset page number
@return 1 if read request is issued. 0 if it is not */
static
ulint
buf_read_page_low(
-/*==============*/
- dberr_t* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
- trying to read from a non-existent tablespace, or a
- tablespace which is just now being dropped */
- bool sync, /*!< in: true if synchronous aio is desired */
- ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ...,
- ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
- at read-ahead functions) */
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size, or 0 */
- ibool unzip, /*!< in: TRUE=request uncompressed page */
- ib_int64_t tablespace_version, /*!< in: if the space memory object has
- this timestamp different from what we are giving here,
- treat the tablespace as dropped; this is a timestamp we
- use to stop dangling page reads from a tablespace
- which we have DISCARDed + IMPORTed back */
- ulint offset, /*!< in: page number */
- buf_page_t** rbpage) /*!< out: page */
+ dberr_t* err,
+ bool sync,
+ ulint mode,
+ ulint space,
+ ulint zip_size,
+ ibool unzip,
+ ib_int64_t tablespace_version,
+ ulint offset)
{
buf_page_t* bpage;
ulint wake_later;
@@ -215,18 +226,13 @@ buf_read_page_low(
if (sync) {
/* The i/o is already completed when we arrive from
fil_read */
- if (!buf_page_io_complete(bpage)) {
- if (rbpage) {
- *rbpage = bpage;
- }
+ *err = buf_page_io_complete(bpage);
+
+ if (*err != DB_SUCCESS) {
return(0);
}
}
- if (rbpage) {
- *rbpage = bpage;
- }
-
return(1);
}
@@ -262,7 +268,7 @@ buf_read_ahead_random(
ulint ibuf_mode;
ulint count;
ulint low, high;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_random_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -357,16 +363,24 @@ read_ahead:
&err, false,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE,
- tablespace_version, i, NULL);
+ tablespace_version, i);
+
if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Warning: in random"
- " readahead trying to access\n"
- "InnoDB: tablespace %lu page %lu,\n"
- "InnoDB: but the tablespace does not"
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "In random"
+ "readahead trying to access"
+ "tablespace " ULINTPF " page " ULINTPF
+ " but the tablespace does not"
" exist or is just being dropped.\n",
- (ulong) space, (ulong) i);
+ space, i);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "In random readahead read page " ULINTPF
+ " from tablespace " ULINTPF
+ " but page is still encrypted. ",
+ i, space);
}
}
}
@@ -400,19 +414,24 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+
+@param[in] space space_id
+@param[in] zip_size compressed page size in bytes, or 0
+@param[in] offset page number
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-ibool
+dberr_t
buf_read_page(
-/*==========*/
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
- ulint offset, /*!< in: page number */
- buf_page_t** bpage) /*!< out: page */
+ ulint space,
+ ulint zip_size,
+ ulint offset)
{
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
tablespace_version = fil_space_get_version(space);
@@ -421,22 +440,23 @@ buf_read_page(
count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, FALSE,
- tablespace_version, offset, bpage);
+ tablespace_version, offset);
+
srv_stats.buf_pool_reads.add(count);
+
if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: trying to access"
- " tablespace %lu page no. %lu,\n"
- "InnoDB: but the tablespace does not exist"
- " or is just being dropped.\n",
- (ulong) space, (ulong) offset);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Trying to access"
+ " tablespace " ULINTPF " page no. " ULINTPF
+ " but the tablespace does not exist"
+ " or is just being dropped.",
+ space, offset);
}
/* Increment number of I/O operations used for LRU policy. */
buf_LRU_stat_inc_io();
- return(count > 0);
+ return(err);
}
/********************************************************************//**
@@ -444,23 +464,27 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+@param[in] space Tablespace id
+@param[in] offset Page no
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-ibool
+dberr_t
buf_read_page_async(
-/*================*/
- ulint space, /*!< in: space id */
- ulint offset) /*!< in: page number */
+ ulint space,
+ ulint offset)
{
ulint zip_size;
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
zip_size = fil_space_get_zip_size(space);
if (zip_size == ULINT_UNDEFINED) {
- return(FALSE);
+ return(err);
}
tablespace_version = fil_space_get_version(space);
@@ -469,7 +493,17 @@ buf_read_page_async(
| OS_AIO_SIMULATED_WAKE_LATER
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
space, zip_size, FALSE,
- tablespace_version, offset, NULL);
+ tablespace_version, offset);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "In async page read "
+ "trying to access"
+ "tablespace " ULINTPF " page " ULINTPF
+ " but failed on error %d.",
+ space, offset, err);
+ }
+
srv_stats.buf_pool_reads.add(count);
/* We do not increment number of I/O operations used for LRU policy
@@ -479,7 +513,7 @@ buf_read_page_async(
these IOs are deliberate and are not part of normal workload we can
ignore these in our heuristics. */
- return(count > 0);
+ return(err);
}
/********************************************************************//**
@@ -528,7 +562,7 @@ buf_read_ahead_linear(
ulint fail_count;
ulint ibuf_mode;
ulint low, high;
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_linear_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -728,16 +762,24 @@ buf_read_ahead_linear(
count += buf_read_page_low(
&err, false,
ibuf_mode,
- space, zip_size, FALSE, tablespace_version, i, NULL);
+ space, zip_size, FALSE, tablespace_version, i);
+
if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Warning: in"
- " linear readahead trying to access\n"
- "InnoDB: tablespace %lu page %lu,\n"
- "InnoDB: but the tablespace does not"
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "In random"
+ "readahead trying to access"
+ "tablespace " ULINTPF " page " ULINTPF
+ " but the tablespace does not"
" exist or is just being dropped.\n",
- (ulong) space, (ulong) i);
+ space, i);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "In random readahead read page " ULINTPF
+ " from tablespace " ULINTPF
+ " but page is still encrypted. ",
+ i, space);
}
}
}
@@ -799,7 +841,7 @@ buf_read_ibuf_merge_pages(
#endif
for (i = 0; i < n_stored; i++) {
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
buf_pool_t* buf_pool;
ulint zip_size = fil_space_get_zip_size(space_ids[i]);
@@ -818,7 +860,7 @@ buf_read_ibuf_merge_pages(
buf_read_page_low(&err, sync && (i + 1 == n_stored),
BUF_READ_ANY_PAGE, space_ids[i],
zip_size, TRUE, space_versions[i],
- page_nos[i], NULL);
+ page_nos[i]);
if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
tablespace_deleted:
@@ -829,6 +871,13 @@ tablespace_deleted:
page_nos[i],
zip_size, FALSE);
}
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Read page " ULINTPF " from tablespace " ULINTPF
+ " for insert buffer but page was encrypted.",
+ page_nos[i], space_ids[i]);
+ }
}
os_aio_simulated_wake_handler_threads();
@@ -865,7 +914,7 @@ buf_read_recv_pages(
{
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
ulint i;
zip_size = fil_space_get_zip_size(space);
@@ -913,12 +962,20 @@ buf_read_recv_pages(
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, TRUE, tablespace_version,
- page_nos[i], NULL);
+ page_nos[i]);
} else {
buf_read_page_low(&err, false, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, TRUE,
- tablespace_version, page_nos[i], NULL);
+ tablespace_version, page_nos[i]);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Recovery read page " ULINTPF
+ " from tablespace " ULINTPF
+ " but page was encrypted.",
+ page_nos[i], space);
}
}
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 8bcdd5da48d..6cc92c2a99a 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -6249,7 +6249,15 @@ fil_aio_wait(
if (fil_node->space->purpose == FIL_TABLESPACE) {
srv_set_io_thread_op_info(segment, "complete io for buf page");
- buf_page_io_complete(static_cast<buf_page_t*>(message));
+ buf_page_t* bpage = static_cast<buf_page_t*>(message);
+ dberr_t err = buf_page_io_complete(bpage);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "ibuf write operation failed for tablespace "
+ "%u offset %u error=%d.",
+ bpage->space, bpage->offset, err);
+ }
} else {
srv_set_io_thread_op_info(segment, "complete io for log");
log_io_complete(static_cast<log_group_t*>(message));
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 643e8c731e5..cf1ad8b133b 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -693,18 +693,6 @@ buf_page_is_corrupted(
ulint zip_size,
const fil_space_t* space)
MY_ATTRIBUTE((warn_unused_result));
-
-/********************************************************************//**
-Check if page is maybe compressed, encrypted or both when we encounter
-corrupted page. Note that we can't be 100% sure if page is corrupted
-or decrypt/decompress just failed.
-@param[in] bpage Page
-@return true if page corrupted, false if not */
-bool
-buf_page_check_corrupt(
- buf_page_t* bpage) /*!< in/out: buffer page read from disk */
- MY_ATTRIBUTE(( warn_unused_result));
-
/********************************************************************//**
Checks if a page is all zeroes.
@return TRUE if the page is all zeroes */
@@ -1255,14 +1243,18 @@ buf_page_init_for_read(
/********************************************************************//**
Completes an asynchronous read or write request of a file page to or from
the buffer pool.
-@return true if successful */
+@param[in,out] bpage pointer to the block in question
+@param[in] evict true if page should be evicted from LRU
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-bool
+dberr_t
buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage, /*!< in: pointer to the block in question */
- bool evict = false);/*!< in: whether or not to evict
- the page from LRU list. */
+ buf_page_t* bpage,
+ bool evict = false);
+
/********************************************************************//**
Calculates a folded value of a file page address to use in the page hash
table.
diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h
index 10714031710..3582885ef92 100644
--- a/storage/innobase/include/buf0rea.h
+++ b/storage/innobase/include/buf0rea.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, MariaDB Corporation.
+Copyright (c) 2015, 2017, 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
@@ -35,27 +35,39 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+
+@param[in] space space_id
+@param[in] zip_size compressed page size in bytes, or 0
+@param[in] offset page number
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-ibool
+dberr_t
buf_read_page(
-/*==========*/
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
- ulint offset, /*!< in: page number */
- buf_page_t** bpage);/*!< out: page */
+ ulint space,
+ ulint zip_size,
+ ulint offset);
+
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+
+@param[in] space Tablespace id
+@param[in] offset Page number
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-ibool
+dberr_t
buf_read_page_async(
/*================*/
- ulint space, /*!< in: space id */
- ulint offset);/*!< in: page number */
+ ulint space,
+ ulint offset);
/********************************************************************//**
Applies a random read-ahead in buf_pool if there are at least a threshold
value of accessed pages from the random read-ahead area. Does not read any
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
index feac81af98e..4bd007323a9 100644
--- a/storage/innobase/include/db0err.h
+++ b/storage/innobase/include/db0err.h
@@ -138,6 +138,8 @@ enum dberr_t {
of missing key management plugin,
or missing or incorrect key or
incorret AES method or algorithm. */
+ DB_PAGE_CORRUPTED, /* Page read from tablespace is
+ corrupted. */
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,
diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc
index afe2c181594..3e1af76fcca 100644
--- a/storage/xtradb/btr/btr0cur.cc
+++ b/storage/xtradb/btr/btr0cur.cc
@@ -3,7 +3,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2015, MariaDB Corporation.
+Copyright (c) 2015, 2017, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -988,7 +988,7 @@ btr_cur_open_at_index_side_func(
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr, &err);
- if (err != DB_SUCCESS) {
+ if (!block || err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
@@ -1161,7 +1161,7 @@ btr_cur_open_at_rnd_pos_func(
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr, &err);
- if (err != DB_SUCCESS) {
+ if (!block || err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
@@ -3854,7 +3854,7 @@ btr_estimate_n_rows_in_range_on_level(
NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr, &err);
- if (err != DB_SUCCESS) {
+ if (!block || err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
DB_DECRYPTION_FAILED,
diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc
index 496cf63d939..e699c4ad9e2 100644
--- a/storage/xtradb/buf/buf0buf.cc
+++ b/storage/xtradb/buf/buf0buf.cc
@@ -2351,7 +2351,17 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
- buf_read_page(space, zip_size, offset, trx, NULL);
+ dberr_t err = buf_read_page(space, zip_size, offset, trx);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Reading compressed page " ULINTPF
+ " from tablespace " ULINTPF
+ " failed with error: %d.",
+ offset, space, err);
+
+ goto err_exit;
+ }
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2957,7 +2967,6 @@ loop:
}
if (block == NULL) {
- buf_page_t* bpage=NULL;
/* Page not in buf_pool: needs to be read from file */
@@ -2993,7 +3002,18 @@ loop:
return(NULL);
}
- if (buf_read_page(space, zip_size, offset, trx, &bpage)) {
+ /* Call path is buf_read_page() -> buf_read_page_low()
+ (_fil_io()) -> buf_page_io_complete() ->
+ buf_decrypt_after_read() here fil_space_t* is used
+ and we decrypt -> buf_page_check_corrupt() where
+ page checksums are compared. Decryption/decompression
+ is handled lower level, error handling is handled on lower
+ level, here we need only to know is page really corrupted
+ or encrypted page with correct checksum. */
+
+ dberr_t local_err = buf_read_page(space, zip_size, offset, trx);
+
+ if (local_err == DB_SUCCESS) {
buf_read_ahead_random(space, zip_size, offset,
ibuf_inside(mtr), trx);
@@ -3001,89 +3021,44 @@ loop:
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
- }
-
- /* Do not try again for encrypted pages */
- if (corrupted && bpage->encrypted) {
- ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
- mutex_enter(&buf_pool->LRU_list_mutex);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
-
- if (!buf_LRU_free_page(bpage, true)) {
- mutex_exit(&buf_pool->LRU_list_mutex);
- }
-
- mutex_exit(pmutex);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
-
- return (NULL);
- }
-
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
- bool corrupted = false;
-
- if (bpage) {
- corrupted = buf_page_check_corrupt(bpage);
+ if (*err) {
+ *err = local_err;
}
- if (corrupted && !bpage->encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR, "Unable"
- " to read tablespace %lu page no"
- " %lu into the buffer pool after"
- " %lu attempts\n"
- "InnoDB: The most probable cause"
- " of this error may be that the"
- " table has been corrupted.\n"
- "InnoDB: You can try to fix this"
- " problem by using"
- " innodb_force_recovery.\n"
- "InnoDB: Please see reference manual"
- " for more details.\n"
- "InnoDB: Aborting...\n",
- space, offset,
- BUF_PAGE_READ_MAX_RETRIES);
-
- ut_error;
- } else {
- ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
- mutex_enter(&buf_pool->LRU_list_mutex);
- mutex_enter(pmutex);
-
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
-
- if (!buf_LRU_free_page(bpage, true)) {
- mutex_exit(&buf_pool->LRU_list_mutex);
- }
-
- mutex_exit(pmutex);
- rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
-
- if (err) {
- *err = DB_DECRYPTION_FAILED;
- }
+ /* Encrypted pages that are not corrupted are marked
+ as encrypted and that fact is later pushed to
+ user thread. */
+ if (local_err == DB_DECRYPTION_FAILED) {
+ return (NULL);
+ }
+ /* Try to set table as corrupted instead of
+ asserting. */
+ if (space > TRX_SYS_SPACE &&
+ dict_set_corrupted_by_space(space)) {
return (NULL);
}
+
+ ib_logf(IB_LOG_LEVEL_FATAL, "Unable"
+ " to read tablespace %lu page no"
+ " %lu into the buffer pool after"
+ " %lu attempts\n"
+ "InnoDB: The most probable cause"
+ " of this error may be that the"
+ " table has been corrupted.\n"
+ "InnoDB: You can try to fix this"
+ " problem by using"
+ " innodb_force_recovery.\n"
+ "InnoDB: Please see reference manual"
+ " for more details.\n"
+ "InnoDB: Aborting...\n",
+ space, offset,
+ BUF_PAGE_READ_MAX_RETRIES);
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -4508,18 +4483,16 @@ buf_page_monitor(
/********************************************************************//**
Mark a table with the specified space pointed by bpage->space corrupted.
Also remove the bpage from LRU list.
-@return TRUE if successful */
+@param[in,out] bpage Block */
static
-ibool
+void
buf_mark_space_corrupt(
-/*===================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
+ buf_page_t* bpage)
{
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
const ibool uncompressed = (buf_page_get_state(bpage)
== BUF_BLOCK_FILE_PAGE);
ulint space = bpage->space;
- ibool ret = TRUE;
const ulint fold = buf_page_address_fold(bpage->space,
bpage->offset);
prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
@@ -4527,42 +4500,34 @@ buf_mark_space_corrupt(
/* First unfix and release lock on the bpage */
ut_ad(!mutex_own(&buf_pool->LRU_list_mutex));
- if (!bpage->encrypted) {
- mutex_enter(&buf_pool->LRU_list_mutex);
- rw_lock_x_lock(hash_lock);
- mutex_enter(buf_page_get_mutex(bpage));
- ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
- ut_ad(bpage->buf_fix_count == 0);
+ mutex_enter(&buf_pool->LRU_list_mutex);
+ rw_lock_x_lock(hash_lock);
+ mutex_enter(buf_page_get_mutex(bpage));
+ ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_READ);
+ ut_ad(bpage->buf_fix_count == 0);
- /* Set BUF_IO_NONE before we remove the block from LRU list */
- buf_page_set_io_fix(bpage, BUF_IO_NONE);
+ /* Set BUF_IO_NONE before we remove the block from LRU list */
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
- if (uncompressed) {
- rw_lock_x_unlock_gen(
- &((buf_block_t*) bpage)->lock,
- BUF_IO_READ);
- }
+ if (uncompressed) {
+ rw_lock_x_unlock_gen(
+ &((buf_block_t*) bpage)->lock,
+ BUF_IO_READ);
}
- /* Find the table with specified space id, and mark it corrupted */
- if (dict_set_corrupted_by_space(space)) {
- if (!bpage->encrypted) {
- buf_LRU_free_one_page(bpage);
- }
- } else {
- if (!bpage->encrypted) {
- mutex_exit(buf_page_get_mutex(bpage));
- }
- ret = FALSE;
+ /* If block is not encrypted find the table with specified
+ space id, and mark it corrupted. Encrypted tables
+ are marked unusable later e.g. in ::open(). */
+ if (!bpage->encrypted) {
+ dict_set_corrupted_by_space(space);
}
- if(!bpage->encrypted) {
- mutex_exit(&buf_pool->LRU_list_mutex);
- ut_ad(buf_pool->n_pend_reads > 0);
- os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
- }
+ /* After this point bpage can't be referenced. */
+ buf_LRU_free_one_page(bpage);
- return(ret);
+ ut_ad(buf_pool->n_pend_reads > 0);
+ os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
+ mutex_exit(&buf_pool->LRU_list_mutex);
}
/********************************************************************//**
@@ -4570,9 +4535,12 @@ Check if page is maybe compressed, encrypted or both when we encounter
corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
@param[in,out] bpage Page
-@return true if page corrupted, false if not */
-UNIV_INTERN
-bool
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
+static
+dberr_t
buf_page_check_corrupt(
buf_page_t* bpage)
{
@@ -4583,6 +4551,7 @@ buf_page_check_corrupt(
fil_space_t* space = fil_space_found_by_id(space_id);
fil_space_crypt_t* crypt_data = space->crypt_data;
bool still_encrypted = false;
+ dberr_t err = DB_SUCCESS;
bool corrupted = false;
ulint page_type = mach_read_from_2(dst_frame + FIL_PAGE_TYPE);
@@ -4605,6 +4574,8 @@ buf_page_check_corrupt(
if (!corrupted) {
bpage->encrypted = false;
+ } else {
+ err = DB_PAGE_CORRUPTED;
}
}
@@ -4620,15 +4591,15 @@ buf_page_check_corrupt(
fil_get_page_type_name(page_type), page_type);
} else if (still_encrypted || (bpage->encrypted && corrupted)) {
bpage->encrypted = true;
- corrupted = true;
+ err = DB_DECRYPTION_FAILED;
ib_logf(IB_LOG_LEVEL_ERROR,
"Block in space_id " ULINTPF " in file %s encrypted.",
space_id, space->name ? space->name : "NULL");
ib_logf(IB_LOG_LEVEL_ERROR,
- "However key management plugin or used key_version %u is not found or"
- " used encryption algorithm or method does not match.",
- bpage->key_version);
+ "However key management plugin or used key_version %u is not found or"
+ " used encryption algorithm or method does not match.",
+ bpage->key_version);
if (space_id > TRX_SYS_SPACE) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Marking tablespace as missing. You may drop this table or"
@@ -4636,18 +4607,21 @@ buf_page_check_corrupt(
}
}
- return corrupted;
+ return (err);
}
/********************************************************************//**
Completes an asynchronous read or write request of a file page to or from
the buffer pool.
-@return true if successful */
+@param[in,out] bpage Page to complete
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-bool
+dberr_t
buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage) /*!< in: pointer to the block in question */
+ buf_page_t* bpage)
{
enum buf_io_fix io_type;
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
@@ -4655,8 +4629,8 @@ buf_page_io_complete(
== BUF_BLOCK_FILE_PAGE);
bool have_LRU_mutex = false;
fil_space_t* space = NULL;
- byte* frame = NULL;
- bool corrupted = false;
+ byte* frame = NULL;
+ dberr_t err = DB_SUCCESS;
ut_a(buf_page_in_file(bpage));
@@ -4695,7 +4669,7 @@ buf_page_io_complete(
"Page %u in tablespace %u zip_decompress failure.",
bpage->offset, bpage->space);
- corrupted = true;
+ err = DB_PAGE_CORRUPTED;
goto database_corrupted;
}
@@ -4745,27 +4719,27 @@ buf_page_io_complete(
if (UNIV_LIKELY(!bpage->is_corrupt ||
!srv_pass_corrupt_table)) {
- corrupted = buf_page_check_corrupt(bpage);
-
+ err = buf_page_check_corrupt(bpage);
}
database_corrupted:
- if (corrupted) {
+ if (err != DB_SUCCESS) {
/* Not a real corruption if it was triggered by
error injection */
DBUG_EXECUTE_IF("buf_page_is_corrupt_failure",
- if (bpage->space > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
+ if (bpage->space > TRX_SYS_SPACE) {
+ buf_mark_space_corrupt(bpage);
ib_logf(IB_LOG_LEVEL_INFO,
"Simulated page corruption");
- return(true);
+ return(err);
}
+ err = DB_SUCCESS;
goto page_not_corrupt;
);
- if (!bpage->encrypted) {
+ if (err == DB_PAGE_CORRUPTED) {
fil_system_enter();
space = fil_space_get_by_id(bpage->space);
fil_system_exit();
@@ -4827,31 +4801,14 @@ database_corrupted:
/* If page space id is larger than TRX_SYS_SPACE
(0), we will attempt to mark the corresponding
table as corrupted instead of crashing server */
- if (bpage->space > TRX_SYS_SPACE
- && buf_mark_space_corrupt(bpage)) {
- return(false);
+ if (bpage->space > TRX_SYS_SPACE) {
+ buf_mark_space_corrupt(bpage);
+ return(err);
} else {
- if (!bpage->encrypted) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Ending processing because of a corrupt database page.");
-
- ut_error;
- }
-
- ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED,
- "Table in tablespace %lu encrypted."
- "However key management plugin or used key_id %lu is not found or"
- " used encryption algorithm or method does not match."
- " Can't continue opening the table.",
- bpage->space, bpage->key_version);
-
- if (bpage->encrypted && bpage->space > TRX_SYS_SPACE) {
- buf_mark_space_corrupt(bpage);
- } else {
- ut_error;
- }
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Ending processing because of a corrupt database page.");
- return(false);
+ ut_error;
}
}
}
@@ -4997,7 +4954,7 @@ retry_mutex:
mutex_exit(block_mutex);
- return(true);
+ return(err);
}
/*********************************************************************//**
diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc
index 4804d71a51f..0add52bcc64 100644
--- a/storage/xtradb/buf/buf0flu.cc
+++ b/storage/xtradb/buf/buf0flu.cc
@@ -992,7 +992,14 @@ buf_flush_write_block_low(
if (sync) {
ut_ad(flush_type == BUF_FLUSH_SINGLE_PAGE);
fil_flush(buf_page_get_space(bpage));
- buf_page_io_complete(bpage);
+ dberr_t err = buf_page_io_complete(bpage);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Page encrypted while evicting a page %u"
+ " from space %u from LRU.",
+ bpage->offset, bpage->space);
+ }
}
/* Increment the counter of I/O operations used
diff --git a/storage/xtradb/buf/buf0rea.cc b/storage/xtradb/buf/buf0rea.cc
index 15465699726..8e5619cedd4 100644
--- a/storage/xtradb/buf/buf0rea.cc
+++ b/storage/xtradb/buf/buf0rea.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, MariaDB Corporation. All Rights Reserved.
+Copyright (c) 2013, 2017, MariaDB Corporation. All Rights Reserved.
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
@@ -103,36 +103,46 @@ flag is cleared and the x-lock released by an i/o-handler thread.
in buf_pool, or if the page is in the doublewrite buffer blocks in
which case it is never read into the pool, or if the tablespace does
not exist or is being dropped
-@return 1 if read request is issued. 0 if it is not */
-UNIV_INTERN
-ulint
-buf_read_page_low(
-/*==============*/
- dberr_t* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
- trying to read from a non-existent tablespace, or a
- tablespace which is just now being dropped */
- bool sync, /*!< in: true if synchronous aio is desired */
- ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ...,
- ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
- at read-ahead functions) */
- ulint space, /*!< in: space id */
- ulint zip_size,/*!< in: compressed page size, or 0 */
- ibool unzip, /*!< in: TRUE=request uncompressed page */
- ib_int64_t tablespace_version, /*!< in: if the space memory object has
+
+@param[out] err DB_SUCCESS, DB_TABLESPACE_DELETED if we are
+ trying to read from a non-existent tablespace, or a
+ tablespace which is just now being dropped,
+ DB_PAGE_CORRUPTED if page based on checksum
+ check is corrupted, or DB_DECRYPTION_FAILED
+ if page post encryption checksum matches but
+ after decryption normal page checksum does not match.
+@param[in] sync true if synchronous aio is desired
+@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...,
+ ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
+ at read-ahead functions)
+@param[in] space space id
+@param[in] zip_size compressed page size, or 0
+@param[in] unzip TRUE=request uncompressed page
+@param[in] tablespace_version if the space memory object has
this timestamp different from what we are giving here,
treat the tablespace as dropped; this is a timestamp we
use to stop dangling page reads from a tablespace
- which we have DISCARDed + IMPORTed back */
- ulint offset, /*!< in: page number */
- trx_t* trx, /*!< in: trx */
- buf_page_t** rbpage) /*!< out: page */
+ which we have DISCARDed + IMPORTed back
+@param[in] offset page number
+@param[in] trx transaction
+@return 1 if read request is issued. 0 if it is not */
+static
+ulint
+buf_read_page_low(
+ dberr_t* err,
+ bool sync,
+ ulint mode,
+ ulint space,
+ ulint zip_size,
+ ibool unzip,
+ ib_int64_t tablespace_version,
+ ulint offset,
+ trx_t* trx = NULL)
{
buf_page_t* bpage;
ulint wake_later;
ibool ignore_nonexistent_pages;
- *err = DB_SUCCESS;
-
wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
mode = mode & ~OS_AIO_SIMULATED_WAKE_LATER;
@@ -259,18 +269,13 @@ not_to_recover:
if (sync) {
/* The i/o is already completed when we arrive from
fil_read */
- if (!buf_page_io_complete(bpage)) {
- if (rbpage) {
- *rbpage = bpage;
- }
+ *err = buf_page_io_complete(bpage);
+
+ if (*err != DB_SUCCESS) {
return(0);
}
}
- if (rbpage) {
- *rbpage = bpage;
- }
-
return(1);
}
@@ -307,7 +312,7 @@ buf_read_ahead_random(
ulint ibuf_mode;
ulint count;
ulint low, high;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_random_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -402,20 +407,29 @@ read_ahead:
mode: hence FALSE as the first parameter */
if (!ibuf_bitmap_page(zip_size, i)) {
+
count += buf_read_page_low(
&err, false,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE,
- tablespace_version, i, trx, NULL);
+ tablespace_version, i, trx);
+
if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Warning: in random"
- " readahead trying to access\n"
- "InnoDB: tablespace %lu page %lu,\n"
- "InnoDB: but the tablespace does not"
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "In random"
+ "readahead trying to access"
+ "tablespace " ULINTPF " page " ULINTPF
+ " but the tablespace does not"
" exist or is just being dropped.\n",
- (ulong) space, (ulong) i);
+ space, i);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "In random readahead read page " ULINTPF
+ " from tablespace " ULINTPF
+ " but page is still encrypted. ",
+ i, space);
}
}
}
@@ -449,20 +463,27 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+
+@param[in] space space_id
+@param[in] zip_size compressed page size in bytes, or 0
+@param[in] offset page number
+@param[in] trx transaction
+@param[out] encrypted true if page encrypted
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-ibool
+dberr_t
buf_read_page(
-/*==========*/
- ulint space, /*!< in: space id */
- ulint zip_size, /*!< in: compressed page size in bytes, or 0 */
- ulint offset, /*!< in: page number */
- trx_t* trx, /*!< in: trx */
- buf_page_t** bpage) /*!< out: page */
+ ulint space,
+ ulint zip_size,
+ ulint offset,
+ trx_t* trx)
{
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
tablespace_version = fil_space_get_version(space);
@@ -471,22 +492,23 @@ buf_read_page(
count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, FALSE,
- tablespace_version, offset, trx, bpage);
+ tablespace_version, offset, trx);
+
srv_stats.buf_pool_reads.add(count);
+
if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: trying to access"
- " tablespace %lu page no. %lu,\n"
- "InnoDB: but the tablespace does not exist"
- " or is just being dropped.\n",
- (ulong) space, (ulong) offset);
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Trying to access"
+ " tablespace " ULINTPF " page no. " ULINTPF
+ " but the tablespace does not exist"
+ " or is just being dropped.",
+ space, offset);
}
/* Increment number of I/O operations used for LRU policy. */
buf_LRU_stat_inc_io();
- return(count > 0);
+ return(err);
}
/********************************************************************//**
@@ -494,23 +516,27 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+@param[in] space Tablespace id
+@param[in] offset Page no
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-ibool
+dberr_t
buf_read_page_async(
-/*================*/
- ulint space, /*!< in: space id */
- ulint offset) /*!< in: page number */
+ ulint space,
+ ulint offset)
{
ulint zip_size;
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
zip_size = fil_space_get_zip_size(space);
if (zip_size == ULINT_UNDEFINED) {
- return(FALSE);
+ return(err);
}
tablespace_version = fil_space_get_version(space);
@@ -519,7 +545,17 @@ buf_read_page_async(
| OS_AIO_SIMULATED_WAKE_LATER
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
space, zip_size, FALSE,
- tablespace_version, offset, NULL,NULL);
+ tablespace_version, offset);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "In async page read "
+ "trying to access"
+ "tablespace " ULINTPF " page " ULINTPF
+ " but failed on error %d.",
+ space, offset, err);
+ }
+
srv_stats.buf_pool_reads.add(count);
/* We do not increment number of I/O operations used for LRU policy
@@ -529,7 +565,7 @@ buf_read_page_async(
these IOs are deliberate and are not part of normal workload we can
ignore these in our heuristics. */
- return(count > 0);
+ return(err);
}
/********************************************************************//**
@@ -580,7 +616,7 @@ buf_read_ahead_linear(
ulint fail_count;
ulint ibuf_mode;
ulint low, high;
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
ulint i;
const ulint buf_read_ahead_linear_area
= BUF_READ_AHEAD_AREA(buf_pool);
@@ -784,20 +820,31 @@ buf_read_ahead_linear(
aio mode: hence FALSE as the first parameter */
if (!ibuf_bitmap_page(zip_size, i)) {
+
count += buf_read_page_low(
&err, false,
ibuf_mode,
- space, zip_size, FALSE, tablespace_version, i, trx, NULL);
+ space, zip_size, FALSE, tablespace_version,
+ i, trx);
+
if (err == DB_TABLESPACE_DELETED) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Warning: in"
- " linear readahead trying to access\n"
- "InnoDB: tablespace %lu page %lu,\n"
- "InnoDB: but the tablespace does not"
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "In random"
+ "readahead trying to access"
+ "tablespace " ULINTPF " page " ULINTPF
+ " but the tablespace does not"
" exist or is just being dropped.\n",
- (ulong) space, (ulong) i);
+ space, i);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "In random readahead read page " ULINTPF
+ " from tablespace " ULINTPF
+ " but page is still encrypted. ",
+ i, space);
}
+
}
}
@@ -858,7 +905,7 @@ buf_read_ibuf_merge_pages(
#endif
for (i = 0; i < n_stored; i++) {
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
buf_pool_t* buf_pool;
ulint zip_size = fil_space_get_zip_size(space_ids[i]);
@@ -877,7 +924,7 @@ buf_read_ibuf_merge_pages(
buf_read_page_low(&err, sync && (i + 1 == n_stored),
BUF_READ_ANY_PAGE, space_ids[i],
zip_size, TRUE, space_versions[i],
- page_nos[i], NULL, NULL);
+ page_nos[i], NULL);
if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
tablespace_deleted:
@@ -888,6 +935,13 @@ tablespace_deleted:
page_nos[i],
zip_size, FALSE);
}
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Read page " ULINTPF " from tablespace " ULINTPF
+ " for insert buffer but page was encrypted.",
+ page_nos[i], space_ids[i]);
+ }
}
os_aio_simulated_wake_handler_threads();
@@ -924,7 +978,7 @@ buf_read_recv_pages(
{
ib_int64_t tablespace_version;
ulint count;
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
ulint i;
zip_size = fil_space_get_zip_size(space);
@@ -1017,12 +1071,21 @@ not_to_recover:
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, TRUE, tablespace_version,
- page_nos[i], NULL, NULL);
+ page_nos[i], NULL);
} else {
buf_read_page_low(&err, false, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, TRUE,
- tablespace_version, page_nos[i], NULL, NULL);
+ tablespace_version, page_nos[i],
+ NULL);
+ }
+
+ if (err == DB_DECRYPTION_FAILED) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Recovery read page " ULINTPF
+ " from tablespace " ULINTPF
+ " but page was encrypted.",
+ page_nos[i], space);
}
}
diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index 848406d9061..f7c6e922d9f 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -6198,8 +6198,15 @@ _fil_io(
mutex_exit(&fil_system->mutex);
if (mode == OS_AIO_NORMAL) {
ut_a(space->purpose == FIL_TABLESPACE);
- buf_page_io_complete(static_cast<buf_page_t *>
- (message));
+ dberr_t err = buf_page_io_complete(static_cast<buf_page_t *>
+ (message));
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "Write operation failed for tablespace %s ("
+ ULINTPF ") offset " ULINTPF " error=%d.",
+ space->name, space->id, byte_offset, err);
+ }
}
}
@@ -6315,7 +6322,15 @@ fil_aio_wait(
if (fil_node->space->purpose == FIL_TABLESPACE) {
srv_set_io_thread_op_info(segment, "complete io for buf page");
- buf_page_io_complete(static_cast<buf_page_t*>(message));
+ buf_page_t* bpage = static_cast<buf_page_t*>(message);
+ dberr_t err = buf_page_io_complete(bpage);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "ibuf write operation failed for tablespace "
+ "%u offset %u error=%d.",
+ bpage->space, bpage->offset, err);
+ }
} else {
srv_set_io_thread_op_info(segment, "complete io for log");
log_io_complete(static_cast<log_group_t*>(message));
diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h
index 6e705e311d5..46185471130 100644
--- a/storage/xtradb/include/buf0buf.h
+++ b/storage/xtradb/include/buf0buf.h
@@ -691,17 +691,6 @@ buf_page_is_corrupted(
const fil_space_t* space)
MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
-Check if page is maybe compressed, encrypted or both when we encounter
-corrupted page. Note that we can't be 100% sure if page is corrupted
-or decrypt/decompress just failed.
-@param[in] bpage Page
-@return true if page corrupted, false if not */
-bool
-buf_page_check_corrupt(
- buf_page_t* bpage) /*!< in/out: buffer page read from disk */
- MY_ATTRIBUTE(( warn_unused_result));
-
-/********************************************************************//**
Checks if a page is all zeroes.
@return TRUE if the page is all zeroes */
bool
@@ -1274,12 +1263,15 @@ buf_page_init_for_read(
/********************************************************************//**
Completes an asynchronous read or write request of a file page to or from
the buffer pool.
-@return true if successful */
+@param[in,out] bpage pointer to the block in question
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-bool
+dberr_t
buf_page_io_complete(
-/*=================*/
- buf_page_t* bpage); /*!< in: pointer to the block in question */
+ buf_page_t* bpage);
/********************************************************************//**
Calculates a folded value of a file page address to use in the page hash
table.
diff --git a/storage/xtradb/include/buf0rea.h b/storage/xtradb/include/buf0rea.h
index f0652b5d2cd..7fd82a41762 100644
--- a/storage/xtradb/include/buf0rea.h
+++ b/storage/xtradb/include/buf0rea.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2015, MariaDB Corporation.
+Copyright (c) 2015, 2017, 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
@@ -35,29 +35,40 @@ High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+
+@param[in] space space_id
+@param[in] zip_size compressed page size in bytes, or 0
+@param[in] offset page number
+@param[in] trx transaction
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-ibool
+dberr_t
buf_read_page(
-/*==========*/
- ulint space, /*!< in: space id */
- ulint zip_size, /*!< in: compressed page size in bytes, or 0 */
- ulint offset, /*!< in: page number */
- trx_t* trx, /*!< in: trx */
- buf_page_t** bpage /*!< out: page */
-);
+ ulint space,
+ ulint zip_size,
+ ulint offset,
+ trx_t* trx);
+
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread.
-@return TRUE if page has been read in, FALSE in case of failure */
+@param[in] space Tablespace id
+@param[in] offset Page number
+@return DB_SUCCESS if page has been read and is not corrupted,
+DB_PAGE_CORRUPTED if page based on checksum check is corrupted,
+DB_DECRYPTION_FAILED if page post encryption checksum matches but
+after decryption normal page checksum does not match.*/
UNIV_INTERN
-ibool
+dberr_t
buf_read_page_async(
-/*================*/
- ulint space, /*!< in: space id */
- ulint offset);/*!< in: page number */
+ ulint space,
+ ulint offset);
+
/********************************************************************//**
Applies a random read-ahead in buf_pool if there are at least a threshold
value of accessed pages from the random read-ahead area. Does not read any
diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h
index b11c5f4ea1a..8bd3beda110 100644
--- a/storage/xtradb/include/db0err.h
+++ b/storage/xtradb/include/db0err.h
@@ -138,6 +138,8 @@ enum dberr_t {
of missing key management plugin,
or missing or incorrect key or
incorret AES method or algorithm. */
+ DB_PAGE_CORRUPTED, /* Page read from tablespace is
+ corrupted. */
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,
diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc
index d9445f6959a..8a83828e7c1 100644
--- a/storage/xtradb/os/os0file.cc
+++ b/storage/xtradb/os/os0file.cc
@@ -2009,10 +2009,6 @@ os_file_create_func(
attributes |= FILE_FLAG_NO_BUFFERING;
#else
if (purpose == OS_FILE_AIO) {
-
- bool encrypt_later; /*!< should the page be encrypted
- before write */
-
#ifdef WIN_ASYNC_IO
/* If specified, use asynchronous (overlapped) io and no
buffering of writes in the OS */