@@ -913,6 +913,7 @@ struct ftrace_hash {
913913 unsigned long size_bits ;
914914 struct hlist_head * buckets ;
915915 unsigned long count ;
916+ struct rcu_head rcu ;
916917};
917918
918919/*
@@ -1058,6 +1059,21 @@ static void free_ftrace_hash(struct ftrace_hash *hash)
10581059 kfree (hash );
10591060}
10601061
1062+ static void __free_ftrace_hash_rcu (struct rcu_head * rcu )
1063+ {
1064+ struct ftrace_hash * hash ;
1065+
1066+ hash = container_of (rcu , struct ftrace_hash , rcu );
1067+ free_ftrace_hash (hash );
1068+ }
1069+
1070+ static void free_ftrace_hash_rcu (struct ftrace_hash * hash )
1071+ {
1072+ if (!hash || hash == EMPTY_HASH )
1073+ return ;
1074+ call_rcu_sched (& hash -> rcu , __free_ftrace_hash_rcu );
1075+ }
1076+
10611077static struct ftrace_hash * alloc_ftrace_hash (int size_bits )
10621078{
10631079 struct ftrace_hash * hash ;
@@ -1122,7 +1138,8 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src)
11221138 struct ftrace_func_entry * entry ;
11231139 struct hlist_node * tp , * tn ;
11241140 struct hlist_head * hhd ;
1125- struct ftrace_hash * hash = * dst ;
1141+ struct ftrace_hash * old_hash ;
1142+ struct ftrace_hash * new_hash ;
11261143 unsigned long key ;
11271144 int size = src -> count ;
11281145 int bits = 0 ;
@@ -1133,13 +1150,11 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src)
11331150 * the empty_hash.
11341151 */
11351152 if (!src -> count ) {
1136- free_ftrace_hash (* dst );
1137- * dst = EMPTY_HASH ;
1153+ free_ftrace_hash_rcu (* dst );
1154+ rcu_assign_pointer ( * dst , EMPTY_HASH ) ;
11381155 return 0 ;
11391156 }
11401157
1141- ftrace_hash_clear (hash );
1142-
11431158 /*
11441159 * Make the hash size about 1/2 the # found
11451160 */
@@ -1150,27 +1165,9 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src)
11501165 if (bits > FTRACE_HASH_MAX_BITS )
11511166 bits = FTRACE_HASH_MAX_BITS ;
11521167
1153- /* We can't modify the empty_hash */
1154- if (hash == EMPTY_HASH ) {
1155- /* Create a new hash */
1156- * dst = alloc_ftrace_hash (bits );
1157- if (!* dst ) {
1158- * dst = EMPTY_HASH ;
1159- return - ENOMEM ;
1160- }
1161- hash = * dst ;
1162- } else {
1163- size = 1 << bits ;
1164-
1165- /* Use the old hash, but create new buckets */
1166- hhd = kzalloc (sizeof (* hhd ) * size , GFP_KERNEL );
1167- if (!hhd )
1168- return - ENOMEM ;
1169-
1170- kfree (hash -> buckets );
1171- hash -> buckets = hhd ;
1172- hash -> size_bits = bits ;
1173- }
1168+ new_hash = alloc_ftrace_hash (bits );
1169+ if (!new_hash )
1170+ return - ENOMEM ;
11741171
11751172 size = 1 << src -> size_bits ;
11761173 for (i = 0 ; i < size ; i ++ ) {
@@ -1181,10 +1178,14 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src)
11811178 else
11821179 key = 0 ;
11831180 remove_hash_entry (src , entry );
1184- __add_hash_entry (hash , entry );
1181+ __add_hash_entry (new_hash , entry );
11851182 }
11861183 }
11871184
1185+ old_hash = * dst ;
1186+ rcu_assign_pointer (* dst , new_hash );
1187+ free_ftrace_hash_rcu (old_hash );
1188+
11881189 return 0 ;
11891190}
11901191
0 commit comments