Skip to content

Commit f926428

Browse files
committed
MDEV-12761 Error return from external_lock make the server crash
bunch of bugs when external_lock() fails on unlock: * mi_lock_database() used mi_mark_crashed() under share->intern_lock, but mi_mark_crashed() itself locks this mutex. * handler::close() required table to be unlocked, but failed external_lock didn't count as unlock * mysql_unlock_tables() ignored all unlock errors, but they still set the error status in stmt_da.
1 parent 52aa200 commit f926428

File tree

5 files changed

+38
-12
lines changed

5 files changed

+38
-12
lines changed

mysql-test/r/myisam_debug.result

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,15 @@ CHECK TABLE t1;
2727
Table Op Msg_type Msg_text
2828
test.t1 check status OK
2929
DROP TABLE t1,t2;
30+
call mtr.add_suppression('Incorrect key file for table');
31+
create table t1 (a int, index(a));
32+
lock tables t1 write;
33+
insert t1 values (1),(2),(1);
34+
set @old_dbug=@@debug_dbug;
35+
set debug_dbug='+d,mi_lock_database_failure';
36+
unlock tables;
37+
Warnings:
38+
Error 126 Incorrect key file for table './test/t1.MYI'; try to repair it
39+
Error 1015 Can't lock file (errno: 22 "Invalid argument")
40+
set debug_dbug=@old_dbug;
41+
drop table t1;

mysql-test/t/myisam_debug.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,16 @@ KILL QUERY @thread_id;
5959
CHECK TABLE t1;
6060
DROP TABLE t1,t2;
6161
DISCONNECT insertConn;
62+
63+
#
64+
# MDEV-12761 Error return from external_lock make the server crash
65+
#
66+
call mtr.add_suppression('Incorrect key file for table');
67+
create table t1 (a int, index(a));
68+
lock tables t1 write;
69+
insert t1 values (1),(2),(1);
70+
set @old_dbug=@@debug_dbug;
71+
set debug_dbug='+d,mi_lock_database_failure';
72+
unlock tables;
73+
set debug_dbug=@old_dbug;
74+
drop table t1;

sql/handler.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5944,7 +5944,7 @@ int handler::ha_external_lock(THD *thd, int lock_type)
59445944
MYSQL_TABLE_LOCK_WAIT(m_psi, PSI_TABLE_EXTERNAL_LOCK, lock_type,
59455945
{ error= external_lock(thd, lock_type); })
59465946

5947-
if (error == 0)
5947+
if (error == 0 || lock_type == F_UNLCK)
59485948
{
59495949
m_lock_type= lock_type;
59505950
cached_table_flags= table_flags();

sql/lock.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,15 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
380380
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
381381
{
382382
DBUG_ENTER("mysql_unlock_tables");
383+
bool errors= thd->is_error();
383384
if (sql_lock->table_count)
384385
unlock_external(thd, sql_lock->table, sql_lock->table_count);
385386
if (sql_lock->lock_count)
386387
thr_multi_unlock(sql_lock->locks, sql_lock->lock_count, 0);
387388
if (free_lock)
388389
my_free(sql_lock);
390+
if (!errors)
391+
thd->clear_error();
389392
DBUG_VOID_RETURN;
390393
}
391394

storage/myisam/mi_locking.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ static void mi_update_status_with_lock(MI_INFO *info);
2929

3030
int mi_lock_database(MI_INFO *info, int lock_type)
3131
{
32-
int error;
32+
int error, mark_crashed= 0;
3333
uint count;
3434
MYISAM_SHARE *share=info->s;
3535
DBUG_ENTER("mi_lock_database");
@@ -52,6 +52,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
5252
}
5353

5454
error= 0;
55+
DBUG_EXECUTE_IF ("mi_lock_database_failure", error= EINVAL;);
5556
mysql_mutex_lock(&share->intern_lock);
5657
if (share->kfile >= 0) /* May only be false on windows */
5758
{
@@ -75,17 +76,15 @@ int mi_lock_database(MI_INFO *info, int lock_type)
7576
&share->dirty_part_map,
7677
FLUSH_KEEP))
7778
{
78-
error=my_errno;
79+
mark_crashed= error=my_errno;
7980
mi_print_error(info->s, HA_ERR_CRASHED);
80-
mi_mark_crashed(info); /* Mark that table must be checked */
8181
}
8282
if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
8383
{
8484
if (end_io_cache(&info->rec_cache))
8585
{
86-
error=my_errno;
86+
mark_crashed= error=my_errno;
8787
mi_print_error(info->s, HA_ERR_CRASHED);
88-
mi_mark_crashed(info);
8988
}
9089
}
9190
if (!count)
@@ -110,22 +109,19 @@ int mi_lock_database(MI_INFO *info, int lock_type)
110109
share->state.unique= info->last_unique= info->this_unique;
111110
share->state.update_count= info->last_loop= ++info->this_loop;
112111
if (mi_state_info_write(share->kfile, &share->state, 1))
113-
error=my_errno;
112+
mark_crashed= error=my_errno;
114113
share->changed=0;
115114
if (myisam_flush)
116115
{
117116
if (mysql_file_sync(share->kfile, MYF(0)))
118-
error= my_errno;
117+
mark_crashed= error= my_errno;
119118
if (mysql_file_sync(info->dfile, MYF(0)))
120-
error= my_errno;
119+
mark_crashed= error= my_errno;
121120
}
122121
else
123122
share->not_flushed=1;
124123
if (error)
125-
{
126124
mi_print_error(info->s, HA_ERR_CRASHED);
127-
mi_mark_crashed(info);
128-
}
129125
}
130126
if (info->lock_type != F_EXTRA_LCK)
131127
{
@@ -260,6 +256,8 @@ int mi_lock_database(MI_INFO *info, int lock_type)
260256
}
261257
#endif
262258
mysql_mutex_unlock(&share->intern_lock);
259+
if (mark_crashed)
260+
mi_mark_crashed(info);
263261
DBUG_RETURN(error);
264262
} /* mi_lock_database */
265263

0 commit comments

Comments
 (0)