diff options
Diffstat (limited to 'kernel/trace/trace.c')
| -rw-r--r-- | kernel/trace/trace.c | 273 |
1 files changed, 244 insertions, 29 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 76dfe6d2466c..a917bea82715 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -197,12 +197,14 @@ unsigned long nsecs_to_usecs(unsigned long nsecs) | |||
| 197 | * NEED_RESCED - reschedule is requested | 197 | * NEED_RESCED - reschedule is requested |
| 198 | * HARDIRQ - inside an interrupt handler | 198 | * HARDIRQ - inside an interrupt handler |
| 199 | * SOFTIRQ - inside a softirq handler | 199 | * SOFTIRQ - inside a softirq handler |
| 200 | * CONT - multiple entries hold the trace item | ||
| 200 | */ | 201 | */ |
| 201 | enum trace_flag_type { | 202 | enum trace_flag_type { |
| 202 | TRACE_FLAG_IRQS_OFF = 0x01, | 203 | TRACE_FLAG_IRQS_OFF = 0x01, |
| 203 | TRACE_FLAG_NEED_RESCHED = 0x02, | 204 | TRACE_FLAG_NEED_RESCHED = 0x02, |
| 204 | TRACE_FLAG_HARDIRQ = 0x04, | 205 | TRACE_FLAG_HARDIRQ = 0x04, |
| 205 | TRACE_FLAG_SOFTIRQ = 0x08, | 206 | TRACE_FLAG_SOFTIRQ = 0x08, |
| 207 | TRACE_FLAG_CONT = 0x10, | ||
| 206 | }; | 208 | }; |
| 207 | 209 | ||
| 208 | /* | 210 | /* |
| @@ -1074,6 +1076,7 @@ enum trace_file_type { | |||
| 1074 | TRACE_FILE_LAT_FMT = 1, | 1076 | TRACE_FILE_LAT_FMT = 1, |
| 1075 | }; | 1077 | }; |
| 1076 | 1078 | ||
| 1079 | /* Return the current entry. */ | ||
| 1077 | static struct trace_entry * | 1080 | static struct trace_entry * |
| 1078 | trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data, | 1081 | trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data, |
| 1079 | struct trace_iterator *iter, int cpu) | 1082 | struct trace_iterator *iter, int cpu) |
| @@ -1104,8 +1107,58 @@ trace_entry_idx(struct trace_array *tr, struct trace_array_cpu *data, | |||
| 1104 | return &array[iter->next_page_idx[cpu]]; | 1107 | return &array[iter->next_page_idx[cpu]]; |
| 1105 | } | 1108 | } |
| 1106 | 1109 | ||
| 1110 | /* Increment the index counter of an iterator by one */ | ||
| 1111 | static void trace_iterator_increment(struct trace_iterator *iter, int cpu) | ||
| 1112 | { | ||
| 1113 | iter->idx++; | ||
| 1114 | iter->next_idx[cpu]++; | ||
| 1115 | iter->next_page_idx[cpu]++; | ||
| 1116 | |||
| 1117 | if (iter->next_page_idx[cpu] >= ENTRIES_PER_PAGE) { | ||
| 1118 | struct trace_array_cpu *data = iter->tr->data[cpu]; | ||
| 1119 | |||
| 1120 | iter->next_page_idx[cpu] = 0; | ||
| 1121 | iter->next_page[cpu] = | ||
| 1122 | trace_next_list(data, iter->next_page[cpu]); | ||
| 1123 | } | ||
| 1124 | } | ||
| 1125 | |||
| 1107 | static struct trace_entry * | 1126 | static struct trace_entry * |
| 1108 | find_next_entry(struct trace_iterator *iter, int *ent_cpu) | 1127 | trace_entry_next(struct trace_array *tr, struct trace_array_cpu *data, |
| 1128 | struct trace_iterator *iter, int cpu) | ||
| 1129 | { | ||
| 1130 | struct list_head *next_page; | ||
| 1131 | struct trace_entry *ent; | ||
| 1132 | int idx, next_idx, next_page_idx; | ||
| 1133 | |||
| 1134 | ent = trace_entry_idx(tr, tr->data[cpu], iter, cpu); | ||
| 1135 | |||
| 1136 | if (likely(!ent || ent->type != TRACE_CONT)) | ||
| 1137 | return ent; | ||
| 1138 | |||
| 1139 | /* save the iterator details */ | ||
| 1140 | idx = iter->idx; | ||
| 1141 | next_idx = iter->next_idx[cpu]; | ||
| 1142 | next_page_idx = iter->next_page_idx[cpu]; | ||
| 1143 | next_page = iter->next_page[cpu]; | ||
| 1144 | |||
| 1145 | /* find a real entry */ | ||
| 1146 | do { | ||
| 1147 | trace_iterator_increment(iter, cpu); | ||
| 1148 | ent = trace_entry_idx(tr, tr->data[cpu], iter, cpu); | ||
| 1149 | } while (ent && ent->type != TRACE_CONT); | ||
| 1150 | |||
| 1151 | /* reset the iterator */ | ||
| 1152 | iter->idx = idx; | ||
| 1153 | iter->next_idx[cpu] = next_idx; | ||
| 1154 | iter->next_page_idx[cpu] = next_page_idx; | ||
| 1155 | iter->next_page[cpu] = next_page; | ||
| 1156 | |||
| 1157 | return ent; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | static struct trace_entry * | ||
| 1161 | __find_next_entry(struct trace_iterator *iter, int *ent_cpu, int inc) | ||
| 1109 | { | 1162 | { |
| 1110 | struct trace_array *tr = iter->tr; | 1163 | struct trace_array *tr = iter->tr; |
| 1111 | struct trace_entry *ent, *next = NULL; | 1164 | struct trace_entry *ent, *next = NULL; |
| @@ -1115,7 +1168,23 @@ find_next_entry(struct trace_iterator *iter, int *ent_cpu) | |||
| 1115 | for_each_tracing_cpu(cpu) { | 1168 | for_each_tracing_cpu(cpu) { |
| 1116 | if (!head_page(tr->data[cpu])) | 1169 | if (!head_page(tr->data[cpu])) |
| 1117 | continue; | 1170 | continue; |
| 1171 | |||
| 1118 | ent = trace_entry_idx(tr, tr->data[cpu], iter, cpu); | 1172 | ent = trace_entry_idx(tr, tr->data[cpu], iter, cpu); |
| 1173 | |||
| 1174 | if (ent && ent->type == TRACE_CONT) { | ||
| 1175 | struct trace_array_cpu *data = tr->data[cpu]; | ||
| 1176 | |||
| 1177 | if (!inc) | ||
| 1178 | ent = trace_entry_next(tr, data, iter, cpu); | ||
| 1179 | else { | ||
| 1180 | while (ent && ent->type == TRACE_CONT) { | ||
| 1181 | trace_iterator_increment(iter, cpu); | ||
| 1182 | ent = trace_entry_idx(tr, tr->data[cpu], | ||
| 1183 | iter, cpu); | ||
| 1184 | } | ||
| 1185 | } | ||
| 1186 | } | ||
| 1187 | |||
| 1119 | /* | 1188 | /* |
| 1120 | * Pick the entry with the smallest timestamp: | 1189 | * Pick the entry with the smallest timestamp: |
| 1121 | */ | 1190 | */ |
| @@ -1131,25 +1200,39 @@ find_next_entry(struct trace_iterator *iter, int *ent_cpu) | |||
| 1131 | return next; | 1200 | return next; |
| 1132 | } | 1201 | } |
| 1133 | 1202 | ||
| 1134 | static void trace_iterator_increment(struct trace_iterator *iter) | 1203 | /* Find the next real entry, without updating the iterator itself */ |
| 1204 | static struct trace_entry * | ||
| 1205 | find_next_entry(struct trace_iterator *iter, int *ent_cpu) | ||
| 1135 | { | 1206 | { |
| 1136 | iter->idx++; | 1207 | return __find_next_entry(iter, ent_cpu, 0); |
| 1137 | iter->next_idx[iter->cpu]++; | 1208 | } |
| 1138 | iter->next_page_idx[iter->cpu]++; | 1209 | |
| 1210 | /* Find the next real entry, and increment the iterator to the next entry */ | ||
| 1211 | static void *find_next_entry_inc(struct trace_iterator *iter) | ||
| 1212 | { | ||
| 1213 | struct trace_entry *next; | ||
| 1214 | int next_cpu = -1; | ||
| 1139 | 1215 | ||
| 1140 | if (iter->next_page_idx[iter->cpu] >= ENTRIES_PER_PAGE) { | 1216 | next = __find_next_entry(iter, &next_cpu, 1); |
| 1141 | struct trace_array_cpu *data = iter->tr->data[iter->cpu]; | ||
| 1142 | 1217 | ||
| 1143 | iter->next_page_idx[iter->cpu] = 0; | 1218 | iter->prev_ent = iter->ent; |
| 1144 | iter->next_page[iter->cpu] = | 1219 | iter->prev_cpu = iter->cpu; |
| 1145 | trace_next_list(data, iter->next_page[iter->cpu]); | 1220 | |
| 1146 | } | 1221 | iter->ent = next; |
| 1222 | iter->cpu = next_cpu; | ||
| 1223 | |||
| 1224 | if (next) | ||
| 1225 | trace_iterator_increment(iter, iter->cpu); | ||
| 1226 | |||
| 1227 | return next ? iter : NULL; | ||
| 1147 | } | 1228 | } |
| 1148 | 1229 | ||
| 1149 | static void trace_consume(struct trace_iterator *iter) | 1230 | static void trace_consume(struct trace_iterator *iter) |
| 1150 | { | 1231 | { |
| 1151 | struct trace_array_cpu *data = iter->tr->data[iter->cpu]; | 1232 | struct trace_array_cpu *data = iter->tr->data[iter->cpu]; |
| 1233 | struct trace_entry *ent; | ||
| 1152 | 1234 | ||
| 1235 | again: | ||
| 1153 | data->trace_tail_idx++; | 1236 | data->trace_tail_idx++; |
| 1154 | if (data->trace_tail_idx >= ENTRIES_PER_PAGE) { | 1237 | if (data->trace_tail_idx >= ENTRIES_PER_PAGE) { |
| 1155 | data->trace_tail = trace_next_page(data, data->trace_tail); | 1238 | data->trace_tail = trace_next_page(data, data->trace_tail); |
| @@ -1160,25 +1243,11 @@ static void trace_consume(struct trace_iterator *iter) | |||
| 1160 | if (data->trace_head == data->trace_tail && | 1243 | if (data->trace_head == data->trace_tail && |
| 1161 | data->trace_head_idx == data->trace_tail_idx) | 1244 | data->trace_head_idx == data->trace_tail_idx) |
| 1162 | data->trace_idx = 0; | 1245 | data->trace_idx = 0; |
| 1163 | } | ||
| 1164 | |||
| 1165 | static void *find_next_entry_inc(struct trace_iterator *iter) | ||
| 1166 | { | ||
| 1167 | struct trace_entry *next; | ||
| 1168 | int next_cpu = -1; | ||
| 1169 | |||
| 1170 | next = find_next_entry(iter, &next_cpu); | ||
| 1171 | |||
| 1172 | iter->prev_ent = iter->ent; | ||
| 1173 | iter->prev_cpu = iter->cpu; | ||
| 1174 | |||
| 1175 | iter->ent = next; | ||
| 1176 | iter->cpu = next_cpu; | ||
| 1177 | |||
| 1178 | if (next) | ||
| 1179 | trace_iterator_increment(iter); | ||
| 1180 | 1246 | ||
| 1181 | return next ? iter : NULL; | 1247 | ent = trace_entry_idx(iter->tr, iter->tr->data[iter->cpu], |
| 1248 | iter, iter->cpu); | ||
| 1249 | if (ent && ent->type == TRACE_CONT) | ||
| 1250 | goto again; | ||
| 1182 | } | 1251 | } |
| 1183 | 1252 | ||
| 1184 | static void *s_next(struct seq_file *m, void *v, loff_t *pos) | 1253 | static void *s_next(struct seq_file *m, void *v, loff_t *pos) |
| @@ -1473,6 +1542,26 @@ lat_print_timestamp(struct trace_seq *s, unsigned long long abs_usecs, | |||
| 1473 | 1542 | ||
| 1474 | static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; | 1543 | static const char state_to_char[] = TASK_STATE_TO_CHAR_STR; |
| 1475 | 1544 | ||
| 1545 | static void | ||
| 1546 | trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter) | ||
| 1547 | { | ||
| 1548 | struct trace_array *tr = iter->tr; | ||
| 1549 | struct trace_array_cpu *data = tr->data[iter->cpu]; | ||
| 1550 | struct trace_entry *ent; | ||
| 1551 | |||
| 1552 | ent = trace_entry_idx(tr, data, iter, iter->cpu); | ||
| 1553 | if (!ent || ent->type != TRACE_CONT) { | ||
| 1554 | trace_seq_putc(s, '\n'); | ||
| 1555 | return; | ||
| 1556 | } | ||
| 1557 | |||
| 1558 | do { | ||
| 1559 | trace_seq_printf(s, "%s", ent->cont.buf); | ||
| 1560 | trace_iterator_increment(iter, iter->cpu); | ||
| 1561 | ent = trace_entry_idx(tr, data, iter, iter->cpu); | ||
| 1562 | } while (ent && ent->type == TRACE_CONT); | ||
| 1563 | } | ||
| 1564 | |||
| 1476 | static int | 1565 | static int |
| 1477 | print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) | 1566 | print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) |
| 1478 | { | 1567 | { |
| @@ -1491,6 +1580,10 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) | |||
| 1491 | 1580 | ||
| 1492 | if (!next_entry) | 1581 | if (!next_entry) |
| 1493 | next_entry = entry; | 1582 | next_entry = entry; |
| 1583 | |||
| 1584 | if (entry->type == TRACE_CONT) | ||
| 1585 | return 1; | ||
| 1586 | |||
| 1494 | rel_usecs = ns2usecs(next_entry->field.t - entry->field.t); | 1587 | rel_usecs = ns2usecs(next_entry->field.t - entry->field.t); |
| 1495 | abs_usecs = ns2usecs(entry->field.t - iter->tr->time_start); | 1588 | abs_usecs = ns2usecs(entry->field.t - iter->tr->time_start); |
| 1496 | 1589 | ||
| @@ -1550,6 +1643,12 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu) | |||
| 1550 | } | 1643 | } |
| 1551 | trace_seq_puts(s, "\n"); | 1644 | trace_seq_puts(s, "\n"); |
| 1552 | break; | 1645 | break; |
| 1646 | case TRACE_PRINT: | ||
| 1647 | seq_print_ip_sym(s, field->print.ip, sym_flags); | ||
| 1648 | trace_seq_printf(s, ": %s", field->print.buf); | ||
| 1649 | if (field->flags && TRACE_FLAG_CONT) | ||
| 1650 | trace_seq_print_cont(s, iter); | ||
| 1651 | break; | ||
| 1553 | default: | 1652 | default: |
| 1554 | trace_seq_printf(s, "Unknown type %d\n", entry->type); | 1653 | trace_seq_printf(s, "Unknown type %d\n", entry->type); |
| 1555 | } | 1654 | } |
| @@ -1571,6 +1670,10 @@ static int print_trace_fmt(struct trace_iterator *iter) | |||
| 1571 | int i; | 1670 | int i; |
| 1572 | 1671 | ||
| 1573 | entry = iter->ent; | 1672 | entry = iter->ent; |
| 1673 | |||
| 1674 | if (entry->type == TRACE_CONT) | ||
| 1675 | return 1; | ||
| 1676 | |||
| 1574 | field = &entry->field; | 1677 | field = &entry->field; |
| 1575 | 1678 | ||
| 1576 | comm = trace_find_cmdline(iter->ent->field.pid); | 1679 | comm = trace_find_cmdline(iter->ent->field.pid); |
| @@ -1653,6 +1756,12 @@ static int print_trace_fmt(struct trace_iterator *iter) | |||
| 1653 | if (!ret) | 1756 | if (!ret) |
| 1654 | return 0; | 1757 | return 0; |
| 1655 | break; | 1758 | break; |
| 1759 | case TRACE_PRINT: | ||
| 1760 | seq_print_ip_sym(s, field->print.ip, sym_flags); | ||
| 1761 | trace_seq_printf(s, ": %s", field->print.buf); | ||
| 1762 | if (field->flags && TRACE_FLAG_CONT) | ||
| 1763 | trace_seq_print_cont(s, iter); | ||
| 1764 | break; | ||
| 1656 | } | 1765 | } |
| 1657 | return 1; | 1766 | return 1; |
| 1658 | } | 1767 | } |
| @@ -1666,6 +1775,10 @@ static int print_raw_fmt(struct trace_iterator *iter) | |||
| 1666 | int S, T; | 1775 | int S, T; |
| 1667 | 1776 | ||
| 1668 | entry = iter->ent; | 1777 | entry = iter->ent; |
| 1778 | |||
| 1779 | if (entry->type == TRACE_CONT) | ||
| 1780 | return 1; | ||
| 1781 | |||
| 1669 | field = &entry->field; | 1782 | field = &entry->field; |
| 1670 | 1783 | ||
| 1671 | ret = trace_seq_printf(s, "%d %d %llu ", | 1784 | ret = trace_seq_printf(s, "%d %d %llu ", |
| @@ -1708,6 +1821,12 @@ static int print_raw_fmt(struct trace_iterator *iter) | |||
| 1708 | if (!ret) | 1821 | if (!ret) |
| 1709 | return 0; | 1822 | return 0; |
| 1710 | break; | 1823 | break; |
| 1824 | case TRACE_PRINT: | ||
| 1825 | trace_seq_printf(s, "# %lx %s", | ||
| 1826 | field->print.ip, field->print.buf); | ||
| 1827 | if (field->flags && TRACE_FLAG_CONT) | ||
| 1828 | trace_seq_print_cont(s, iter); | ||
| 1829 | break; | ||
| 1711 | } | 1830 | } |
| 1712 | return 1; | 1831 | return 1; |
| 1713 | } | 1832 | } |
| @@ -1733,6 +1852,10 @@ static int print_hex_fmt(struct trace_iterator *iter) | |||
| 1733 | int S, T; | 1852 | int S, T; |
| 1734 | 1853 | ||
| 1735 | entry = iter->ent; | 1854 | entry = iter->ent; |
| 1855 | |||
| 1856 | if (entry->type == TRACE_CONT) | ||
| 1857 | return 1; | ||
| 1858 | |||
| 1736 | field = &entry->field; | 1859 | field = &entry->field; |
| 1737 | 1860 | ||
| 1738 | SEQ_PUT_HEX_FIELD_RET(s, field->pid); | 1861 | SEQ_PUT_HEX_FIELD_RET(s, field->pid); |
| @@ -1778,6 +1901,10 @@ static int print_bin_fmt(struct trace_iterator *iter) | |||
| 1778 | struct trace_field *field; | 1901 | struct trace_field *field; |
| 1779 | 1902 | ||
| 1780 | entry = iter->ent; | 1903 | entry = iter->ent; |
| 1904 | |||
| 1905 | if (entry->type == TRACE_CONT) | ||
| 1906 | return 1; | ||
| 1907 | |||
| 1781 | field = &entry->field; | 1908 | field = &entry->field; |
| 1782 | 1909 | ||
| 1783 | SEQ_PUT_FIELD_RET(s, field->pid); | 1910 | SEQ_PUT_FIELD_RET(s, field->pid); |
| @@ -2943,6 +3070,94 @@ static __init void tracer_init_debugfs(void) | |||
| 2943 | #endif | 3070 | #endif |
| 2944 | } | 3071 | } |
| 2945 | 3072 | ||
| 3073 | #define TRACE_BUF_SIZE 1024 | ||
| 3074 | #define TRACE_PRINT_BUF_SIZE \ | ||
| 3075 | (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf)) | ||
| 3076 | #define TRACE_CONT_BUF_SIZE sizeof(struct trace_field) | ||
| 3077 | |||
| 3078 | /** | ||
| 3079 | * ftrace_printk - printf formatting in the ftrace buffer | ||
| 3080 | * @fmt - the printf format for printing. | ||
| 3081 | * | ||
| 3082 | * Note: __ftrace_printk is an internal function for ftrace_printk and | ||
| 3083 | * the @ip is passed in via the ftrace_printk macro. | ||
| 3084 | * | ||
| 3085 | * This function allows a kernel developer to debug fast path sections | ||
| 3086 | * that printk is not appropriate for. By scattering in various | ||
| 3087 | * printk like tracing in the code, a developer can quickly see | ||
| 3088 | * where problems are occurring. | ||
| 3089 | * | ||
| 3090 | * This is intended as a debugging tool for the developer only. | ||
| 3091 | * Please reframe from leaving ftrace_printks scattered around in | ||
| 3092 | * your code. | ||
| 3093 | */ | ||
| 3094 | int __ftrace_printk(unsigned long ip, const char *fmt, ...) | ||
| 3095 | { | ||
| 3096 | struct trace_array *tr = &global_trace; | ||
| 3097 | static DEFINE_SPINLOCK(trace_buf_lock); | ||
| 3098 | static char trace_buf[TRACE_BUF_SIZE]; | ||
| 3099 | struct trace_array_cpu *data; | ||
| 3100 | struct trace_entry *entry; | ||
| 3101 | unsigned long flags; | ||
| 3102 | long disabled; | ||
| 3103 | va_list ap; | ||
| 3104 | int cpu, len = 0, write, written = 0; | ||
| 3105 | |||
| 3106 | if (likely(!ftrace_function_enabled)) | ||
| 3107 | return 0; | ||
| 3108 | |||
| 3109 | local_irq_save(flags); | ||
| 3110 | cpu = raw_smp_processor_id(); | ||
| 3111 | data = tr->data[cpu]; | ||
| 3112 | disabled = atomic_inc_return(&data->disabled); | ||
| 3113 | |||
| 3114 | if (unlikely(disabled != 1 || !ftrace_function_enabled)) | ||
| 3115 | goto out; | ||
| 3116 | |||
| 3117 | spin_lock(&trace_buf_lock); | ||
| 3118 | va_start(ap, fmt); | ||
| 3119 | len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, ap); | ||
| 3120 | va_end(ap); | ||
| 3121 | |||
| 3122 | len = min(len, TRACE_BUF_SIZE-1); | ||
| 3123 | trace_buf[len] = 0; | ||
| 3124 | |||
| 3125 | __raw_spin_lock(&data->lock); | ||
| 3126 | entry = tracing_get_trace_entry(tr, data); | ||
| 3127 | tracing_generic_entry_update(entry, flags); | ||
| 3128 | entry->type = TRACE_PRINT; | ||
| 3129 | entry->field.print.ip = ip; | ||
| 3130 | |||
| 3131 | write = min(len, (int)(TRACE_PRINT_BUF_SIZE-1)); | ||
| 3132 | |||
| 3133 | memcpy(&entry->field.print.buf, trace_buf, write); | ||
| 3134 | entry->field.print.buf[write] = 0; | ||
| 3135 | written = write; | ||
| 3136 | |||
| 3137 | if (written != len) | ||
| 3138 | entry->field.flags |= TRACE_FLAG_CONT; | ||
| 3139 | |||
| 3140 | while (written != len) { | ||
| 3141 | entry = tracing_get_trace_entry(tr, data); | ||
| 3142 | |||
| 3143 | entry->type = TRACE_CONT; | ||
| 3144 | write = min(len - written, (int)(TRACE_CONT_BUF_SIZE-1)); | ||
| 3145 | memcpy(&entry->cont.buf, trace_buf+written, write); | ||
| 3146 | entry->cont.buf[write] = 0; | ||
| 3147 | written += write; | ||
| 3148 | } | ||
| 3149 | __raw_spin_unlock(&data->lock); | ||
| 3150 | |||
| 3151 | spin_unlock(&trace_buf_lock); | ||
| 3152 | |||
| 3153 | out: | ||
| 3154 | atomic_dec(&data->disabled); | ||
| 3155 | local_irq_restore(flags); | ||
| 3156 | |||
| 3157 | return len; | ||
| 3158 | } | ||
| 3159 | EXPORT_SYMBOL_GPL(__ftrace_printk); | ||
| 3160 | |||
| 2946 | static int trace_alloc_page(void) | 3161 | static int trace_alloc_page(void) |
| 2947 | { | 3162 | { |
| 2948 | struct trace_array_cpu *data; | 3163 | struct trace_array_cpu *data; |
