Motr  M0
trace.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2011-2021 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #ifdef __KERNEL__
24 # include <linux/ctype.h> /* tolower */
25 # include <linux/sched.h> /* current->pid */
26 #else
27 #include <limits.h> /* CHAR_BIT */
28 #include <ctype.h> /* tolower */
29 #include <sys/types.h>
30 #endif
31 #include "lib/errno.h"
32 #include "lib/atomic.h"
33 #include "lib/arith.h" /* m0_align */
34 #include "lib/misc.h" /* m0_short_file_name, string.h */
35 #include "lib/memory.h" /* m0_pagesize_get */
36 #include "lib/string.h" /* m0_strdup */
37 #include "lib/cookie.h" /* m0_addr_is_sane */
38 #include "lib/trace.h"
39 #include "lib/trace_internal.h"
40 #include "motr/magic.h"
41 #include "motr/version.h"
42 
62 /*
63  * Magic symbol, which used to calculate offset for trace descriptors when
64  * parsing trace files. It needs to be placed in .rodata section (the same
65  * section which holds trace descriptors) so it should be static const.
66  */
67 static const uint64_t trace_magic_symbol = M0_TRACE_MAGIC;
68 static const char trace_magic_symbol_name[] = "trace_magic_symbol";
69 
70 /* single buffer for now */
71 
72 /* Must be multiple of page size on all supported platforms. */
73 enum { BOOTLOG_BUF_SIZE = (1 << 16) }; /* 64K */
74 
79 static struct {
82 } bootlog;
83 M0_BASSERT(bootlog.bl_buf == bootlog.bl_area.ta_buf);
84 
85 struct m0_trace_buf_header *m0_logbuf_header = &bootlog.bl_area.ta_header;
86 void *m0_logbuf = bootlog.bl_area.ta_buf;
87 size_t m0_logbufsize = sizeof bootlog.bl_buf;
88 static size_t bufmask = sizeof bootlog.bl_buf - 1;
89 M0_BASSERT(((sizeof bootlog.bl_buf) & ((sizeof bootlog.bl_buf) - 1)) == 0);
90 
91 unsigned long m0_trace_immediate_mask = 0;
92 M0_EXPORTED(m0_trace_immediate_mask);
94 
96 M0_EXPORTED(m0_trace_print_context);
97 
99 M0_EXPORTED(m0_trace_level);
100 
101 #undef M0_TRACE_SUBSYS
102 #define M0_TRACE_SUBSYS(name, value) [value] = #name,
103 
104 static const char *trace_subsys_str[] = {
106 };
107 
109 static struct {
110  const char *name;
112 } trace_levels[] = {
113  [0] = { .name = "NONE", .level = M0_NONE },
114  [1] = { .name = "ALWAYS", .level = M0_ALWAYS },
115  [2] = { .name = "FATAL", .level = M0_FATAL },
116  [3] = { .name = "ERROR", .level = M0_ERROR },
117  [4] = { .name = "WARN", .level = M0_WARN },
118  [5] = { .name = "NOTICE", .level = M0_NOTICE },
119  [6] = { .name = "INFO", .level = M0_INFO },
120  [7] = { .name = "DEBUG", .level = M0_DEBUG },
121  [8] = { .name = "CALL", .level = M0_CALL },
122 };
123 
125 static const char *trace_print_ctx_str[] = {
126  [M0_TRACE_PCTX_NONE] = "none",
127  [M0_TRACE_PCTX_FUNC] = "func",
128  [M0_TRACE_PCTX_SHORT] = "short",
129  [M0_TRACE_PCTX_FULL] = "full",
130 };
131 
132 M0_INTERNAL int m0_trace_init(void)
133 {
134  int rc;
135 
139 
141 
143  M0_POST(m0_is_po2(bufmask + 1));
144 
145  return rc;
146 }
147 
148 M0_INTERNAL void m0_trace_fini(void)
149 {
151 }
152 
161 static inline uint64_t m0_rdtsc(void)
162 {
163 #ifdef CONFIG_X86_64
164  uint32_t count_hi;
165  uint32_t count_lo;
166 
167  __asm__ __volatile__("rdtsc" : "=a"(count_lo), "=d"(count_hi));
168 
169  return ((uint64_t)count_lo) | (((uint64_t)count_hi) << 32);
170 #elif defined (CONFIG_AARCH64)
171  uint64_t cycle;
172 
173  asm volatile("mrs %0, pmccntr_el0" : "=r"(cycle));
174  return cycle;
175 #else
176 #error "The Platform is not supported"
177 #endif
178 }
179 
180 #define NULL_STRING_STUB "(null)"
181 
182 static uint32_t calc_string_data_size(const struct m0_trace_descr *td,
183  const void *body)
184 {
185  int i;
186  uint32_t total_size = 0;
187 
188  if (!td->td_hasstr)
189  return 0;
190 
191  for (i = 0; i < td->td_nr; ++i)
192  if (td->td_isstr[i]) {
193  char *s = *(char**)((char*)body + td->td_offset[i]) ?:
195  total_size += strlen(s) + 1;
196  }
197 
198  return total_size;
199 }
200 
201 static void copy_string_data(char *dst_str, const char *body,
202  const struct m0_trace_descr *td)
203 {
204  int i;
205 
206  for (i = 0; i < td->td_nr; ++i)
207  if (td->td_isstr[i]) {
208  char *src_str = *(char**)(body + td->td_offset[i]) ?:
210  size_t str_len = strlen(src_str);
211  memcpy(dst_str, src_str, str_len + 1);
212  dst_str += str_len + 1;
213  }
214 }
215 
216 static unsigned allowed_level = UINT_MAX;
217 
218 M0_INTERNAL void m0_trace_level_allow(unsigned level)
219 {
220  M0_PRE(level <= M0_CALL);
222 }
223 M0_EXPORTED(m0_trace_level_allow);
224 
225 M0_INTERNAL void m0_trace_allot(const struct m0_trace_descr *td,
226  const void *body)
227 {
228  uint64_t record_num;
229  uint32_t header_len;
230  uint32_t record_len;
231  uint32_t pos_in_buf;
232  uint32_t endpos_in_buf;
233  uint64_t pos;
234  uint64_t endpos;
235  uint32_t str_data_size;
236  void *body_in_buf;
237  char *dst_str;
238 
239  struct m0_trace_rec_header *header;
241 #ifdef __clang__
242  /* Approximation of the stack pointer for clang compiler. */
243  unsigned long sp = (unsigned long)&tbh;
244 #else
245  register unsigned long sp asm("sp"); /* stack pointer */
246 #endif /* __clang__ */
247 
248 #ifdef ENABLE_RESTRICTED_TRACE_MODE
249  /* discard records with verbosity level higher than allowed */
250  if (td->td_level > M0_TRACE_HIGHEST_ALLOWED_LEVEL)
251  return;
252 #endif
253 
254  if (td->td_level > allowed_level)
255  return;
256 
257  record_num = m0_atomic64_add_return(&tbh->tbh_rec_cnt, 1);
258 
259  /*
260  * Allocate space in trace buffer to store trace record header
261  * (header_len bytes) and record payload (record_len bytes).
262  *
263  * Record and payload always start at 8-byte (M0_TRACE_REC_ALIGN)
264  * aligned address.
265  *
266  * Record payload consists of a body (printf arguments) and optional
267  * string data section, which starts immediately after body at the
268  * nearest 8-byte (M0_TRACE_REC_ALIGN) aligned address.
269  *
270  * String data section contains copies of data, pointed by any char*
271  * arguments, present in body.
272  *
273  * First free byte in the trace buffer is at "cur" offset. Note, that
274  * cur is not wrapped to 0 when the end of the buffer is reached (that
275  * would require additional synchronization between contending threads).
276  */
277 
278  header_len = m0_align(sizeof *header, M0_TRACE_REC_ALIGN);
279  str_data_size = calc_string_data_size(td, body);
280  record_len = header_len + m0_align(td->td_size, M0_TRACE_REC_ALIGN) +
281  m0_align(str_data_size, M0_TRACE_REC_ALIGN);
282 
283  while (1) {
284  endpos = m0_atomic64_add_return(&tbh->tbh_cur_pos, record_len);
285  pos = endpos - record_len;
286  pos_in_buf = pos & bufmask;
287  endpos_in_buf = endpos & bufmask;
288  /*
289  * The record should not cross the buffer.
290  */
291  if (pos_in_buf > endpos_in_buf && endpos_in_buf) {
292  memset(m0_logbuf + pos_in_buf, 0,
293  m0_logbufsize - pos_in_buf);
294  memset(m0_logbuf, 0, endpos_in_buf);
295  } else
296  break;
297  }
298 
299  m0_trace_stats_update(record_len);
300 
301  header = m0_logbuf + pos_in_buf;
302  header->trh_magic = 0;
303 #ifdef __KERNEL__
304  header->trh_pid = current->pid;
305 #else
306  header->trh_pid = m0_pid_cached;
307 #endif
308  header->trh_no = record_num;
309  header->trh_pos = pos;
310  header->trh_sp = sp;
311  header->trh_timestamp = m0_rdtsc();
312  header->trh_descr = td;
313  header->trh_string_data_size = str_data_size;
314  header->trh_record_size = record_len;
315  body_in_buf = (char*)header + header_len;
316 
317  memcpy(body_in_buf, body, td->td_size);
318 
319  if (str_data_size > 0) {
320  dst_str = body_in_buf + m0_align(td->td_size, M0_TRACE_REC_ALIGN);
321  copy_string_data(dst_str, body, td);
322  }
323 
325  header->trh_magic = M0_TRACE_MAGIC;
326 
327 #ifdef ENABLE_IMMEDIATE_TRACE
328  if (((td->td_subsys & m0_trace_immediate_mask ||
329  td->td_level & (M0_WARN|M0_ERROR|M0_FATAL)) &&
330  td->td_level & m0_trace_level) ||
331  td->td_level & M0_ALWAYS)
332 #else
334 #endif
335  m0_trace_record_print(header, body_in_buf);
336 }
337 M0_EXPORTED(m0_trace_allot);
338 
339 M0_INTERNAL const char *m0_trace_subsys_name(uint64_t subsys)
340 {
341  int i;
342 
343  for (i = 0; i < ARRAY_SIZE(trace_subsys_str); i++, subsys >>= 1)
344  if (subsys & 1)
345  return trace_subsys_str[i];
346 
347  return NULL;
348 }
349 M0_EXPORTED(m0_trace_subsys_name);
350 
351 static char *subsys_str(uint64_t subsys, char *buf)
352 {
353  int i;
354  char *s = buf;
355 
356  *s++ = '<';
357  for (i = 0; i < ARRAY_SIZE(trace_subsys_str); i++, subsys >>= 1)
358  *s++ = (subsys & 1) ? trace_subsys_str[i][0] :
359  tolower(trace_subsys_str[i][0]);
360  *s++ = '>';
361  *s = '\0';
362 
363  return buf;
364 }
365 
366 static inline char *uppercase(char *s)
367 {
368  char *p;
369 
370  for (p = s; *p != '\0'; ++p)
371  *p = toupper(*p);
372 
373  return s;
374 }
375 
376 static inline char *lowercase(char *s)
377 {
378  char *p;
379 
380  for (p = s; *p != '\0'; ++p)
381  *p = tolower(*p);
382 
383  return s;
384 }
385 
386 static unsigned long subsys_name_to_mask(char *subsys_name)
387 {
388  int i;
389 
390  /* uppercase subsys_name to match names in trace_subsys_str array */
391  uppercase(subsys_name);
392 
393  for (i = 0; i < ARRAY_SIZE(trace_subsys_str); ++i) {
394  if (m0_streq(subsys_name, trace_subsys_str[i]))
395  return M0_BITS(i);
396  }
397  return 0;
398 }
399 
413 M0_INTERNAL int
414 m0_trace_subsys_list_to_mask(char *subsys_names, unsigned long *ret_mask)
415 {
416  char *p;
417  char *subsys = subsys_names;
418  unsigned long mask;
419  unsigned long m;
420 
421  /*
422  * there can be an optional '!' symbol at the beginning of mask,
423  * skip it if it present
424  */
425  subsys = subsys_names[0] == '!' ? subsys_names + 1 : subsys_names;
426 
427  /*
428  * a special pseudo-subsystem 'all' represents all available subsystems;
429  * it's valid only when it's the only subsystem in a list
430  */
431  if (strcmp(subsys, "all") == 0 || strcmp(subsys, "ALL") == 0) {
432  mask = ~0UL;
433  goto out;
434  }
435 
436  mask = 0;
437  p = subsys;
438 
439  while (p != NULL) {
440  p = strchr(subsys, ',');
441  if (p != NULL)
442  *p++ = '\0';
443  m = subsys_name_to_mask(subsys);
444  if (m == 0) {
445  m0_error_printf("motr: failed to initialize trace"
446  " immediate mask: subsystem '%s' not"
447  " found\n", lowercase(subsys));
448  return -EINVAL;
449  }
450  mask |= m;
451  subsys = p;
452  }
453 out:
454  /* invert mask if there is '!' at the beginning */
455  *ret_mask = subsys_names[0] == '!' ? ~mask : mask;
456 
457  return 0;
458 }
459 
460 M0_INTERNAL const char *m0_trace_level_name(enum m0_trace_level level)
461 {
462  int i;
463 
464  for (i = 0; i < ARRAY_SIZE(trace_levels); i++)
465  if (level == trace_levels[i].level)
466  return trace_levels[i].name;
467 
468  return NULL;
469 }
470 M0_EXPORTED(m0_trace_level_name);
471 
472 static enum m0_trace_level trace_level_value(char *level_name)
473 {
474  int i;
475 
476  /* uppercase level name to match names in trace_levels array */
477  uppercase(level_name);
478 
479  for (i = 0; i < ARRAY_SIZE(trace_levels); i++) {
480  if (strcmp(level_name, trace_levels[i].name) == 0)
481  return trace_levels[i].level;
482 
483  }
484 
485  return M0_NONE;
486 }
487 
488 static enum m0_trace_level trace_level_value_plus(char *level_name)
489 {
491  size_t n = strlen(level_name);
492  bool is_plus_level = false;
493 
494  if (level_name[n - 1] == '+') {
495  level_name[n - 1] = '\0';
496  is_plus_level = true;
497  }
498 
499  level = trace_level_value(level_name);
500  if (level == M0_NONE)
501  return M0_NONE;
502 
503  /*
504  * enable requested level and all other levels with higher precedance if
505  * it's a "plus" level, otherwise just the requested level
506  */
507  return is_plus_level ? level | (level - 1) : level;
508 }
509 
521 M0_INTERNAL enum m0_trace_level m0_trace_level_parse(char *str)
522 {
523  char *level_str = str;
524  char *p = level_str;
526  enum m0_trace_level l;
527 
528  while (p != NULL) {
529  p = strchr(level_str, ',');
530  if (p != NULL)
531  *p++ = '\0';
533  if (l == M0_NONE) {
534  m0_error_printf("motr: failed to initialize trace"
535  " level: no such level '%s'\n",
537  return M0_NONE;
538  }
539  level |= l;
540  level_str = p;
541  }
542 
543  return level;
544 }
545 M0_EXPORTED(m0_trace_level_parse);
546 
547 M0_INTERNAL enum m0_trace_print_context
548 m0_trace_print_context_parse(const char *ctx_name)
549 {
550  int i;
551 
552  for (i = 0; i < ARRAY_SIZE(trace_print_ctx_str); ++i)
553  if (strcmp(ctx_name, trace_print_ctx_str[i]) == 0)
554  return i;
555 
556  m0_error_printf("motr: failed to initialize trace print context:"
557  " invalid value '%s'\n", ctx_name);
558 
559  return M0_TRACE_PCTX_INVALID;
560 }
561 
562 M0_INTERNAL int m0_trace_set_print_context(const char *ctx_name)
563 {
565 
566  if (ctx_name == NULL)
567  return 0;
568 
569  ctx = m0_trace_print_context_parse(ctx_name);
570  if (ctx == M0_TRACE_PCTX_INVALID)
571  return -EINVAL;
572 
574 #ifdef __KERNEL__
575  pr_info("motr: trace print context: %s\n", ctx_name);
576 #endif
577  return 0;
578 }
579 M0_EXPORTED(m0_trace_set_print_context);
580 
581 M0_INTERNAL int m0_trace_set_level(const char *level_str)
582 {
583  unsigned int level;
584  char *level_str_copy;
585 
586  if (level_str == NULL)
587  return 0;
588 
589  level_str_copy = m0_strdup(level_str);
590  if (level_str_copy == NULL)
591  return -ENOMEM;
592 
593  level = m0_trace_level_parse(level_str_copy);
594  m0_free(level_str_copy);
595 
596  if (level == M0_NONE) {
597  m0_error_printf("motr: incorrect trace level specification,"
598  " it should be in form of 'level[+][,level[+]]'"
599  " where 'level' is one of call|debug|info|notice|warn|"
600  "error|fatal");
601  return -EINVAL;
602  }
603 
605 #ifdef __KERNEL__
606  pr_info("motr: trace level: %s\n", level_str);
607 #endif
608  return 0;
609 }
610 M0_EXPORTED(m0_trace_set_level);
611 
612 M0_INTERNAL const struct m0_trace_buf_header *m0_trace_logbuf_header_get(void)
613 {
614  return m0_logbuf_header;
615 }
616 M0_EXPORTED(m0_trace_logbuf_header_get);
617 
618 M0_INTERNAL const void *m0_trace_logbuf_get(void)
619 {
620  return m0_logbuf;
621 }
622 M0_EXPORTED(m0_trace_logbuf_get);
623 
624 M0_INTERNAL uint32_t m0_trace_logbuf_size_get(void)
625 {
626  return m0_logbufsize;
627 }
628 M0_EXPORTED(m0_trace_logbuf_size_get);
629 
630 M0_INTERNAL void m0_trace_logbuf_size_set(size_t size)
631 {
632  M0_PRE(m0_is_po2(size) && size % m0_pagesize_get() == 0);
634  bufmask = size ? size - 1 : 0;
635 }
636 M0_EXPORTED(m0_trace_logbuf_size_set);
637 
638 M0_INTERNAL uint64_t m0_trace_logbuf_pos_get(void)
639 {
641 }
642 M0_EXPORTED(m0_trace_logbuf_pos_get);
643 
644 M0_INTERNAL const void *m0_trace_magic_sym_addr_get(void)
645 {
646  return &trace_magic_symbol;
647 }
648 
649 M0_INTERNAL const char* m0_trace_magic_sym_name_get(void)
650 {
652 }
653 
655 {
657  int i;
658 
659  if (tbh == (void*)bootlog.bl_area.ta_buf)
660  /* trace subsystem is not ready yet */
661  return -EUNATCH;
662 
663  if (tbh->tbh_magic_sym_addresses_nr >=
665  /* no free slots available in the magic sym array */
666  return -ENOSPC;
667 
668  i = tbh->tbh_magic_sym_addresses_nr++;
669  if (i >= ARRAY_SIZE(tbh->tbh_magic_sym_addresses))
670  /* other thread must have stolen the last free slot from us */
671  return -ENOSPC;
672 
674 
675  return 0;
676 }
677 
678 M0_INTERNAL void m0_trace_print_subsystems(void)
679 {
680  int i;
681 
682  m0_console_printf("# YAML\n");
683  m0_console_printf("---\n");
684  m0_console_printf("trace_subsystems:\n");
685 
686  for (i = 0; i < ARRAY_SIZE(trace_subsys_str); i++)
687  m0_console_printf(" - %s\n", trace_subsys_str[i]);
688 }
689 
690 M0_INTERNAL int m0_trace_args_unpack(const struct m0_trace_rec_header *trh,
692  const void *buf)
693 {
694  int i;
695  size_t total_str_len = 0;
696  const char *str_data = NULL;
697  const struct m0_trace_descr *td = trh->trh_descr;
698 
699  if (trh->trh_string_data_size != 0)
700  str_data = (char*)buf + m0_align(td->td_size, M0_TRACE_REC_ALIGN);
701 
702  for (i = 0; i < td->td_nr; ++i) {
703  const char *addr;
704 
705  addr = buf + td->td_offset[i];
706  switch (td->td_sizeof[i]) {
707  case 0:
708  break;
709  case 1:
710  args[i].v8 = *(uint8_t *)addr;
711  break;
712  case 2:
713  args[i].v16 = *(uint16_t *)addr;
714  break;
715  case 4:
716  args[i].v32 = *(uint32_t *)addr;
717  break;
718  case 8:
719  args[i].v64 = *(uint64_t *)addr;
720  break;
721  default:
722  M0_IMPOSSIBLE("sizeof");
723  }
724 
725  if (td->td_isstr[i]) {
726  size_t str_len;
727 
728  if (!m0_addr_is_sane((const uint64_t *)str_data))
729  return -EFAULT;
730 
731  str_len = strlen(str_data);
732  total_str_len += str_len + 1;
733 
734  if (total_str_len > trh->trh_string_data_size)
735  return -EFAULT;
736 
737  args[i].v64 = (uint64_t)str_data;
738  str_data += str_len + 1;
739  }
740  }
741 
742  return 0;
743 }
744 
745 M0_INTERNAL void
746 m0_trace_record_print(const struct m0_trace_rec_header *trh, const void *buf)
747 {
748  const struct m0_trace_descr *td = trh->trh_descr;
750  int rc;
751 
752  /* there are 64 possible subsystems, so we need one byte for each
753  * subsystem name plus two bytes for '<' and '>' symbols around them and
754  * one byte for '\0' and the end */
755  char subsys_map_str[sizeof(uint64_t) * CHAR_BIT + 3];
756 
757  rc = m0_trace_args_unpack(trh, args, buf);
758  if (rc != 0) {
759  m0_error_printf("motr: failed to unpack trace descriptor args"
760  " for M0_LOG() inside '%s' at '%s:%u'\n",
761  td->td_func, td->td_file, td->td_line);
762  return;
763  }
764 
766  m0_error_printf("%5.5u %8.8llu %15.15llu %6.6x %-18s %-7s "
767  "%-20s %s:%-3i\n\t",
768  trh->trh_pid,
769  (unsigned long long)trh->trh_no,
770  (unsigned long long)trh->trh_timestamp,
771  (unsigned) (trh->trh_sp & 0xffff),
772  subsys_str(td->td_subsys, subsys_map_str),
775  td->td_line);
776  }
777 
779  m0_error_printf("motr[%5.5u]: %5x %6s [%s:%i:%s] ",
780  trh->trh_pid,
781  (unsigned) (trh->trh_sp & 0xffff),
784  td->td_line, td->td_func);
787  (td->td_level == M0_CALL || td->td_level == M0_NOTICE)))
788  m0_error_printf("motr: %s: ", td->td_func);
789  else /* td->td_level == M0_TRACE_PCTX_NONE
790  || td->td_level == M0_TRACE_PCTX_FULL */
791  m0_error_printf("motr: ");
792 
793  m0_error_printf(td->td_fmt, args[0], args[1], args[2], args[3],
794  args[4], args[5], args[6], args[7],
795  args[8]);
796 
797  if (td->td_fmt[strlen(td->td_fmt) - 1] != '\n')
798  m0_error_printf("\n");
799 }
800 
801 void m0_console_printf(const char *fmt, ...)
802 {
803  va_list ap;
804 
805  va_start(ap, fmt);
806  m0_console_vprintf(fmt, ap);
807  va_end(ap);
808 }
809 
810 /*
811  */
812 static int format_yaml_str(char *str, size_t max_size, size_t align_size)
813 {
814  size_t str_len = strlen(str);
815  ssize_t free_space = max_size - str_len;
816  const char *fill_chars = " ";
817  char *p = str;
818 
819  if (free_space < 0 || strlen(fill_chars) < align_size)
820  return -EINVAL;
821 
822  while ((p = strchr(p, '\n')) != NULL)
823  {
824  p++;
825  free_space -= align_size;
826  if (free_space < 0)
827  return -ENOMEM;
828  memmove(p + align_size, p, strlen(p) + 1);
829  memcpy(p, fill_chars, align_size);
830  }
831 
832  return 0;
833 }
834 
835 M0_INTERNAL
836 int m0_trace_record_print_yaml(char *outbuf, size_t outbuf_size,
837  const struct m0_trace_rec_header *trh,
838  const void *tr_body, bool yaml_stream_mode)
839 {
840  const struct m0_trace_descr *td = trh->trh_descr;
842  const char *td_fmt;
843  static char msg_buf[128 * 1024]; /* 128 KB */
844  size_t outbuf_used = 0;
845  int rc;
846 
847  enum {
848  MSG_SHIFT_LEN_STREAM = 2,
849  MSG_SHIFT_LEN_NORMAL = 6,
850  };
851 
852  msg_buf[0] = '\0';
854  if (rc != 0) {
855  m0_error_printf("motr: failed to unpack trace descriptor args"
856  " for M0_LOG() inside '%s' at '%s:%u'\n",
857  td->td_func, td->td_file, td->td_line);
858  return rc;
859  }
860 
861  td_fmt = yaml_stream_mode ? "record_num: %" PRIu64 "\n"
862  "timestamp: %" PRIu64 "\n"
863  "pid: %u\n"
864  "stack_addr: %" PRIx64 "\n"
865  "subsystem: %s\n"
866  "level: %s\n"
867  "func: %s\n"
868  "file: %s\n"
869  "line: %u\n"
870  "msg: !str |\n"
871  " "
872 
873  : " - record_num: %" PRIu64 "\n"
874  " timestamp: %" PRIu64 "\n"
875  " pid: %u\n"
876  " stack_addr: %" PRIx64 "\n"
877  " subsystem: %s\n"
878  " level: %s\n"
879  " func: %s\n"
880  " file: %s\n"
881  " line: %u\n"
882  " msg: !str |\n"
883  " ";
884 
885  outbuf_used += snprintf(outbuf, outbuf_size, td_fmt,
886  trh->trh_no,
887  trh->trh_timestamp,
888  trh->trh_pid,
889  trh->trh_sp,
892  td->td_func,
893  td->td_file,
894  td->td_line);
895  if (outbuf_used >= outbuf_size)
896  return -ENOBUFS;
897 
898  rc = snprintf(msg_buf, sizeof msg_buf, td->td_fmt, args[0], args[1],
899  args[2], args[3], args[4], args[5], args[6], args[7],
900  args[8]);
901  if (rc > sizeof msg_buf)
902  m0_error_printf("motr: %s: 'msg' is too big and has been"
903  " truncated to %zu bytes",
904  __func__, sizeof msg_buf);
905 
906  rc = format_yaml_str(msg_buf, sizeof msg_buf,
907  yaml_stream_mode ? MSG_SHIFT_LEN_STREAM :
908  MSG_SHIFT_LEN_NORMAL);
909  if (rc != 0)
910  m0_error_printf("motr: %s: failed to align msg: %s\n",
911  __func__, msg_buf);
912 
913  outbuf_used += snprintf(outbuf + outbuf_used, outbuf_size - outbuf_used,
914  "%s\n", msg_buf);
915  if (outbuf_used >= outbuf_size)
916  return -ENOBUFS;
917 
918  if (yaml_stream_mode) {
919  outbuf_used += snprintf(outbuf + outbuf_used,
920  outbuf_size - outbuf_used, "---\n");
921  if (outbuf_used >= outbuf_size)
922  return -ENOBUFS;
923  }
924 
925  return 0;
926 }
927 M0_EXPORTED(m0_trace_record_print_yaml);
928 
929 M0_INTERNAL const struct m0_trace_rec_header *m0_trace_last_record_get(void)
930 {
931  char *curptr = (char*)m0_logbuf +
933  char *p = curptr;
934 
935  /* moving from current position in buffer backwards to buffer start */
936  while (p >= (char*)m0_logbuf) {
938  if (*((uint64_t*)p) == M0_TRACE_MAGIC)
939  return (const struct m0_trace_rec_header*)p;
940  }
941 
942  /* continue search from buffer end, backwards till current position */
943  p = (char*)m0_logbuf + m0_logbufsize;
944 
945  while (p >= curptr) {
947  if (*((uint64_t*)p) == M0_TRACE_MAGIC)
948  return (const struct m0_trace_rec_header*)p;
949  }
950 
951  return NULL;
952 }
953 M0_EXPORTED(m0_trace_last_record_get);
954 
955 
956 M0_INTERNAL void m0_trace_buf_header_init(struct m0_trace_buf_header *tbh, size_t buf_size)
957 {
958  const struct m0_build_info *bi = m0_build_info_get();
959 
961  tbh->tbh_header_addr = tbh;
963  /* by default, assume that trace buffer follows header immediately;
964  * m0_trace_init()|m0_arch_trace_init() may override it though */
965  tbh->tbh_buf_addr = (char*)tbh->tbh_header_addr + tbh->tbh_header_size;
966  tbh->tbh_buf_size = buf_size;
968  tbh->tbh_log_time = m0_time_now();
969 
971 
972  m0_atomic64_set(&tbh->tbh_cur_pos, 0);
973  m0_atomic64_set(&tbh->tbh_rec_cnt, 0);
974 
975  strncpy(tbh->tbh_motr_version, bi->bi_version_string,
976  sizeof tbh->tbh_motr_version - 1);
977  strncpy(tbh->tbh_motr_git_describe, bi->bi_git_describe,
978  sizeof tbh->tbh_motr_git_describe - 1);
979  strncpy(tbh->tbh_motr_kernel_ver, bi->bi_kernel,
980  sizeof tbh->tbh_motr_kernel_ver - 1);
981 
983 }
984 M0_EXPORTED(m0_trace_buf_header_init);
985 
986 M0_INTERNAL void m0_trace_switch_to_static_logbuf(void)
987 {
988  m0_logbuf_header = &bootlog.bl_area.ta_header;
989  m0_logbuf = bootlog.bl_area.ta_buf;
990  m0_trace_logbuf_size_set(sizeof bootlog.bl_buf);
991 }
992 
995 /*
996  * Local variables:
997  * c-indentation-style: "K&R"
998  * c-basic-offset: 8
999  * tab-width: 8
1000  * fill-column: 80
1001  * scroll-step: 1
1002  * End:
1003  */
M0_INTERNAL void m0_trace_buf_header_init(struct m0_trace_buf_header *tbh, size_t buf_size)
Definition: trace.c:956
Definition: trace.h:493
M0_INTERNAL const void * m0_trace_logbuf_get(void)
Definition: trace.c:618
static struct m0_addb2_philter p
Definition: consumer.c:40
#define M0_PRE(cond)
#define NULL_STRING_STUB
Definition: trace.c:180
#define m0_strdup(s)
Definition: string.h:43
M0_INTERNAL uint32_t m0_trace_logbuf_size_get(void)
Definition: trace.c:624
static char * uppercase(char *s)
Definition: trace.c:366
#define NULL
Definition: misc.h:38
static struct m0_addb2_mach * m
Definition: consumer.c:38
uint64_t td_subsys
Definition: trace.h:510
void m0_error_printf(const char *fmt,...)
Definition: ktrace.c:169
int td_line
Definition: trace.h:511
static struct @261 trace_levels[]
static enum m0_trace_level trace_level_value(char *level_name)
Definition: trace.c:472
M0_INTERNAL void m0_trace_print_subsystems(void)
Definition: trace.c:678
struct m0_atomic64 tbh_cur_pos
Definition: trace.h:385
M0_INTERNAL void m0_trace_logbuf_size_set(size_t size)
Definition: trace.c:630
enum m0_trace_level level
Definition: trace.c:111
uint64_t trh_timestamp
Definition: trace.h:444
uint64_t tbh_buf_size
Definition: trace.h:376
void m0_console_printf(const char *fmt,...)
Definition: trace.c:801
M0_INTERNAL void m0_trace_level_allow(unsigned level)
Definition: trace.c:218
enum m0_trace_level td_level
Definition: trace.h:517
M0_INTERNAL int m0_trace_record_print_yaml(char *outbuf, size_t outbuf_size, const struct m0_trace_rec_header *trh, const void *tr_body, bool yaml_stream_mode)
Definition: trace.c:836
const bool * td_isstr
Definition: trace.h:516
static bool m0_is_po2(uint64_t val)
Definition: arith.h:153
const int * td_offset
Definition: trace.h:514
int m0_trace_magic_sym_extra_addr_add(const void *addr)
Definition: trace.c:654
union m0_trace_rec_argument m0_trace_rec_args_t[M0_TRACE_ARGC_MAX]
void * m0_logbuf
Definition: trace.c:86
M0_INTERNAL const struct m0_trace_rec_header * m0_trace_last_record_get(void)
Definition: trace.c:929
const void * tbh_header_addr
Definition: trace.h:365
uint64_t * tr_body
Definition: addb2.h:435
#define M0_BITS(...)
Definition: misc.h:236
static const char * trace_subsys_str[]
Definition: trace.c:104
char tbh_motr_version[16]
Definition: trace.h:394
void m0_console_vprintf(const char *fmt, va_list args)
Definition: ktrace.c:160
static int void * buf
Definition: dir.c:1019
Definition: ub.c:49
uint16_t tbh_magic_sym_addresses_nr
Definition: trace.h:417
M0_INTERNAL const char * m0_trace_magic_sym_name_get(void)
Definition: trace.c:649
#define M0_TRACE_KBUF_SIZE
Definition: config.h:293
#define PRIx64
Definition: types.h:61
Definition: sock.c:887
struct m0_fop_cob * body
Definition: dir.c:1436
M0_INTERNAL const char * m0_short_file_name(const char *fname)
Definition: misc.c:212
M0_INTERNAL int m0_pagesize_get(void)
Definition: memory.c:233
char tbh_motr_kernel_ver[128]
Definition: trace.h:398
static char * addr
Definition: node_k.c:37
const char * td_func
Definition: trace.h:508
int i
Definition: dir.c:1033
#define PRIu64
Definition: types.h:58
def args
Definition: addb2db.py:716
M0_INTERNAL void m0_arch_trace_fini(void)
Definition: ktrace.c:225
const char * bi_kernel
Definition: version.h:45
const struct m0_build_info * m0_build_info_get(void)
Definition: version.c:61
Definition: trace.h:482
const char * name
Definition: trace.c:110
M0_INTERNAL const char * m0_trace_subsys_name(uint64_t subsys)
Definition: trace.c:339
uint64_t trh_sp
Definition: trace.h:441
M0_INTERNAL int m0_trace_subsys_list_to_mask(char *subsys_names, unsigned long *ret_mask)
Definition: trace.c:414
uint32_t trh_string_data_size
Definition: trace.h:446
M0_INTERNAL void m0_trace_switch_to_static_logbuf(void)
Definition: trace.c:986
static const char * trace_print_ctx_str[]
Definition: trace.c:125
M0_INTERNAL int m0_trace_set_print_context(const char *ctx_name)
Definition: trace.c:562
M0_INTERNAL void m0_trace_stats_update(uint32_t rec_size)
Definition: ktrace.c:119
char tbh_motr_git_describe[64]
Definition: trace.h:396
m0_time_t m0_time_now(void)
Definition: time.c:134
static uint32_t calc_string_data_size(const struct m0_trace_descr *td, const void *body)
Definition: trace.c:182
M0_INTERNAL void m0_trace_fini(void)
Definition: trace.c:148
static struct @260 bootlog
#define m0_streq(a, b)
Definition: string.h:34
M0_INTERNAL const char * m0_trace_level_name(enum m0_trace_level level)
Definition: trace.c:460
static const char trace_magic_symbol_name[]
Definition: trace.c:68
#define M0_TRACE_UBUF_SIZE
Definition: config.h:296
static int format_yaml_str(char *str, size_t max_size, size_t align_size)
Definition: trace.c:812
const char * bi_git_describe
Definition: version.h:35
char * fmt(const char *format,...) __attribute__((format(printf
bool td_hasstr
Definition: trace.h:518
const void * tbh_magic_sym_addresses[128]
Definition: trace.h:419
#define M0_POST(cond)
Definition: xcode.h:73
const char * td_fmt
Definition: trace.h:507
pid_t m0_pid_cached
Definition: utrace.c:55
uint64_t tbh_magic
Definition: trace.h:363
M0_INTERNAL const struct m0_trace_buf_header * m0_trace_logbuf_header_get(void)
Definition: trace.c:612
struct m0_atomic64 tbh_rec_cnt
Definition: trace.h:387
static struct fdmi_ctx ctx
Definition: main.c:80
static struct m0_clink l[NR]
Definition: chan.c:37
M0_INTERNAL void m0_trace_record_print(const struct m0_trace_rec_header *trh, const void *buf)
Definition: trace.c:746
static int64_t m0_atomic64_get(const struct m0_atomic64 *a)
const char * td_file
Definition: trace.h:509
M0_INTERNAL void m0_trace_allot(const struct m0_trace_descr *td, const void *body)
Definition: trace.c:225
static enum m0_trace_level trace_level_value_plus(char *level_name)
Definition: trace.c:488
M0_INTERNAL int m0_trace_args_unpack(const struct m0_trace_rec_header *trh, m0_trace_rec_args_t args, const void *buf)
Definition: trace.c:690
char bl_buf[BOOTLOG_BUF_SIZE]
Definition: trace.c:81
uint64_t n
Definition: fops.h:107
const void * tbh_buf_addr
Definition: trace.h:374
uint32_t tbh_header_size
Definition: trace.h:372
size_t m0_logbufsize
Definition: trace.c:87
const void * tbh_magic_sym_addr
Definition: trace.h:392
Definition: trace.h:459
int td_size
Definition: trace.h:512
m0_trace_level
Definition: trace.h:454
m0_bcount_t size
Definition: di.c:39
static char * lowercase(char *s)
Definition: trace.c:376
static unsigned allowed_level
Definition: trace.c:216
const int * td_sizeof
Definition: trace.h:515
m0_trace_print_context
Definition: trace.h:496
static const uint64_t trace_magic_symbol
Definition: trace.c:67
static size_t bufmask
Definition: trace.c:88
struct @326 level_str[]
const struct m0_trace_descr * trh_descr
Definition: trace.h:445
static uint32_t buf_size
Definition: ad.c:75
Definition: nucleus.c:42
static char * subsys_str(uint64_t subsys, char *buf)
Definition: trace.c:351
unsigned long m0_trace_immediate_mask
Definition: trace.c:91
#define out(...)
Definition: gen.c:41
M0_INTERNAL const void * m0_trace_magic_sym_addr_get(void)
Definition: trace.c:644
#define CHAR_BIT
Definition: misc.h:32
M0_INTERNAL int m0_trace_init(void)
Definition: trace.c:132
static uint64_t m0_rdtsc(void)
Definition: trace.c:161
struct m0_trace_area bl_area
Definition: trace.c:80
M0_INTERNAL int m0_arch_trace_init()
Definition: ktrace.c:178
static unsigned long subsys_name_to_mask(char *subsys_name)
Definition: trace.c:386
M0_BASSERT(bootlog.bl_buf==bootlog.bl_area.ta_buf)
M0_INTERNAL void m0_arch_trace_buf_header_init(struct m0_trace_buf_header *tbh)
Definition: ktrace.c:233
struct m0_trace_buf_header * m0_logbuf_header
Definition: trace.c:85
M0_INTERNAL enum m0_trace_print_context m0_trace_print_context_parse(const char *ctx_name)
Definition: trace.c:548
void m0_free(void *data)
Definition: memory.c:146
static struct m0_addb2_source * s
Definition: consumer.c:39
M0_INTERNAL uint64_t m0_trace_logbuf_pos_get(void)
Definition: trace.c:638
m0_time_t tbh_log_time
Definition: trace.h:400
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
static uint64_t m0_align(uint64_t val, uint64_t alignment)
Definition: arith.h:170
uint64_t trh_no
Definition: trace.h:442
static int64_t m0_atomic64_add_return(struct m0_atomic64 *a, int64_t d)
static void copy_string_data(char *dst_str, const char *body, const struct m0_trace_descr *td)
Definition: trace.c:201
Definition: trace.h:478
const char * bi_version_string
Definition: version.h:33
static void m0_atomic64_set(struct m0_atomic64 *a, int64_t num)
M0_INTERNAL enum m0_trace_level m0_trace_level_parse(char *str)
Definition: trace.c:521
#define M0_IMPOSSIBLE(fmt,...)
M0_INTERNAL int m0_trace_set_level(const char *level_str)
Definition: trace.c:581