@@ -411,16 +411,24 @@ static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
411
411
412
412
/*
413
413
A mutex LOCK_plugin_delete must be acquired before calling plugin_del
414
- function.
414
+ function.
415
415
*/
416
416
mysql_mutex_t LOCK_plugin_delete;
417
417
418
- /*
419
- A mutex LOCK_plugin must be acquired before accessing the
420
- following variables/structures.
418
+ /* *
419
+ Serializes access to the global plugin memory list.
420
+
421
+ LOCK_plugin must be acquired before accessing
422
+ plugin_dl_array, plugin_array and plugin_hash.
421
423
We are always manipulating ref count, so a rwlock here is unneccessary.
424
+ If it must be taken together with the LOCK_system_variables_hash then
425
+ LOCK_plugin must be taken before LOCK_system_variables_hash.
422
426
*/
423
427
mysql_mutex_t LOCK_plugin;
428
+ /* *
429
+ Serializes the INSTALL and UNINSTALL PLUGIN commands.
430
+ Must be taken before LOCK_plugin.
431
+ */
424
432
mysql_mutex_t LOCK_plugin_install;
425
433
static Prealloced_array<st_plugin_dl*, 16 > *plugin_dl_array;
426
434
static Prealloced_array<st_plugin_int*, 16 > *plugin_array;
@@ -561,6 +569,7 @@ static inline void free_plugin_mem(st_plugin_dl *p)
561
569
Fills in a ::st_plugin_dl structure.
562
570
Initializes the plugin services pointer inside the plugin.
563
571
Does not initialize the individual plugins.
572
+ Must have LOCK_plugin locked. On error releases LOCK_plugin.
564
573
565
574
@arg dl The path to the plugin binary to load
566
575
@arg report a bitmask that's passed down to report_error()
@@ -590,6 +599,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
590
599
system_charset_info, 1 ) ||
591
600
plugin_dir_len + dl->length + 1 >= FN_REFLEN)
592
601
{
602
+ mysql_mutex_unlock (&LOCK_plugin);
593
603
report_error (report, ER_UDF_NO_PATHS);
594
604
DBUG_RETURN (NULL );
595
605
}
@@ -624,6 +634,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
624
634
if (*errmsg == ' :' ) errmsg++;
625
635
if (*errmsg == ' ' ) errmsg++;
626
636
}
637
+ mysql_mutex_unlock (&LOCK_plugin);
627
638
report_error (report, ER_CANT_OPEN_LIBRARY, dlpath, error_number, errmsg);
628
639
629
640
/*
@@ -644,6 +655,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
644
655
if (!(sym= dlsym (plugin_dl.handle , plugin_interface_version_sym)))
645
656
{
646
657
free_plugin_mem (&plugin_dl);
658
+ mysql_mutex_unlock (&LOCK_plugin);
647
659
report_error (report, ER_CANT_FIND_DL_ENTRY, plugin_interface_version_sym);
648
660
DBUG_RETURN (NULL );
649
661
}
@@ -653,6 +665,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
653
665
(plugin_dl.version >> 8 ) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8 ))
654
666
{
655
667
free_plugin_mem (&plugin_dl);
668
+ mysql_mutex_unlock (&LOCK_plugin);
656
669
report_error (report, ER_CANT_OPEN_LIBRARY, dlpath, 0 ,
657
670
" plugin interface version mismatch" );
658
671
DBUG_RETURN (NULL );
@@ -672,6 +685,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
672
685
my_snprintf (buf, sizeof (buf),
673
686
" service '%s' interface version mismatch" ,
674
687
list_of_services[i].name );
688
+ mysql_mutex_unlock (&LOCK_plugin);
675
689
report_error (report, ER_CANT_OPEN_LIBRARY, dlpath, 0 , buf);
676
690
DBUG_RETURN (NULL );
677
691
}
@@ -683,6 +697,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
683
697
if (!(sym= dlsym (plugin_dl.handle , plugin_declarations_sym)))
684
698
{
685
699
free_plugin_mem (&plugin_dl);
700
+ mysql_mutex_unlock (&LOCK_plugin);
686
701
report_error (report, ER_CANT_FIND_DL_ENTRY, plugin_declarations_sym);
687
702
DBUG_RETURN (NULL );
688
703
}
@@ -721,6 +736,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
721
736
if (!cur)
722
737
{
723
738
free_plugin_mem (&plugin_dl);
739
+ mysql_mutex_unlock (&LOCK_plugin);
724
740
report_error (report, ER_OUTOFMEMORY,
725
741
static_cast <int >(plugin_dl.dl .length ));
726
742
DBUG_RETURN (NULL );
@@ -750,6 +766,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
750
766
for ( ; plugin->info ; ++plugin)
751
767
if (plugin->flags & PLUGIN_OPT_NO_INSTALL)
752
768
{
769
+ mysql_mutex_unlock (&LOCK_plugin);
753
770
report_error (report, ER_PLUGIN_NO_INSTALL, plugin->name );
754
771
free_plugin_mem (&plugin_dl);
755
772
DBUG_RETURN (NULL );
@@ -761,6 +778,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
761
778
if (! (plugin_dl.dl .str = (char *) my_malloc (key_memory_mysql_plugin_dl,
762
779
plugin_dl.dl .length , MYF (0 ))))
763
780
{
781
+ mysql_mutex_unlock (&LOCK_plugin);
764
782
free_plugin_mem (&plugin_dl);
765
783
report_error (report, ER_OUTOFMEMORY,
766
784
static_cast <int >(plugin_dl.dl .length ));
@@ -773,6 +791,7 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
773
791
/* Add this dll to array */
774
792
if (! (tmp= plugin_dl_insert_or_reuse (&plugin_dl)))
775
793
{
794
+ mysql_mutex_unlock (&LOCK_plugin);
776
795
free_plugin_mem (&plugin_dl);
777
796
report_error (report, ER_OUTOFMEMORY,
778
797
static_cast <int >(sizeof (st_plugin_dl)));
@@ -956,9 +975,12 @@ static st_plugin_int *plugin_insert_or_reuse(st_plugin_int *plugin)
956
975
}
957
976
958
977
959
- /*
960
- NOTE
961
- Requires that a write-lock is held on LOCK_system_variables_hash
978
+ /* *
979
+ Adds a plugin to the global plugin list.
980
+
981
+ Also installs the plugin variables.
982
+ In case of error releases ::LOCK_plugin and reports the error
983
+ @note Requires that a write-lock is held on ::LOCK_system_variables_hash
962
984
*/
963
985
static bool plugin_add (MEM_ROOT *tmp_root,
964
986
const LEX_STRING *name, const LEX_STRING *dl,
@@ -974,13 +996,14 @@ static bool plugin_add(MEM_ROOT *tmp_root,
974
996
{
975
997
mysql_mutex_unlock (&LOCK_plugin);
976
998
report_error (report, ER_UDF_EXISTS, name->str );
977
- mysql_mutex_lock (&LOCK_plugin);
978
- DBUG_RETURN (TRUE );
999
+ DBUG_RETURN (true );
979
1000
}
980
1001
/* Clear the whole struct to catch future extensions. */
981
1002
memset (&tmp, 0 , sizeof (tmp));
982
- if (! (tmp.plugin_dl = plugin_dl_add (dl, report)))
983
- DBUG_RETURN (TRUE );
1003
+ if (!(tmp.plugin_dl = plugin_dl_add (dl, report)))
1004
+ {
1005
+ DBUG_RETURN (true );
1006
+ }
984
1007
/* Find plugin by name */
985
1008
for (plugin= tmp.plugin_dl ->plugins ; plugin->info ; plugin++)
986
1009
{
@@ -997,14 +1020,17 @@ static bool plugin_add(MEM_ROOT *tmp_root,
997
1020
((*(int *)plugin->info ) >> 8 ) >
998
1021
(cur_plugin_info_interface_version[plugin->type ] >> 8 ))
999
1022
{
1000
- char buf[256 ];
1023
+ char buf[256 ], dl_name[FN_REFLEN] ;
1001
1024
strxnmov (buf, sizeof (buf) - 1 , " API version for " ,
1002
1025
plugin_type_names[plugin->type ].str ,
1003
1026
" plugin is too different" , NullS);
1027
+ /* copy the library name so we can release the mutex */
1028
+ strncpy (dl_name, dl->str , sizeof (dl_name) - 1 );
1029
+ dl_name[sizeof (dl_name) - 1 ] = 0 ;
1030
+ plugin_dl_del (dl);
1004
1031
mysql_mutex_unlock (&LOCK_plugin);
1005
- report_error (report, ER_CANT_OPEN_LIBRARY, dl->str , 0 , buf);
1006
- mysql_mutex_lock (&LOCK_plugin);
1007
- goto err;
1032
+ report_error (report, ER_CANT_OPEN_LIBRARY, dl_name, 0 , buf);
1033
+ DBUG_RETURN (true );
1008
1034
}
1009
1035
tmp.plugin = plugin;
1010
1036
tmp.name .str = (char *)plugin->name ;
@@ -1023,25 +1049,21 @@ static bool plugin_add(MEM_ROOT *tmp_root,
1023
1049
{
1024
1050
init_alloc_root (key_memory_plugin_int_mem_root,
1025
1051
&tmp_plugin_ptr->mem_root , 4096 , 4096 );
1026
- DBUG_RETURN (FALSE );
1052
+ DBUG_RETURN (false );
1027
1053
}
1028
1054
tmp_plugin_ptr->state = PLUGIN_IS_FREED;
1029
1055
}
1030
1056
mysql_del_sys_var_chain (tmp.system_vars );
1031
1057
restore_pluginvar_names (tmp.system_vars );
1032
- goto err;
1033
-
1034
- /* plugin was disabled */
1035
1058
plugin_dl_del (dl);
1036
- DBUG_RETURN (FALSE );
1059
+ mysql_mutex_unlock (&LOCK_plugin);
1060
+ DBUG_RETURN (true );
1037
1061
}
1038
1062
}
1063
+ plugin_dl_del (dl);
1039
1064
mysql_mutex_unlock (&LOCK_plugin);
1040
1065
report_error (report, ER_CANT_FIND_DL_ENTRY, name->str );
1041
- mysql_mutex_lock (&LOCK_plugin);
1042
- err:
1043
- plugin_dl_del (dl);
1044
- DBUG_RETURN (TRUE );
1066
+ DBUG_RETURN (true );
1045
1067
}
1046
1068
1047
1069
@@ -1709,8 +1731,17 @@ static bool register_builtin(st_mysql_plugin *plugin,
1709
1731
}
1710
1732
1711
1733
1712
- /*
1713
- called only by plugin_register_dynamic_and_init_all()
1734
+ /* *
1735
+ Reads the plugins from mysql.plugin and loads them
1736
+
1737
+ Called only by plugin_register_dynamic_and_init_all()
1738
+ a.k.a. the bootstrap sequence.
1739
+
1740
+ @arg tmp_root memory root to use for plugin_add()
1741
+ @arg argc number of command line arguments to process
1742
+ @arg argv array of command line argument to read values from
1743
+ @retval true failure
1744
+ @retval false success
1714
1745
*/
1715
1746
static void plugin_load (MEM_ROOT *tmp_root, int *argc, char **argv)
1716
1747
{
@@ -1751,7 +1782,6 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
1751
1782
environment, and it uses mysql_mutex_assert_owner(), so we lock
1752
1783
the mutex here to satisfy the assert
1753
1784
*/
1754
- mysql_mutex_lock (&LOCK_plugin);
1755
1785
while (!(error= read_record_info.read_record (&read_record_info)))
1756
1786
{
1757
1787
DBUG_PRINT (" info" , (" init plugin record" ));
@@ -1762,12 +1792,27 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
1762
1792
LEX_STRING name= {(char *)str_name.ptr (), str_name.length ()};
1763
1793
LEX_STRING dl= {(char *)str_dl.ptr (), str_dl.length ()};
1764
1794
1795
+ /*
1796
+ The whole locking sequence is not strictly speaking needed since this
1797
+ is a function that's executed only during server bootstrap, but we do
1798
+ it properly for uniformity of the environment for plugin_add.
1799
+ Note that it must be done for each iteration since, unlike INSTALL PLUGIN
1800
+ the bootstrap process just reports the error and goes on.
1801
+ So to ensure the right sequence of lock and unlock we need to take and
1802
+ release both the wlock and the mutex.
1803
+ */
1804
+ mysql_mutex_lock (&LOCK_plugin);
1805
+ mysql_rwlock_wrlock (&LOCK_system_variables_hash);
1765
1806
if (plugin_add (tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1807
+ {
1766
1808
LogErr (WARNING_LEVEL, ER_PLUGIN_CANT_LOAD,
1767
- str_name.c_ptr (), str_dl.c_ptr ());
1809
+ str_name.c_ptr (), str_dl.c_ptr ());
1810
+ }
1811
+ else
1812
+ mysql_mutex_unlock (&LOCK_plugin);
1813
+ mysql_rwlock_unlock (&LOCK_system_variables_hash);
1768
1814
free_root (tmp_root, MYF (MY_MARK_BLOCKS_FREE));
1769
1815
}
1770
- mysql_mutex_unlock (&LOCK_plugin);
1771
1816
if (error > 0 )
1772
1817
{
1773
1818
char errbuf[MYSQL_ERRMSG_SIZE];
@@ -1783,9 +1828,18 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
1783
1828
}
1784
1829
1785
1830
1786
- /*
1787
- called by plugin_register_early_plugins() and
1788
- plugin_register_dynamic_and_init_all()
1831
+ /* *
1832
+ Load a list of plugins
1833
+
1834
+ Called by plugin_register_early_plugins() and
1835
+ plugin_register_dynamic_and_init_all(), a.k.a. the bootstrap sequence.
1836
+
1837
+ @arg tmp_root memory root to use for plugin_add()
1838
+ @arg argc number of command line arguments to process
1839
+ @arg argv array of command line argument to read values from
1840
+ @arg list list of plugins to load. Ends with a NULL pointer
1841
+ @retval true failure
1842
+ @retval false success
1789
1843
*/
1790
1844
static bool plugin_load_list (MEM_ROOT *tmp_root, int *argc, char **argv,
1791
1845
const char *list)
@@ -1822,7 +1876,13 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
1822
1876
}
1823
1877
1824
1878
dl= name;
1879
+ /*
1880
+ The whole locking sequence is not strictly speaking needed since this
1881
+ is a function that's executed only during server bootstrap, but we do
1882
+ it properly for uniformity of the environment for plugin_add.
1883
+ */
1825
1884
mysql_mutex_lock (&LOCK_plugin);
1885
+ mysql_rwlock_wrlock (&LOCK_system_variables_hash);
1826
1886
if ((plugin_dl= plugin_dl_add (&dl, REPORT_TO_LOG)))
1827
1887
{
1828
1888
for (plugin= plugin_dl->plugins ; plugin->info ; plugin++)
@@ -1832,19 +1892,37 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
1832
1892
1833
1893
free_root (tmp_root, MYF (MY_MARK_BLOCKS_FREE));
1834
1894
if (plugin_add (tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1895
+ {
1896
+ mysql_rwlock_unlock (&LOCK_system_variables_hash);
1835
1897
goto error;
1898
+ }
1836
1899
}
1837
1900
plugin_dl_del (&dl); // reduce ref count
1838
1901
}
1902
+ else
1903
+ {
1904
+ mysql_rwlock_unlock (&LOCK_system_variables_hash);
1905
+ goto error;
1906
+ }
1839
1907
}
1840
1908
else
1841
1909
{
1842
1910
free_root (tmp_root, MYF (MY_MARK_BLOCKS_FREE));
1911
+ /*
1912
+ The whole locking sequence is not strictly speaking needed since this
1913
+ is a function that's executed only during server bootstrap, but we do
1914
+ it properly for uniformity of the environment for plugin_add.
1915
+ */
1843
1916
mysql_mutex_lock (&LOCK_plugin);
1917
+ mysql_rwlock_wrlock (&LOCK_system_variables_hash);
1844
1918
if (plugin_add (tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
1919
+ {
1920
+ mysql_rwlock_unlock (&LOCK_system_variables_hash);
1845
1921
goto error;
1922
+ }
1846
1923
}
1847
1924
mysql_mutex_unlock (&LOCK_plugin);
1925
+ mysql_rwlock_unlock (&LOCK_system_variables_hash);
1848
1926
name.length = dl.length = 0 ;
1849
1927
dl.str = NULL ; name.str = p= buffer;
1850
1928
str= &name;
@@ -1866,7 +1944,6 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
1866
1944
}
1867
1945
DBUG_RETURN (FALSE );
1868
1946
error:
1869
- mysql_mutex_unlock (&LOCK_plugin);
1870
1947
LogErr (ERROR_LEVEL, ER_PLUGIN_CANT_LOAD, name.str , dl.str );
1871
1948
DBUG_RETURN (TRUE );
1872
1949
}
@@ -2172,8 +2249,8 @@ static bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
2172
2249
&argc, &argv, NULL ))
2173
2250
{
2174
2251
mysql_rwlock_unlock (&LOCK_system_variables_hash);
2175
- report_error (REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str );
2176
2252
mysql_mutex_unlock (&LOCK_plugin);
2253
+ report_error (REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str );
2177
2254
goto err;
2178
2255
}
2179
2256
default_argv= argv;
@@ -2185,16 +2262,20 @@ static bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
2185
2262
if (pv && pv->append_read_only_variables (&argc, &argv, TRUE ))
2186
2263
{
2187
2264
mysql_rwlock_unlock (&LOCK_system_variables_hash);
2188
- report_error (REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str );
2189
2265
mysql_mutex_unlock (&LOCK_plugin);
2266
+ report_error (REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str );
2190
2267
goto err;
2191
2268
}
2192
2269
error= plugin_add (thd->mem_root , name, dl, &argc, argv, REPORT_TO_USER);
2193
2270
if (default_argv)
2194
2271
free_defaults (default_argv);
2195
2272
mysql_rwlock_unlock (&LOCK_system_variables_hash);
2196
2273
2197
- if (error || !(tmp= plugin_find_internal (name_cstr, MYSQL_ANY_PLUGIN)))
2274
+ /* LOCK_plugin already unlocked by plugin_add() if error */
2275
+ if (error)
2276
+ goto err;
2277
+
2278
+ if (!(tmp= plugin_find_internal (name_cstr, MYSQL_ANY_PLUGIN)))
2198
2279
{
2199
2280
mysql_mutex_unlock (&LOCK_plugin);
2200
2281
goto err;
0 commit comments