[Commits] 7545c49061d: MDEV-12253: Buffer pool blocks are accessed after they have been freed

jan jan.lindstrom at mariadb.com
Wed Mar 15 16:20:50 EET 2017


revision-id: 7545c49061dbc6f748046a159127c1629d373741 (mariadb-10.1.22-6-g7545c49061d)
parent(s): 854359ffc519292470d29ebcbfe9416968b56da0
author: Jan Lindström
committer: Jan Lindström
timestamp: 2017-03-15 16:19:25 +0200
message:

MDEV-12253: Buffer pool blocks are accessed after they have been freed

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. In read
case only DB_SUCCESS is possible.

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.

---
 mysql-test/suite/encryption/include/innodb-util.pl |  32 +++
 .../encryption/r/innodb-bad-key-change.result      |   5 -
 .../encryption/r/innodb-compressed-blob.result     |  23 ++
 .../suite/encryption/r/innodb-force-corrupt.result |  42 +++
 .../encryption/r/innodb-ibuf-merge-badkey.result   |  48 ++++
 .../suite/encryption/r/innodb-redo-badkey.result   |  48 ++++
 .../suite/encryption/t/innodb-compressed-blob.opt  |   4 +
 .../suite/encryption/t/innodb-compressed-blob.test |  84 ++++++
 .../suite/encryption/t/innodb-force-corrupt.test   | 133 ++++++++++
 .../encryption/t/innodb-ibuf-merge-badkey.test     | 104 ++++++++
 .../suite/encryption/t/innodb-redo-badkey.test     | 103 ++++++++
 .../suite/innodb/r/innodb_bug14147491.result       |   1 +
 mysql-test/suite/innodb/t/innodb_bug14147491.test  |   1 +
 storage/innobase/btr/btr0cur.cc                    |  10 +-
 storage/innobase/btr/btr0pcur.cc                   |  12 +-
 storage/innobase/buf/buf0buf.cc                    | 285 +++++++++------------
 storage/innobase/buf/buf0flu.cc                    |   5 +-
 storage/innobase/buf/buf0rea.cc                    | 207 +++++++++------
 storage/innobase/dict/dict0dict.cc                 |  20 +-
 storage/innobase/dict/dict0stats.cc                |  11 +-
 storage/innobase/fil/fil0fil.cc                    |  17 +-
 storage/innobase/handler/ha_innodb.cc              |   8 +
 storage/innobase/include/btr0pcur.ic               |   5 +
 storage/innobase/include/buf0buf.h                 |  28 +-
 storage/innobase/include/buf0rea.h                 |  32 ++-
 storage/innobase/include/db0err.h                  |   2 +
 storage/innobase/include/dict0dict.h               |  11 +-
 storage/innobase/ut/ut0ut.cc                       |   2 +
 storage/xtradb/btr/btr0cur.cc                      |   7 +-
 storage/xtradb/btr/btr0pcur.cc                     |  12 +-
 storage/xtradb/buf/buf0buf.cc                      | 276 +++++++++-----------
 storage/xtradb/buf/buf0flu.cc                      |   5 +-
 storage/xtradb/buf/buf0rea.cc                      | 223 ++++++++++------
 storage/xtradb/dict/dict0dict.cc                   |  18 ++
 storage/xtradb/dict/dict0stats.cc                  |  11 +-
 storage/xtradb/fil/fil0fil.cc                      |  28 +-
 storage/xtradb/handler/ha_innodb.cc                |   8 +
 storage/xtradb/include/btr0pcur.ic                 |   5 +
 storage/xtradb/include/buf0buf.h                   |  22 +-
 storage/xtradb/include/buf0rea.h                   |  37 +--
 storage/xtradb/include/db0err.h                    |   2 +
 storage/xtradb/include/dict0dict.h                 |   9 +
 storage/xtradb/ut/ut0ut.cc                         |   2 +
 43 files changed, 1385 insertions(+), 563 deletions(-)

diff --git a/mysql-test/suite/encryption/include/innodb-util.pl b/mysql-test/suite/encryption/include/innodb-util.pl
index 241545dac18..5a7295682dd 100644
--- a/mysql-test/suite/encryption/include/innodb-util.pl
+++ b/mysql-test/suite/encryption/include/innodb-util.pl
@@ -4,8 +4,11 @@
 # All the tables must be in the same database, you can call it like so:
 # ib_backup_tablespaces("test", "t1", "blah", ...).
 
+use strict;
+use warnings;
 use File::Copy;
 use File::Spec;
+use Fcntl qw(:DEFAULT :seek);
 
 sub ib_normalize_path {
     my ($path) = @_;
@@ -124,3 +127,32 @@ sub ib_restore_ibd_files {
         ib_restore_ibd_file($tmpd, $datadir, $db, $table);
     }
 }
+
+sub ib_corrupt_tablespace {
+    my ($db, $table) = @_;
+    my $datadir = $ENV{'MYSQLD_DATADIR'};
+    my $page_size = $ENV{'INNODB_PAGE_SIZE'};
+    my $ibd_file = sprintf("%s%s/%s.ibd", $datadir,$db,$table);
+    print "file: $ibd_file $page_size\n";
+#   We try to corrupt FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION field
+    my $len;
+
+    sysopen IBD_FILE, $ibd_file, O_RDWR || die "Unable to open $ibd_file";
+
+    while ($len = sysread(IBD_FILE, $_, $page_size))
+    {
+	sysseek(IBD_FILE, -$len, SEEK_CUR);
+        substr($_, 26, 8) = pack("N",0xdeadbeef);
+	print "Corrupted page with $chunk\n";
+	syswrite(IBD_FILE, $_, $len);
+    }
+    close IBD_FILE;
+}
+
+sub ib_corrupt_tablespaces {
+    my ($db, @tables) = @_;
+    foreach my $table (@tables) {
+        print "corrupt: $table\n";
+        ib_corrupt_tablespace($db, $table);
+    }
+}
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..80cca3cc7df
--- /dev/null
+++ b/mysql-test/suite/encryption/r/innodb-force-corrupt.result
@@ -0,0 +1,42 @@
+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');
+BEGIN;
+INSERT INTO t1 (b,c) VALUES ('corrupt me','moresecretmoresecret');
+INSERT INTO t2 select * from t1;
+INSERT INTO t3 select * from t1;
+COMMIT;
+# 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;
+SELECT * FROM t2;
+SELECT * FROM t3;
+# Restore the original t1.ibd
+DROP TABLE t1,t2,t3;
diff --git a/mysql-test/suite/encryption/r/innodb-ibuf-merge-badkey.result b/mysql-test/suite/encryption/r/innodb-ibuf-merge-badkey.result
new file mode 100644
index 00000000000..a0652b40226
--- /dev/null
+++ b/mysql-test/suite/encryption/r/innodb-ibuf-merge-badkey.result
@@ -0,0 +1,48 @@
+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.");
+# Restart mysqld --file-key-management-filename=keys1.txt
+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 auto_increment, c char(200), b blob) engine=innodb row_format=compressed encrypted=yes;
+create table t2(a int not null primary key auto_increment, c char(200), b blob) engine=innodb row_format=compressed;
+create table t3(a int not null primary key auto_increment, c char(200), b blob) engine=innodb encrypted=yes;
+create table t4(a int not null primary key auto_increment, c char(200), b blob) engine=innodb;
+CREATE INDEX test ON t1 (b(10));
+CREATE INDEX test ON t2 (b(10));
+CREATE INDEX test ON t3 (b(10));
+CREATE INDEX test ON t4 (b(10));
+begin;
+insert into t2 select * from t1;
+insert into t3 select * from t1;
+insert into t4 select * from t1;
+commit;
+begin;
+update t1 set c = repeat('secret3', 20);
+update t2 set c = repeat('secret4', 20);
+update t3 set c = repeat('secret4', 20);
+update t4 set c = repeat('secret4', 20);
+insert into t1 (c,b) values (repeat('secret5',20), repeat('secret6',6000));
+insert into t2 (c,b) values (repeat('secret7',20), repeat('secret8',6000));
+insert into t3 (c,b) values (repeat('secret9',20), repeat('secre10',6000));
+insert into t4 (c,b) values (repeat('secre11',20), repeat('secre12',6000));
+SET GLOBAL innodb_buf_flush_list_now = 1;
+SET GLOBAL innodb_flush_log_at_trx_commit=1;
+COMMIT;
+# Kill the server
+# Restart mysqld --file-key-management-filename=keys2.txt
+# Restart mysqld --file-key-management-filename=keys1.txt
+select count(*) from t1;
+count(*)
+21
+select count(*) from t2;
+count(*)
+21
+select count(*) from t3;
+count(*)
+21
+select count(*) from t4;
+count(*)
+21
+drop table t1, t2,t3,t4;
diff --git a/mysql-test/suite/encryption/r/innodb-redo-badkey.result b/mysql-test/suite/encryption/r/innodb-redo-badkey.result
new file mode 100644
index 00000000000..3a98f676b4d
--- /dev/null
+++ b/mysql-test/suite/encryption/r/innodb-redo-badkey.result
@@ -0,0 +1,48 @@
+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.");
+# Restart mysqld --file-key-management-filename=keys1.txt --innodb-change-buffering=none
+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 auto_increment, c char(200), b blob) engine=innodb row_format=compressed encrypted=yes;
+create table t2(a int not null primary key auto_increment, c char(200), b blob) engine=innodb row_format=compressed;
+create table t3(a int not null primary key auto_increment, c char(200), b blob) engine=innodb encrypted=yes;
+create table t4(a int not null primary key auto_increment, c char(200), b blob) engine=innodb;
+CREATE INDEX test ON t1 (b(10));
+CREATE INDEX test ON t2 (b(10));
+CREATE INDEX test ON t3 (b(10));
+CREATE INDEX test ON t4 (b(10));
+begin;
+insert into t2 select * from t1;
+insert into t3 select * from t1;
+insert into t4 select * from t1;
+commit;
+SET GLOBAL innodb_buf_flush_list_now = 1;
+SET GLOBAL innodb_flush_log_at_trx_commit=1;
+begin;
+update t1 set c = repeat('secret3', 20);
+update t2 set c = repeat('secret4', 20);
+update t3 set c = repeat('secret4', 20);
+update t4 set c = repeat('secret4', 20);
+insert into t1 (c,b) values (repeat('secret5',20), repeat('secret6',6000));
+insert into t2 (c,b) values (repeat('secret7',20), repeat('secret8',6000));
+insert into t3 (c,b) values (repeat('secret9',20), repeat('secre10',6000));
+insert into t4 (c,b) values (repeat('secre11',20), repeat('secre12',6000));
+COMMIT;
+# Kill the server
+# Restart mysqld --file-key-management-filename=keys2.txt
+# Restart mysqld --file-key-management-filename=keys1.txt
+select count(*) from t1;
+count(*)
+21
+select count(*) from t2;
+count(*)
+21
+select count(*) from t3;
+count(*)
+21
+select count(*) from t4;
+count(*)
+21
+drop table t1, t2,t3,t4;
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..14aaa57892d
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-force-corrupt.test
@@ -0,0 +1,133 @@
+#
+# 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 = 100
+while ($i)
+{
+  INSERT INTO t1 (b,c) VALUES (REPEAT('abcabcabc', 100),'secretsecret');
+  dec $i;
+}
+--enable_query_log
+
+BEGIN;
+INSERT INTO t1 (b,c) VALUES ('corrupt me','moresecretmoresecret');
+INSERT INTO t2 select * from t1;
+INSERT INTO t3 select * from t1;
+COMMIT;
+
+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";
+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";
+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
+
+--disable_result_log
+--error 1296
+SELECT * FROM t1;
+#
+# There is change that index is marked as corrupted here
+#
+--error 0,1712
+SELECT * FROM t2;
+--error 1296
+SELECT * FROM t3;
+--enable_result_log
+
+--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/encryption/t/innodb-ibuf-merge-badkey.test b/mysql-test/suite/encryption/t/innodb-ibuf-merge-badkey.test
new file mode 100644
index 00000000000..4081cd5dca7
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-ibuf-merge-badkey.test
@@ -0,0 +1,104 @@
+-- source include/have_innodb.inc
+-- source include/have_file_key_management_plugin.inc
+# embedded does not support restart
+-- source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur.
+--source include/not_valgrind.inc
+# Avoid CrashReporter popup on Mac
+--source include/not_crashrep.inc
+--source include/not_windows.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
+
+--write_file $MYSQLTEST_VARDIR/keys1.txt
+1;770A8A65DA156D24EE2A093277530142
+4;770A8A65DA156D24EE2A093277530143
+EOF
+
+--echo # Restart mysqld --file-key-management-filename=keys1.txt
+-- let $restart_parameters=--plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt
+-- source include/restart_mysqld.inc
+
+--disable_warnings
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+--enable_warnings
+
+set GLOBAL innodb_default_encryption_key_id=4;
+create table t1(a int not null primary key auto_increment, c char(200), b blob) engine=innodb row_format=compressed encrypted=yes;
+create table t2(a int not null primary key auto_increment, c char(200), b blob) engine=innodb row_format=compressed;
+create table t3(a int not null primary key auto_increment, c char(200), b blob) engine=innodb encrypted=yes;
+create table t4(a int not null primary key auto_increment, c char(200), b blob) engine=innodb;
+CREATE INDEX test ON t1 (b(10));
+CREATE INDEX test ON t2 (b(10));
+CREATE INDEX test ON t3 (b(10));
+CREATE INDEX test ON t4 (b(10));
+
+--disable_query_log
+--let $i = 20
+begin;
+while ($i)
+{
+  insert into t1(c,b) values (repeat('secret1',20), repeat('secret2',6000));
+  dec $i;
+}
+commit;
+--enable_query_log
+
+begin;
+insert into t2 select * from t1;
+insert into t3 select * from t1;
+insert into t4 select * from t1;
+commit;
+
+#--source ../../suite/innodb/include/no_checkpoint_start.inc
+begin;
+update t1 set c = repeat('secret3', 20);
+update t2 set c = repeat('secret4', 20);
+update t3 set c = repeat('secret4', 20);
+update t4 set c = repeat('secret4', 20);
+insert into t1 (c,b) values (repeat('secret5',20), repeat('secret6',6000));
+insert into t2 (c,b) values (repeat('secret7',20), repeat('secret8',6000));
+insert into t3 (c,b) values (repeat('secret9',20), repeat('secre10',6000));
+insert into t4 (c,b) values (repeat('secre11',20), repeat('secre12',6000));
+SET GLOBAL innodb_buf_flush_list_now = 1;
+SET GLOBAL innodb_flush_log_at_trx_commit=1;
+COMMIT;
+
+--source include/kill_mysqld.inc
+
+--write_file $MYSQLTEST_VARDIR/keys2.txt
+1;770A8A65DA156D24EE2A093277530998
+4;770A8A65DA156D24EE2A093277530999
+EOF
+
+#
+# Can't start because pages are encrypted with different key
+#
+# The crash is expected
+--echo # Restart mysqld --file-key-management-filename=keys2.txt
+-- let $restart_parameters=--plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys2.txt
+--error 2013
+--enable_reconnect
+
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+--echo # Restart mysqld --file-key-management-filename=keys1.txt
+-- let $restart_parameters=--plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt
+-- source include/start_mysqld.inc
+
+select count(*) from t1;
+select count(*) from t2;
+select count(*) from t3;
+select count(*) from t4;
+
+drop table t1, t2,t3,t4;
+
+--remove_file $MYSQLTEST_VARDIR/keys1.txt
+--remove_file $MYSQLTEST_VARDIR/keys2.txt
diff --git a/mysql-test/suite/encryption/t/innodb-redo-badkey.test b/mysql-test/suite/encryption/t/innodb-redo-badkey.test
new file mode 100644
index 00000000000..83eb2fba02a
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-redo-badkey.test
@@ -0,0 +1,103 @@
+-- source include/have_innodb.inc
+-- source include/have_file_key_management_plugin.inc
+# embedded does not support restart
+-- source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur.
+--source include/not_valgrind.inc
+# Avoid CrashReporter popup on Mac
+--source include/not_crashrep.inc
+--source include/not_windows.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
+
+--write_file $MYSQLTEST_VARDIR/keys1.txt
+1;770A8A65DA156D24EE2A093277530142
+4;770A8A65DA156D24EE2A093277530143
+EOF
+
+--echo # Restart mysqld --file-key-management-filename=keys1.txt --innodb-change-buffering=none
+-- let $restart_parameters=--plugin-load-add=file_key_management.so --innodb-change-buffering=none --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt
+-- source include/restart_mysqld.inc
+
+--disable_warnings
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+--enable_warnings
+
+set GLOBAL innodb_default_encryption_key_id=4;
+create table t1(a int not null primary key auto_increment, c char(200), b blob) engine=innodb row_format=compressed encrypted=yes;
+create table t2(a int not null primary key auto_increment, c char(200), b blob) engine=innodb row_format=compressed;
+create table t3(a int not null primary key auto_increment, c char(200), b blob) engine=innodb encrypted=yes;
+create table t4(a int not null primary key auto_increment, c char(200), b blob) engine=innodb;
+CREATE INDEX test ON t1 (b(10));
+CREATE INDEX test ON t2 (b(10));
+CREATE INDEX test ON t3 (b(10));
+CREATE INDEX test ON t4 (b(10));
+
+--disable_query_log
+--let $i = 20
+begin;
+while ($i)
+{
+  insert into t1(c,b) values (repeat('secret1',20), repeat('secret2',6000));
+  dec $i;
+}
+commit;
+--enable_query_log
+
+begin;
+insert into t2 select * from t1;
+insert into t3 select * from t1;
+insert into t4 select * from t1;
+commit;
+
+SET GLOBAL innodb_buf_flush_list_now = 1;
+SET GLOBAL innodb_flush_log_at_trx_commit=1;
+begin;
+update t1 set c = repeat('secret3', 20);
+update t2 set c = repeat('secret4', 20);
+update t3 set c = repeat('secret4', 20);
+update t4 set c = repeat('secret4', 20);
+insert into t1 (c,b) values (repeat('secret5',20), repeat('secret6',6000));
+insert into t2 (c,b) values (repeat('secret7',20), repeat('secret8',6000));
+insert into t3 (c,b) values (repeat('secret9',20), repeat('secre10',6000));
+insert into t4 (c,b) values (repeat('secre11',20), repeat('secre12',6000));
+COMMIT;
+
+--source include/kill_mysqld.inc
+
+--write_file $MYSQLTEST_VARDIR/keys2.txt
+1;770A8A65DA156D24EE2A093277530998
+4;770A8A65DA156D24EE2A093277530999
+EOF
+
+#
+# Here pages are encrypted with different key compared to one in key file
+#
+# The crash is expected
+--echo # Restart mysqld --file-key-management-filename=keys2.txt
+-- let $restart_parameters=--plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys2.txt
+--error 2013
+--enable_reconnect
+
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+--echo # Restart mysqld --file-key-management-filename=keys1.txt
+-- let $restart_parameters=--plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt
+-- source include/start_mysqld.inc
+
+select count(*) from t1;
+select count(*) from t2;
+select count(*) from t3;
+select count(*) from t4;
+
+drop table t1, t2,t3,t4;
+
+--remove_file $MYSQLTEST_VARDIR/keys1.txt
+--remove_file $MYSQLTEST_VARDIR/keys2.txt
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 07451f71f66..513986e4b3e 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/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
@@ -872,7 +872,7 @@ btr_cur_open_at_index_side_func(
 	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
 	ulint*		offsets		= offsets_;
 	dberr_t		err = DB_SUCCESS;
-	
+
 	rec_offs_init(offsets_);
 
 	estimate = latch_mode & BTR_ESTIMATE;
@@ -4096,6 +4096,11 @@ btr_estimate_number_of_different_key_vals(
 
 		page = btr_cur_get_page(&cursor);
 
+		if (index->table->is_encrypted || index->table->corrupted) {
+			mtr_commit(&mtr);
+			goto exit_loop;
+		}
+
 		rec = page_rec_get_next(page_get_infimum_rec(page));
 
 		if (!page_rec_is_supremum(rec)) {
@@ -4180,6 +4185,7 @@ btr_estimate_number_of_different_key_vals(
 		mtr_commit(&mtr);
 	}
 
+exit_loop:
 	/* If we saw k borders between different key values on
 	n_sample_pages leaf pages, we can estimate how many
 	there will be in index->stat_n_leaf_pages */
diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc
index 01d2e1bb8e2..237e4e8d109 100644
--- a/storage/innobase/btr/btr0pcur.cc
+++ b/storage/innobase/btr/btr0pcur.cc
@@ -416,6 +416,11 @@ btr_pcur_move_to_next_page(
 	cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
 
 	page = btr_pcur_get_page(cursor);
+
+	if (!page) {
+		return;
+	}
+
 	next_page_no = btr_page_get_next(page, mtr);
 	space = buf_block_get_space(btr_pcur_get_block(cursor));
 	zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
@@ -425,11 +430,16 @@ btr_pcur_move_to_next_page(
 	next_block = btr_block_get(space, zip_size, next_page_no,
 				   cursor->latch_mode,
 				   btr_pcur_get_btr_cur(cursor)->index, mtr);
+
+	if (!next_block) {
+		return;
+	}
+
 	next_page = buf_block_get_frame(next_block);
 #ifdef UNIV_BTR_DEBUG
 	ut_a(page_is_comp(next_page) == page_is_comp(page));
 	ut_a(btr_page_get_prev(next_page, mtr)
-	     == buf_block_get_page_no(btr_pcur_get_block(cursor)));
+		== buf_block_get_page_no(btr_pcur_get_block(cursor)));
 #endif /* UNIV_BTR_DEBUG */
 	next_block->check_index_page_at_flush = TRUE;
 
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index c7e2183fa7b..066a68da8c0 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -2358,7 +2358,18 @@ buf_page_get_zip(
 		/* 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: %s (%d).",
+				offset, space, ut_strerr(err), err);
+
+			goto err_exit;
+		}
+
 
 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 		ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2916,7 +2927,6 @@ buf_page_get_gen(
 	}
 
 	if (block == NULL) {
-		buf_page_t*	bpage=NULL;
 
 		/* Page not in buf_pool: needs to be read from file */
 
@@ -2950,7 +2960,18 @@ buf_page_get_gen(
 			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,45 @@ buf_page_get_gen(
 		} 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;
+				goto force_fail;
 			);
 		} 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);
-			}
+force_fail:
+			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 +4393,51 @@ buf_page_monitor(
 /********************************************************************//**
 Mark a table with the specified space pointed by bpage->space corrupted.
 Also remove the bpage from LRU list.
- at return TRUE if successful */
++ at 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);
+	ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
 
-		/* 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(block_mutex);
+	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);
-		}
+	mutex_exit(block_mutex);
+
+	/* 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);
 	} else {
-		ret = FALSE;
+		dict_set_encrypted_by_space(space);
 	}
 
-	if (!bpage->encrypted) {
-		ut_ad(buf_pool->n_pend_reads > 0);
-		buf_pool->n_pend_reads--;
+	/* After this point bpage can't be referenced. */
+	buf_LRU_free_one_page(bpage);
 
-		buf_pool_mutex_exit(buf_pool);
-	}
+	ut_ad(buf_pool->n_pend_reads > 0);
+	buf_pool->n_pend_reads--;
 
-	return(ret);
+	buf_pool_mutex_exit(buf_pool);
 }
 
 /********************************************************************//**
@@ -4470,9 +4445,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
- at return true if page corrupted, false if not */
-UNIV_INTERN
-bool
+ at 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)
 {
@@ -4482,6 +4460,7 @@ buf_page_check_corrupt(
 	ulint space_id = bpage->space;
 	fil_space_t* space = fil_space_acquire_silent(space_id);
 	bool still_encrypted = false;
+	dberr_t err = DB_SUCCESS;
 	bool corrupted = false;
 	ulint page_type = mach_read_from_2(dst_frame + FIL_PAGE_TYPE);
 	fil_space_crypt_t* crypt_data = NULL;
@@ -4507,6 +4486,8 @@ buf_page_check_corrupt(
 
 		if (!corrupted) {
 			bpage->encrypted = false;
+		} else {
+			err = DB_PAGE_CORRUPTED;
 		}
 	}
 
@@ -4522,15 +4503,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 && 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"
@@ -4542,29 +4523,33 @@ buf_page_check_corrupt(
 		fil_space_release(space);
 	}
 
-	return corrupted;
+	return (err);
 }
 
 /********************************************************************//**
 Completes an asynchronous read or write request of a file page to or from
 the buffer pool.
- at return true if successful */
+ at param[in,out]		bpage		Page to complete
+ at param[in]		evict		whether or not to evict the page
+					from LRU list.
+ at 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.
+in write only DB_SUCCESS is possible. */
 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));
 
@@ -4602,6 +4587,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--;
@@ -4648,25 +4635,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();
@@ -4708,31 +4696,12 @@ buf_page_io_complete(
 				/* 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.");
 				}
 			}
 		}
@@ -4861,7 +4830,7 @@ buf_page_io_complete(
 
 	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 3f03ee8256f..e805585ed1e 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -956,7 +956,10 @@ 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);
+
+		/* This is write path, encryption should not fail here. */
+		ut_ad(err == DB_SUCCESS);
 	}
 
 	/* Increment the counter of I/O operations used
diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc
index 285fc465160..69ef9e07ed1 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
+
+ at 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.
+ at param[in]	sync		true if synchronous aio is desired
+ at param[in]	mode		BUF_READ_IBUF_PAGES_ONLY, ...,
+				ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
+				at read-ahead functions)
+ at param[in]	space		space id
+ at param[in]	zip_size	compressed page size, or 0
+ at param[in]	unzip		TRUE=request uncompressed page
+ at 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
+ at 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 @@ buf_read_ahead_random(
 				&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.
- at return TRUE if page has been read in, FALSE in case of failure */
+
+ at param[in]	space		space_id
+ at param[in]	zip_size	compressed page size in bytes, or 0
+ at param[in]	offset		page number
+ at 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,23 @@ 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.
- at return TRUE if page has been read in, FALSE in case of failure */
+ at param[in]	space		Tablespace id
+ at param[in]	offset		Page no */
 UNIV_INTERN
-ibool
+void
 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;
 	}
 
 	tablespace_version = fil_space_get_version(space);
@@ -469,7 +489,9 @@ 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);
+
+	/* Possible decryption errors are already reported. */
 	srv_stats.buf_pool_reads.add(count);
 
 	/* We do not increment number of I/O operations used for LRU policy
@@ -478,8 +500,6 @@ buf_read_page_async(
 	buffer pool. Since this function is called from buffer pool load
 	these IOs are deliberate and are not part of normal workload we can
 	ignore these in our heuristics. */
-
-	return(count > 0);
 }
 
 /********************************************************************//**
@@ -528,7 +548,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 +748,30 @@ buf_read_ahead_linear(
 			count += buf_read_page_low(
 				&err, false,
 				ibuf_mode,
-				space, zip_size, FALSE, tablespace_version, i, NULL);
-			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"
-					" exist or is just being dropped.\n",
-					(ulong) space, (ulong) i);
+				space, zip_size, FALSE, tablespace_version, i);
+
+			switch(err) {
+			case DB_SUCCESS:
+				break;
+			case DB_TABLESPACE_DELETED:
+				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.",
+					space, i);
+				break;
+
+			case 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);
+				break;
+			default:
+				ut_error;
 			}
 		}
 	}
@@ -799,7 +833,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 +852,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 +863,13 @@ buf_read_ibuf_merge_pages(
 						      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 +906,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 +954,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/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 2a11c15441a..7f20c11af28 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -2,7 +2,7 @@
 
 Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2015, MariaDB Corporation.
+Copyright (c) 2013, 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
@@ -6189,6 +6189,24 @@ dict_set_corrupted_by_space(
 }
 
 /**********************************************************************//**
+Flags a table with specified space_id encrypted in the data dictionary
+cache
+ at param[in]	space_id	Tablespace id */
+UNIV_INTERN
+void
+dict_set_encrypted_by_space(
+	ulint	space_id)
+{
+	dict_table_t*   table;
+
+	table = dict_find_table_by_space(space_id);
+
+	if (table) {
+		table->is_encrypted = true;
+	}
+}
+
+/**********************************************************************//**
 Flags an index corrupted both in the data dictionary cache
 and in the SYS_INDEXES */
 UNIV_INTERN
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 6a28f3cdf8f..2d1d49b35bf 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -920,7 +920,11 @@ dict_stats_update_transient_for_index(
 
 		index->stat_n_leaf_pages = size;
 
-		btr_estimate_number_of_different_key_vals(index);
+		/* Do not continue if table decryption has failed or
+		table is already marked as corrupted. */
+		if (!index->table->is_encrypted && !index->table->corrupted) {
+			btr_estimate_number_of_different_key_vals(index);
+		}
 	}
 }
 
@@ -974,8 +978,9 @@ dict_stats_update_transient(
 			continue;
 		}
 
-		/* Do not continue if table decryption has failed. */
-		if (index->table->is_encrypted) {
+		/* Do not continue if table decryption has failed or
+		table is already marked as corrupted. */
+		if (index->table->is_encrypted || index->table->corrupted) {
 			break;
 		}
 
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 74a33b4e4ff..e92bc5155d2 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -6291,6 +6291,8 @@ fil_aio_wait(
 	mutex_enter(&fil_system->mutex);
 
 	fil_node_complete_io(fil_node, fil_system, type);
+	ulint purpose = fil_node->space->purpose;
+	ulint space_id = fil_node->space->id;
 
 	mutex_exit(&fil_system->mutex);
 
@@ -6302,9 +6304,20 @@ fil_aio_wait(
 	deadlocks in the i/o system. We keep tablespace 0 data files always
 	open, and use a special i/o thread to serve insert buffer requests. */
 
-	if (fil_node->space->purpose == FIL_TABLESPACE) {
+	if (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);
+		ulint offset = bpage ? bpage->offset : ULINT_UNDEFINED;
+
+		dberr_t err = buf_page_io_complete(bpage);
+
+		if (err != DB_SUCCESS) {
+			ib_logf(IB_LOG_LEVEL_FATAL,
+				"%s operation failed for tablespace "
+				ULINTPF " offset " ULINTPF " error=%s (%d).",
+				type == OS_FILE_WRITE ? "Write" : "Read",
+				space_id, offset, ut_strerr(err),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/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index c9d78d68092..fc95f0d7cda 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -9588,6 +9588,14 @@ ha_innobase::general_fetch(
 
 	innobase_srv_conc_enter_innodb(prebuilt->trx);
 
+	if (prebuilt->table->corrupted) {
+		DBUG_RETURN(HA_ERR_CRASHED);
+	}
+
+	if (prebuilt->table->is_encrypted) {
+		DBUG_RETURN(HA_ERR_DECRYPTION_FAILED);
+	}
+
 	ret = row_search_for_mysql(
 		(byte*) buf, 0, prebuilt, match_mode, direction);
 
diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic
index 1cd13824542..38e597fba99 100644
--- a/storage/innobase/include/btr0pcur.ic
+++ b/storage/innobase/include/btr0pcur.ic
@@ -357,6 +357,11 @@ btr_pcur_move_to_next(
 			return(FALSE);
 		}
 
+		if (cursor->btr_cur.index->table->corrupted ||
+		    cursor->btr_cur.index->table->is_encrypted) {
+			return(FALSE);
+		}
+
 		btr_pcur_move_to_next_page(cursor, mtr);
 
 		return(TRUE);
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.
- at param[in]	bpage		Page
- at 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.
- at return true if successful */
+ at param[in,out]	bpage		pointer to the block in question
+ at param[in]	evict		true if page should be evicted from LRU
+ at 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..fe6c45b8c10 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,35 @@ 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.
- at return TRUE if page has been read in, FALSE in case of failure */
+
+ at param[in]	space		space_id
+ at param[in]	zip_size	compressed page size in bytes, or 0
+ at param[in]	offset		page number
+ at 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.
- at return TRUE if page has been read in, FALSE in case of failure */
+
+ at param[in]	space		Tablespace id
+ at param[in]	offset		Page number */
 UNIV_INTERN
-ibool
+void
 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/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index 42f93b5a889..20482ee40ac 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -2,7 +2,7 @@
 
 Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2015, MariaDB Corporation.
+Copyright (c) 2013, 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
@@ -1822,6 +1822,15 @@ dict_set_corrupted_by_space(
 /*========================*/
 	ulint		space_id);	/*!< in: space ID */
 
+/**********************************************************************//**
+Flags a table with specified space_id encrypted in the data dictionary
+cache
+ at param[in]	space_id	Tablespace id */
+UNIV_INTERN
+void
+dict_set_encrypted_by_space(
+	ulint	space_id);
+
 /********************************************************************//**
 Validate the table flags.
 @return	true if valid. */
diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc
index bde40220db3..181e713cca9 100644
--- a/storage/innobase/ut/ut0ut.cc
+++ b/storage/innobase/ut/ut0ut.cc
@@ -849,6 +849,8 @@ ut_strerr(
 		return("BLOB record length is greater than 10%% of redo log");
 	case DB_DECRYPTION_FAILED:
 		return("Table is encrypted but decrypt failed.");
+	case DB_PAGE_CORRUPTED:
+		return("Page read from tablespace is corrupted.");
 
 	/* do not add default: in order to produce a warning if new code
 	is added to the enum but not added here */
diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc
index 512b791f212..d15d952175c 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
@@ -4362,6 +4362,11 @@ btr_estimate_number_of_different_key_vals(
 
 		page = btr_cur_get_page(&cursor);
 
+		if (index->table->is_encrypted || index->table->corrupted) {
+			mtr_commit(&mtr);
+			goto exit_loop;
+		}
+
 		SRV_CORRUPT_TABLE_CHECK(page, goto exit_loop;);
 		DBUG_EXECUTE_IF("ib_corrupt_page_while_stats_calc",
 				page = NULL;);
diff --git a/storage/xtradb/btr/btr0pcur.cc b/storage/xtradb/btr/btr0pcur.cc
index dd6ef484fc3..d73bee4dd26 100644
--- a/storage/xtradb/btr/btr0pcur.cc
+++ b/storage/xtradb/btr/btr0pcur.cc
@@ -420,6 +420,11 @@ btr_pcur_move_to_next_page(
 	cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
 
 	page = btr_pcur_get_page(cursor);
+
+	if (!page) {
+		return;
+	}
+
 	next_page_no = btr_page_get_next(page, mtr);
 	space = buf_block_get_space(btr_pcur_get_block(cursor));
 	zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
@@ -429,6 +434,11 @@ btr_pcur_move_to_next_page(
 	next_block = btr_block_get(space, zip_size, next_page_no,
 				   cursor->latch_mode,
 				   btr_pcur_get_btr_cur(cursor)->index, mtr);
+
+	if (!next_block) {
+		return;
+	}
+
 	next_page = buf_block_get_frame(next_block);
 
 	SRV_CORRUPT_TABLE_CHECK(next_page,
@@ -444,7 +454,7 @@ btr_pcur_move_to_next_page(
 #ifdef UNIV_BTR_DEBUG
 	ut_a(page_is_comp(next_page) == page_is_comp(page));
 	ut_a(btr_page_get_prev(next_page, mtr)
-	     == buf_block_get_page_no(btr_pcur_get_block(cursor)));
+		== buf_block_get_page_no(btr_pcur_get_block(cursor)));
 #endif /* UNIV_BTR_DEBUG */
 	next_block->check_index_page_at_flush = TRUE;
 
diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc
index 5016445b8e7..92b052cbc20 100644
--- a/storage/xtradb/buf/buf0buf.cc
+++ b/storage/xtradb/buf/buf0buf.cc
@@ -2351,7 +2351,17 @@ buf_page_get_zip(
 		/* 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: %s (%d).",
+				offset, space, ut_strerr(err), err);
+
+			goto err_exit;
+		}
 
 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 		ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2957,7 +2967,6 @@ buf_page_get_gen(
 	}
 
 	if (block == NULL) {
-		buf_page_t*	bpage=NULL;
 
 		/* Page not in buf_pool: needs to be read from file */
 
@@ -2993,7 +3002,18 @@ buf_page_get_gen(
 			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,47 @@ buf_page_get_gen(
 		} 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;
+				goto force_fail;
 			);
-		} else {
-			bool corrupted = false;
-
-			if (bpage) {
-				corrupted = buf_page_check_corrupt(bpage);
-			}
-
-			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);
+		} else {
+			if (*err) {
+				*err = local_err;
+			}
 
-				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);
 			}
+
+force_fail:
+			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
@@ -4499,61 +4477,54 @@ buf_page_monitor(
 /********************************************************************//**
 Mark a table with the specified space pointed by bpage->space corrupted.
 Also remove the bpage from LRU list.
- at return TRUE if successful */
+ at 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);
+	ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
 
 	/* 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(block_mutex);
+	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);
-		}
+	/* 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);
 	} else {
-		if (!bpage->encrypted) {
-			mutex_exit(buf_page_get_mutex(bpage));
-		}
-		ret = FALSE;
+		dict_set_encrypted_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);
 }
 
 /********************************************************************//**
@@ -4561,9 +4532,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
- at return true if page corrupted, false if not */
-UNIV_INTERN
-bool
+ at 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)
 {
@@ -4573,6 +4547,7 @@ buf_page_check_corrupt(
 	ulint space_id = bpage->space;
 	fil_space_t* space = fil_space_acquire_silent(space_id);
 	bool still_encrypted = false;
+	dberr_t err = DB_SUCCESS;
 	bool corrupted = false;
 	ulint page_type = mach_read_from_2(dst_frame + FIL_PAGE_TYPE);
 	fil_space_crypt_t* crypt_data = NULL;
@@ -4599,6 +4574,8 @@ buf_page_check_corrupt(
 
 		if (!corrupted) {
 			bpage->encrypted = false;
+		} else {
+			err = DB_PAGE_CORRUPTED;
 		}
 	}
 
@@ -4614,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 && 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"
@@ -4634,18 +4611,22 @@ buf_page_check_corrupt(
 		fil_space_release(space);
 	}
 
-	return corrupted;
+	return (err);
 }
 
 /********************************************************************//**
 Completes an asynchronous read or write request of a file page to or from
 the buffer pool.
- at return true if successful */
+ at param[in,out]		bpage		Page to complete
+ at 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.
+in write only DB_SUCCESS is possible. */
 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);
@@ -4653,8 +4634,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));
 
@@ -4693,7 +4674,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;
 			}
@@ -4743,27 +4724,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();
@@ -4825,31 +4806,14 @@ buf_page_io_complete(
 				/* 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;
 				}
 			}
 		}
@@ -4995,7 +4959,7 @@ buf_page_io_complete(
 
 	mutex_exit(block_mutex);
 
-	return(true);
+	return(err);
 }
 
 /*********************************************************************//**
diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc
index 4804d71a51f..177e4af7cbc 100644
--- a/storage/xtradb/buf/buf0flu.cc
+++ b/storage/xtradb/buf/buf0flu.cc
@@ -992,7 +992,10 @@ 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);
+
+		/* This is write path, encryption should not fail here. */
+		ut_ad(err == DB_SUCCESS);
 	}
 
 	/* Increment the counter of I/O operations used
diff --git a/storage/xtradb/buf/buf0rea.cc b/storage/xtradb/buf/buf0rea.cc
index 15465699726..bb3104ce614 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
- at 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
+
+ at 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.
+ at param[in]	sync		true if synchronous aio is desired
+ at param[in]	mode		BUF_READ_IBUF_PAGES_ONLY, ...,
+				ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
+				at read-ahead functions)
+ at param[in]	space		space id
+ at param[in]	zip_size	compressed page size, or 0
+ at param[in]	unzip		TRUE=request uncompressed page
+ at 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
+ at param[in]	offset		page number
+ at param[in]	trx		transaction
+ at 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 @@ 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);
 }
 
@@ -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 @@ buf_read_ahead_random(
 		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.
- at return TRUE if page has been read in, FALSE in case of failure */
+
+ at param[in]	space		space_id
+ at param[in]	zip_size	compressed page size in bytes, or 0
+ at param[in]	offset		page number
+ at param[in]	trx		transaction
+ at param[out]	encrypted	true if page encrypted
+ at 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,23 @@ 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.
- at return TRUE if page has been read in, FALSE in case of failure */
+ at param[in]	space		Tablespace id
+ at param[in]	offset		Page no */
 UNIV_INTERN
-ibool
+void
 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;
 	}
 
 	tablespace_version = fil_space_get_version(space);
@@ -519,7 +541,9 @@ 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);
+
+	/* Possible decryption errors are already reported. */
 	srv_stats.buf_pool_reads.add(count);
 
 	/* We do not increment number of I/O operations used for LRU policy
@@ -528,8 +552,6 @@ buf_read_page_async(
 	buffer pool. Since this function is called from buffer pool load
 	these IOs are deliberate and are not part of normal workload we can
 	ignore these in our heuristics. */
-
-	return(count > 0);
 }
 
 /********************************************************************//**
@@ -580,7 +602,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 +806,37 @@ 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);
-			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"
-					" exist or is just being dropped.\n",
-					(ulong) space, (ulong) i);
+				space, zip_size, FALSE, tablespace_version,
+				i, trx);
+
+			switch(err) {
+			case DB_SUCCESS:
+				break;
+			case DB_TABLESPACE_DELETED:
+				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.",
+					space, i);
+				break;
+
+			case 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);
+				break;
+			default:
+				ut_error;
 			}
+
 		}
 	}
 
@@ -858,7 +897,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 +916,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 +927,13 @@ buf_read_ibuf_merge_pages(
 						      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 +970,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 +1063,21 @@ 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, 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/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc
index 49de1cf7ef8..b887209559f 100644
--- a/storage/xtradb/dict/dict0dict.cc
+++ b/storage/xtradb/dict/dict0dict.cc
@@ -6189,6 +6189,24 @@ dict_set_corrupted_by_space(
 }
 
 /**********************************************************************//**
+Flags a table with specified space_id encrypted in the data dictionary
+cache
+ at param[in]	space_id	Tablespace id */
+UNIV_INTERN
+void
+dict_set_encrypted_by_space(
+	ulint	space_id)
+{
+	dict_table_t*   table;
+
+	table = dict_find_table_by_space(space_id);
+
+	if (table) {
+		table->is_encrypted = true;
+	}
+}
+
+/**********************************************************************//**
 Flags an index corrupted both in the data dictionary cache
 and in the SYS_INDEXES */
 UNIV_INTERN
diff --git a/storage/xtradb/dict/dict0stats.cc b/storage/xtradb/dict/dict0stats.cc
index 6a28f3cdf8f..2d1d49b35bf 100644
--- a/storage/xtradb/dict/dict0stats.cc
+++ b/storage/xtradb/dict/dict0stats.cc
@@ -920,7 +920,11 @@ dict_stats_update_transient_for_index(
 
 		index->stat_n_leaf_pages = size;
 
-		btr_estimate_number_of_different_key_vals(index);
+		/* Do not continue if table decryption has failed or
+		table is already marked as corrupted. */
+		if (!index->table->is_encrypted && !index->table->corrupted) {
+			btr_estimate_number_of_different_key_vals(index);
+		}
 	}
 }
 
@@ -974,8 +978,9 @@ dict_stats_update_transient(
 			continue;
 		}
 
-		/* Do not continue if table decryption has failed. */
-		if (index->table->is_encrypted) {
+		/* Do not continue if table decryption has failed or
+		table is already marked as corrupted. */
+		if (index->table->is_encrypted || index->table->corrupted) {
 			break;
 		}
 
diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index 36900839160..6cb07657769 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -6251,8 +6251,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);
+				}
 			}
 		}
 
@@ -6355,6 +6362,8 @@ fil_aio_wait(
 	mutex_enter(&fil_system->mutex);
 
 	fil_node_complete_io(fil_node, fil_system, type);
+	ulint purpose = fil_node->space->purpose;
+	space_id = fil_node->space->id;
 
 	mutex_exit(&fil_system->mutex);
 
@@ -6366,9 +6375,20 @@ fil_aio_wait(
 	deadlocks in the i/o system. We keep tablespace 0 data files always
 	open, and use a special i/o thread to serve insert buffer requests. */
 
-	if (fil_node->space->purpose == FIL_TABLESPACE) {
+	if (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);
+		ulint offset = bpage ? bpage->offset : ULINT_UNDEFINED;
+
+		dberr_t err = buf_page_io_complete(bpage);
+
+		if (err != DB_SUCCESS) {
+			ib_logf(IB_LOG_LEVEL_FATAL,
+				"%s operation failed for tablespace "
+				ULINTPF " offset " ULINTPF " error=%s (%d).",
+				type == OS_FILE_WRITE ? "Write" : "Read",
+				space_id, offset, ut_strerr(err),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/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 4ca4259273f..8a57d3a721b 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -10232,6 +10232,14 @@ ha_innobase::general_fetch(
 
 	innobase_srv_conc_enter_innodb(prebuilt->trx);
 
+	if (prebuilt->table->corrupted) {
+		DBUG_RETURN(HA_ERR_CRASHED);
+	}
+
+	if (prebuilt->table->is_encrypted) {
+		DBUG_RETURN(HA_ERR_DECRYPTION_FAILED);
+	}
+
 	ret = row_search_for_mysql(
 		(byte*) buf, 0, prebuilt, match_mode, direction);
 
diff --git a/storage/xtradb/include/btr0pcur.ic b/storage/xtradb/include/btr0pcur.ic
index 1cd13824542..38e597fba99 100644
--- a/storage/xtradb/include/btr0pcur.ic
+++ b/storage/xtradb/include/btr0pcur.ic
@@ -357,6 +357,11 @@ btr_pcur_move_to_next(
 			return(FALSE);
 		}
 
+		if (cursor->btr_cur.index->table->corrupted ||
+		    cursor->btr_cur.index->table->is_encrypted) {
+			return(FALSE);
+		}
+
 		btr_pcur_move_to_next_page(cursor, mtr);
 
 		return(TRUE);
diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h
index 1774d9445ff..f232aed30c0 100644
--- a/storage/xtradb/include/buf0buf.h
+++ b/storage/xtradb/include/buf0buf.h
@@ -690,17 +690,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.
- at param[in]	bpage		Page
- at 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
@@ -1273,12 +1262,15 @@ buf_page_init_for_read(
 /********************************************************************//**
 Completes an asynchronous read or write request of a file page to or from
 the buffer pool.
- at return true if successful */
+ at param[in,out]	bpage		pointer to the block in question
+ at 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..6b9b2ccce75 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,36 @@ 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.
- at return TRUE if page has been read in, FALSE in case of failure */
+
+ at param[in]	space		space_id
+ at param[in]	zip_size	compressed page size in bytes, or 0
+ at param[in]	offset		page number
+ at param[in]	trx		transaction
+ at 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.
- at return TRUE if page has been read in, FALSE in case of failure */
+ at param[in]	space		Tablespace id
+ at param[in]	offset		Page number */
 UNIV_INTERN
-ibool
+void
 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/include/dict0dict.h b/storage/xtradb/include/dict0dict.h
index 1622b927a76..7b0c9f4c465 100644
--- a/storage/xtradb/include/dict0dict.h
+++ b/storage/xtradb/include/dict0dict.h
@@ -1820,6 +1820,15 @@ dict_set_corrupted_by_space(
 /*========================*/
 	ulint		space_id);	/*!< in: space ID */
 
+/**********************************************************************//**
+Flags a table with specified space_id encrypted in the data dictionary
+cache
+ at param[in]	space_id	Tablespace id */
+UNIV_INTERN
+void
+dict_set_encrypted_by_space(
+	ulint	space_id);
+
 /********************************************************************//**
 Validate the table flags.
 @return	true if valid. */
diff --git a/storage/xtradb/ut/ut0ut.cc b/storage/xtradb/ut/ut0ut.cc
index acedb56879a..fd52537ae11 100644
--- a/storage/xtradb/ut/ut0ut.cc
+++ b/storage/xtradb/ut/ut0ut.cc
@@ -852,6 +852,8 @@ ut_strerr(
 		return("BLOB record length is greater than 10%% of redo log");
 	case DB_DECRYPTION_FAILED:
 		return("Table is encrypted but decrypt failed.");
+	case DB_PAGE_CORRUPTED:
+		return("Page read from tablespace is corrupted.");
 
 	/* do not add default: in order to produce a warning if new code
 	is added to the enum but not added here */


More information about the commits mailing list