aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/ftrace.c158
1 files changed, 142 insertions, 16 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 46f08264980b..5dd332cc5aa8 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -890,6 +890,10 @@ static const struct ftrace_hash empty_hash = {
890}; 890};
891#define EMPTY_HASH ((struct ftrace_hash *)&empty_hash) 891#define EMPTY_HASH ((struct ftrace_hash *)&empty_hash)
892 892
893enum {
894 FTRACE_OPS_FL_ENABLED = 1,
895};
896
893struct ftrace_ops global_ops = { 897struct ftrace_ops global_ops = {
894 .func = ftrace_stub, 898 .func = ftrace_stub,
895 .notrace_hash = EMPTY_HASH, 899 .notrace_hash = EMPTY_HASH,
@@ -1161,6 +1165,105 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src)
1161 } \ 1165 } \
1162 } 1166 }
1163 1167
1168static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
1169 int filter_hash,
1170 bool inc)
1171{
1172 struct ftrace_hash *hash;
1173 struct ftrace_hash *other_hash;
1174 struct ftrace_page *pg;
1175 struct dyn_ftrace *rec;
1176 int count = 0;
1177 int all = 0;
1178
1179 /* Only update if the ops has been registered */
1180 if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
1181 return;
1182
1183 /*
1184 * In the filter_hash case:
1185 * If the count is zero, we update all records.
1186 * Otherwise we just update the items in the hash.
1187 *
1188 * In the notrace_hash case:
1189 * We enable the update in the hash.
1190 * As disabling notrace means enabling the tracing,
1191 * and enabling notrace means disabling, the inc variable
1192 * gets inversed.
1193 */
1194 if (filter_hash) {
1195 hash = ops->filter_hash;
1196 other_hash = ops->notrace_hash;
1197 if (!hash->count)
1198 all = 1;
1199 } else {
1200 inc = !inc;
1201 hash = ops->notrace_hash;
1202 other_hash = ops->filter_hash;
1203 /*
1204 * If the notrace hash has no items,
1205 * then there's nothing to do.
1206 */
1207 if (!hash->count)
1208 return;
1209 }
1210
1211 do_for_each_ftrace_rec(pg, rec) {
1212 int in_other_hash = 0;
1213 int in_hash = 0;
1214 int match = 0;
1215
1216 if (all) {
1217 /*
1218 * Only the filter_hash affects all records.
1219 * Update if the record is not in the notrace hash.
1220 */
1221 if (!ftrace_lookup_ip(other_hash, rec->ip))
1222 match = 1;
1223 } else {
1224 in_hash = !!ftrace_lookup_ip(hash, rec->ip);
1225 in_other_hash = !!ftrace_lookup_ip(other_hash, rec->ip);
1226
1227 /*
1228 *
1229 */
1230 if (filter_hash && in_hash && !in_other_hash)
1231 match = 1;
1232 else if (!filter_hash && in_hash &&
1233 (in_other_hash || !other_hash->count))
1234 match = 1;
1235 }
1236 if (!match)
1237 continue;
1238
1239 if (inc) {
1240 rec->flags++;
1241 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == FTRACE_REF_MAX))
1242 return;
1243 } else {
1244 if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == 0))
1245 return;
1246 rec->flags--;
1247 }
1248 count++;
1249 /* Shortcut, if we handled all records, we are done. */
1250 if (!all && count == hash->count)
1251 return;
1252 } while_for_each_ftrace_rec();
1253}
1254
1255static void ftrace_hash_rec_disable(struct ftrace_ops *ops,
1256 int filter_hash)
1257{
1258 __ftrace_hash_rec_update(ops, filter_hash, 0);
1259}
1260
1261static void ftrace_hash_rec_enable(struct ftrace_ops *ops,
1262 int filter_hash)
1263{
1264 __ftrace_hash_rec_update(ops, filter_hash, 1);
1265}
1266
1164static void ftrace_free_rec(struct dyn_ftrace *rec) 1267static void ftrace_free_rec(struct dyn_ftrace *rec)
1165{ 1268{
1166 rec->freelist = ftrace_free_records; 1269 rec->freelist = ftrace_free_records;
@@ -1276,26 +1379,24 @@ int ftrace_text_reserved(void *start, void *end)
1276static int 1379static int
1277__ftrace_replace_code(struct dyn_ftrace *rec, int enable) 1380__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
1278{ 1381{
1279 struct ftrace_ops *ops = &global_ops;
1280 unsigned long ftrace_addr; 1382 unsigned long ftrace_addr;
1281 unsigned long flag = 0UL; 1383 unsigned long flag = 0UL;
1282 1384
1283 ftrace_addr = (unsigned long)FTRACE_ADDR; 1385 ftrace_addr = (unsigned long)FTRACE_ADDR;
1284 1386
1285 /* 1387 /*
1286 * If this record is not to be traced or we want to disable it, 1388 * If we are enabling tracing:
1287 * then disable it.
1288 * 1389 *
1289 * If we want to enable it and filtering is off, then enable it. 1390 * If the record has a ref count, then we need to enable it
1391 * because someone is using it.
1290 * 1392 *
1291 * If we want to enable it and filtering is on, enable it only if 1393 * Otherwise we make sure its disabled.
1292 * it's filtered 1394 *
1395 * If we are disabling tracing, then disable all records that
1396 * are enabled.
1293 */ 1397 */
1294 if (enable && !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) { 1398 if (enable && (rec->flags & ~FTRACE_FL_MASK))
1295 if (!ops->filter_hash->count || 1399 flag = FTRACE_FL_ENABLED;
1296 ftrace_lookup_ip(ops->filter_hash, rec->ip))
1297 flag = FTRACE_FL_ENABLED;
1298 }
1299 1400
1300 /* If the state of this record hasn't changed, then do nothing */ 1401 /* If the state of this record hasn't changed, then do nothing */
1301 if ((rec->flags & FTRACE_FL_ENABLED) == flag) 1402 if ((rec->flags & FTRACE_FL_ENABLED) == flag)
@@ -1423,17 +1524,25 @@ static void ftrace_startup_enable(int command)
1423 1524
1424static void ftrace_startup(int command) 1525static void ftrace_startup(int command)
1425{ 1526{
1527 struct ftrace_ops *ops = &global_ops;
1528
1426 if (unlikely(ftrace_disabled)) 1529 if (unlikely(ftrace_disabled))
1427 return; 1530 return;
1428 1531
1429 ftrace_start_up++; 1532 ftrace_start_up++;
1430 command |= FTRACE_ENABLE_CALLS; 1533 command |= FTRACE_ENABLE_CALLS;
1431 1534
1535 ops->flags |= FTRACE_OPS_FL_ENABLED;
1536 if (ftrace_start_up == 1)
1537 ftrace_hash_rec_enable(ops, 1);
1538
1432 ftrace_startup_enable(command); 1539 ftrace_startup_enable(command);
1433} 1540}
1434 1541
1435static void ftrace_shutdown(int command) 1542static void ftrace_shutdown(int command)
1436{ 1543{
1544 struct ftrace_ops *ops = &global_ops;
1545
1437 if (unlikely(ftrace_disabled)) 1546 if (unlikely(ftrace_disabled))
1438 return; 1547 return;
1439 1548
@@ -1446,7 +1555,12 @@ static void ftrace_shutdown(int command)
1446 WARN_ON_ONCE(ftrace_start_up < 0); 1555 WARN_ON_ONCE(ftrace_start_up < 0);
1447 1556
1448 if (!ftrace_start_up) 1557 if (!ftrace_start_up)
1558 ftrace_hash_rec_disable(ops, 1);
1559
1560 if (!ftrace_start_up) {
1449 command |= FTRACE_DISABLE_CALLS; 1561 command |= FTRACE_DISABLE_CALLS;
1562 ops->flags &= ~FTRACE_OPS_FL_ENABLED;
1563 }
1450 1564
1451 if (saved_ftrace_func != ftrace_trace_function) { 1565 if (saved_ftrace_func != ftrace_trace_function) {
1452 saved_ftrace_func = ftrace_trace_function; 1566 saved_ftrace_func = ftrace_trace_function;
@@ -2668,6 +2782,7 @@ ftrace_regex_release(struct inode *inode, struct file *file)
2668 struct ftrace_iterator *iter; 2782 struct ftrace_iterator *iter;
2669 struct ftrace_hash **orig_hash; 2783 struct ftrace_hash **orig_hash;
2670 struct trace_parser *parser; 2784 struct trace_parser *parser;
2785 int filter_hash;
2671 int ret; 2786 int ret;
2672 2787
2673 mutex_lock(&ftrace_regex_lock); 2788 mutex_lock(&ftrace_regex_lock);
@@ -2687,15 +2802,26 @@ ftrace_regex_release(struct inode *inode, struct file *file)
2687 trace_parser_put(parser); 2802 trace_parser_put(parser);
2688 2803
2689 if (file->f_mode & FMODE_WRITE) { 2804 if (file->f_mode & FMODE_WRITE) {
2690 if (iter->flags & FTRACE_ITER_NOTRACE) 2805 filter_hash = !!(iter->flags & FTRACE_ITER_FILTER);
2691 orig_hash = &iter->ops->notrace_hash; 2806
2692 else 2807 if (filter_hash)
2693 orig_hash = &iter->ops->filter_hash; 2808 orig_hash = &iter->ops->filter_hash;
2809 else
2810 orig_hash = &iter->ops->notrace_hash;
2694 2811
2695 mutex_lock(&ftrace_lock); 2812 mutex_lock(&ftrace_lock);
2813 /*
2814 * Remove the current set, update the hash and add
2815 * them back.
2816 */
2817 ftrace_hash_rec_disable(iter->ops, filter_hash);
2696 ret = ftrace_hash_move(orig_hash, iter->hash); 2818 ret = ftrace_hash_move(orig_hash, iter->hash);
2697 if (!ret && ftrace_start_up && ftrace_enabled) 2819 if (!ret) {
2698 ftrace_run_update_code(FTRACE_ENABLE_CALLS); 2820 ftrace_hash_rec_enable(iter->ops, filter_hash);
2821 if (iter->ops->flags & FTRACE_OPS_FL_ENABLED
2822 && ftrace_enabled)
2823 ftrace_run_update_code(FTRACE_ENABLE_CALLS);
2824 }
2699 mutex_unlock(&ftrace_lock); 2825 mutex_unlock(&ftrace_lock);
2700 } 2826 }
2701 free_ftrace_hash(iter->hash); 2827 free_ftrace_hash(iter->hash);