diff --git a/mysql-test/suite/innodb/r/innodb_temp_create_fail_einval.result b/mysql-test/suite/innodb/r/innodb_temp_create_fail_einval.result new file mode 100644 index 0000000..7695bd4 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_temp_create_fail_einval.result @@ -0,0 +1,41 @@ +# test for posix_fallocate for creating temp table +# returns errors EINVAL +# restart +# Restart server to cleanup the temp tablespaces +# create connections and temp tables to fill up temp +# tablespace which allocated by default. +# establishing connection 1 +# establishing connection 2 +# establishing connection 3 +# establishing connection 4 +# establishing connection 5 +SET SESSION debug='+d,ib_temp_posix_fallocate_fail_einval'; +CREATE TEMPORARY TABLE ttext1(c1 INT, c2 TEXT); +SELECT ID,PATH FROM INFORMATION_SCHEMA.INNODB_SESSION_TEMP_TABLESPACES ORDER BY ID, PATH; +ID PATH +0 ./#innodb_temp/temp_11.ibt +0 ./#innodb_temp/temp_12.ibt +0 ./#innodb_temp/temp_13.ibt +0 ./#innodb_temp/temp_14.ibt +0 ./#innodb_temp/temp_15.ibt +0 ./#innodb_temp/temp_16.ibt +0 ./#innodb_temp/temp_17.ibt +0 ./#innodb_temp/temp_18.ibt +0 ./#innodb_temp/temp_19.ibt +8 ./#innodb_temp/temp_10.ibt +9 ./#innodb_temp/temp_8.ibt +9 ./#innodb_temp/temp_9.ibt +10 ./#innodb_temp/temp_6.ibt +10 ./#innodb_temp/temp_7.ibt +11 ./#innodb_temp/temp_4.ibt +11 ./#innodb_temp/temp_5.ibt +12 ./#innodb_temp/temp_2.ibt +12 ./#innodb_temp/temp_3.ibt +13 ./#innodb_temp/temp_1.ibt +13 ./#innodb_temp/temp_20.ibt +SET SESSION debug='-d,ib_temp_posix_fallocate_fail_einval'; +# cleaning up connection connection_1 +# cleaning up connection connection_2 +# cleaning up connection connection_3 +# cleaning up connection connection_4 +# cleaning up connection connection_5 diff --git a/mysql-test/suite/innodb/t/innodb_temp_create_fail_einval.test b/mysql-test/suite/innodb/t/innodb_temp_create_fail_einval.test new file mode 100644 index 0000000..d884036 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_temp_create_fail_einval.test @@ -0,0 +1,58 @@ +--source include/linux.inc + +--source include/have_debug.inc + +--echo # test for posix_fallocate for creating temp table +--echo # returns errors EINVAL +--source include/restart_mysqld.inc + +--echo # Restart server to cleanup the temp tablespaces + +--echo # create connections and temp tables to fill up temp +--echo # tablespace which allocated by default. + +--disable_query_log +--disable_result_log +--let $connection_number = 1 +while($connection_number <= 4) +{ + --let $connection_name = connection_$connection_number + --echo # establishing connection $connection_number + --connect ($connection_name, localhost, root,,) + --disable_query_log + + CREATE TEMPORARY TABLE ttext1(c1 INT, c2 TEXT); + SELECT * FROM INFORMATION_SCHEMA.INNODB_SESSION_TEMP_TABLESPACES; + + --inc $connection_number +} +--enable_result_log +--enable_query_log + +# Force server to return EINVAL error after posix_fallocate +--let $connection_name = connection_$connection_number +--echo # establishing connection $connection_number +--connect ($connection_name, localhost, root,,) +SET SESSION debug='+d,ib_temp_posix_fallocate_fail_einval'; + +CREATE TEMPORARY TABLE ttext1(c1 INT, c2 TEXT); +SELECT ID,PATH FROM INFORMATION_SCHEMA.INNODB_SESSION_TEMP_TABLESPACES ORDER BY ID, PATH; + +SET SESSION debug='-d,ib_temp_posix_fallocate_fail_einval'; + +--connection default + +--disable_query_log +--let $connection_number = 1 +while($connection_number <= 5) +{ + --let $connection_name = connection_$connection_number + --connection $connection_name + --echo # cleaning up connection $connection_name + + --disconnect $connection_name + + --inc $connection_number +} +--enable_query_log + diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 737f828..e9e0c8d 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -5566,7 +5566,20 @@ static dberr_t fil_create_tablespace(space_id_t space_id, const char *name, if (type == FIL_TYPE_TEMPORARY || fil_fusionio_enable_atomic_write(file)) { int ret = posix_fallocate(file.m_file, 0, size * page_size.physical()); - if (ret != 0) { + DBUG_EXECUTE_IF("ib_temp_posix_fallocate_fail_einval", ret = EINVAL;); + + if (ret == EINVAL && type == FIL_TYPE_TEMPORARY) { + /* For temp table, we already pass the valid offset and len in, if EINVAL + is returned, it could only mean that the file system doesn't + support fallocate(), currently one known case is ext3 with O_DIRECT. + + Also because above call could be interrupted, in this case, + simply go to plan B by calling os_file_set_size. */ + atomic_write = false; + + success = os_file_set_size(path, file, 0, size * page_size.physical(), + srv_read_only_mode, true); + } else if (ret != 0) { ib::error(ER_IB_MSG_303, path, ulonglong{size * page_size.physical()}, ret); success = false;