void cfs_trace_assertion_failed(const char *str, const char *fn, const char *file, int line) { struct ptldebug_header hdr; libcfs_panic_in_progress = 1; libcfs_catastrophe = 1; cfs_mb(); cfs_set_ptldebug_header(&hdr, DEBUG_SUBSYSTEM, D_EMERG, line, CDEBUG_STACK()); cfs_print_to_console(&hdr, D_EMERG, str, strlen(str), file, fn); LIBCFS_PANIC("Lustre debug assertion failure\n"); /* not reached */ }
int libcfs_debug_vmsg2(cfs_debug_limit_state_t *cdls, int subsys, int mask, const char *file, const char *fn, const int line, const char *format1, va_list args, const char *format2, ...) { struct cfs_trace_cpu_data *tcd = NULL; struct ptldebug_header header = {0}; struct cfs_trace_page *tage; /* string_buf is used only if tcd != NULL, and is always set then */ char *string_buf = NULL; char *debug_buf; int known_size; int needed = 85; /* average message length */ int max_nob; va_list ap; int depth; int i; int remain; if (strchr(file, '/')) file = strrchr(file, '/') + 1; tcd = cfs_trace_get_tcd(); /* cfs_trace_get_tcd() grabs a lock, which disables preemption and * pins us to a particular CPU. This avoids an smp_processor_id() * warning on Linux when debugging is enabled. */ cfs_set_ptldebug_header(&header, subsys, mask, line, CDEBUG_STACK()); if (tcd == NULL) /* arch may not log in IRQ context */ goto console; if (tcd->tcd_cur_pages == 0) header.ph_flags |= PH_FLAG_FIRST_RECORD; if (tcd->tcd_shutting_down) { cfs_trace_put_tcd(tcd); tcd = NULL; goto console; } depth = __current_nesting_level(); known_size = strlen(file) + 1 + depth; if (fn) known_size += strlen(fn) + 1; if (libcfs_debug_binary) known_size += sizeof(header); /*/ * '2' used because vsnprintf return real size required for output * _without_ terminating NULL. * if needed is to small for this format. */ for (i = 0; i < 2; i++) { tage = cfs_trace_get_tage(tcd, needed + known_size + 1); if (tage == NULL) { if (needed + known_size > CFS_PAGE_SIZE) mask |= D_ERROR; cfs_trace_put_tcd(tcd); tcd = NULL; goto console; } string_buf = (char *)cfs_page_address(tage->page) + tage->used + known_size; max_nob = CFS_PAGE_SIZE - tage->used - known_size; if (max_nob <= 0) { printk(CFS_KERN_EMERG "negative max_nob: %d\n", max_nob); mask |= D_ERROR; cfs_trace_put_tcd(tcd); tcd = NULL; goto console; } needed = 0; if (format1) { va_copy(ap, args); needed = vsnprintf(string_buf, max_nob, format1, ap); va_end(ap); } if (format2) { remain = max_nob - needed; if (remain < 0) remain = 0; va_start(ap, format2); needed += vsnprintf(string_buf + needed, remain, format2, ap); va_end(ap); } if (needed < max_nob) /* well. printing ok.. */ break; } if (*(string_buf+needed-1) != '\n') printk(CFS_KERN_INFO "format at %s:%d:%s doesn't end in newline\n", file, line, fn); header.ph_len = known_size + needed; debug_buf = (char *)cfs_page_address(tage->page) + tage->used; if (libcfs_debug_binary) { memcpy(debug_buf, &header, sizeof(header)); tage->used += sizeof(header); debug_buf += sizeof(header); } /* indent message according to the nesting level */ while (depth-- > 0) { *(debug_buf++) = '.'; ++ tage->used; } strcpy(debug_buf, file); tage->used += strlen(file) + 1; debug_buf += strlen(file) + 1; if (fn) { strcpy(debug_buf, fn); tage->used += strlen(fn) + 1; debug_buf += strlen(fn) + 1; } __LASSERT(debug_buf == string_buf); tage->used += needed; __LASSERT (tage->used <= CFS_PAGE_SIZE); console: if ((mask & libcfs_printk) == 0) { /* no console output requested */ if (tcd != NULL) cfs_trace_put_tcd(tcd); return 1; } if (cdls != NULL) { if (libcfs_console_ratelimit && cdls->cdls_next != 0 && /* not first time ever */ !cfs_time_after(cfs_time_current(), cdls->cdls_next)) { /* skipping a console message */ cdls->cdls_count++; if (tcd != NULL) cfs_trace_put_tcd(tcd); return 1; } if (cfs_time_after(cfs_time_current(), cdls->cdls_next + libcfs_console_max_delay + cfs_time_seconds(10))) { /* last timeout was a long time ago */ cdls->cdls_delay /= libcfs_console_backoff * 4; } else { cdls->cdls_delay *= libcfs_console_backoff; if (cdls->cdls_delay < libcfs_console_min_delay) cdls->cdls_delay = libcfs_console_min_delay; else if (cdls->cdls_delay > libcfs_console_max_delay) cdls->cdls_delay = libcfs_console_max_delay; } /* ensure cdls_next is never zero after it's been seen */ cdls->cdls_next = (cfs_time_current() + cdls->cdls_delay) | 1; } if (tcd != NULL) { cfs_print_to_console(&header, mask, string_buf, needed, file, fn); cfs_trace_put_tcd(tcd); } else { string_buf = cfs_trace_get_console_buffer(); needed = 0; if (format1 != NULL) { va_copy(ap, args); needed = vsnprintf(string_buf, CFS_TRACE_CONSOLE_BUFFER_SIZE, format1, ap); va_end(ap); } if (format2 != NULL) { remain = CFS_TRACE_CONSOLE_BUFFER_SIZE - needed; if (remain > 0) { va_start(ap, format2); needed += vsnprintf(string_buf+needed, remain, format2, ap); va_end(ap); } } cfs_print_to_console(&header, mask, string_buf, needed, file, fn); cfs_trace_put_console_buffer(string_buf); } if (cdls != NULL && cdls->cdls_count != 0) { string_buf = cfs_trace_get_console_buffer(); needed = snprintf(string_buf, CFS_TRACE_CONSOLE_BUFFER_SIZE, "Skipped %d previous similar message%s\n", cdls->cdls_count, (cdls->cdls_count > 1) ? "s" : ""); cfs_print_to_console(&header, mask, string_buf, needed, file, fn); cfs_trace_put_console_buffer(string_buf); cdls->cdls_count = 0; } return 0; }
int spl_debug_vmsg(spl_debug_limit_state_t *cdls, int subsys, int mask, const char *file, const char *fn, const int line, const char *format1, va_list args, const char *format2, ...) { struct trace_cpu_data *tcd = NULL; struct spl_debug_header header = { 0, }; struct trace_page *tage; /* string_buf is used only if tcd != NULL, and is always set then */ char *string_buf = NULL; char *debug_buf; int known_size; int needed = 85; /* average message length */ int max_nob; va_list ap; int i; int remain; if (strchr(file, '/')) file = strrchr(file, '/') + 1; trace_set_debug_header(&header, subsys, mask, line, CDEBUG_STACK()); tcd = trace_get_tcd(); if (tcd == NULL) goto console; if (tcd->tcd_shutting_down) { trace_put_tcd(tcd); tcd = NULL; goto console; } known_size = strlen(file) + 1; if (fn) known_size += strlen(fn) + 1; if (spl_debug_binary) known_size += sizeof(header); /* '2' used because vsnprintf returns real size required for output * _without_ terminating NULL. */ for (i = 0; i < 2; i++) { tage = trace_get_tage(tcd, needed + known_size + 1); if (tage == NULL) { if (needed + known_size > PAGE_SIZE) mask |= D_ERROR; trace_put_tcd(tcd); tcd = NULL; goto console; } string_buf = (char *)page_address(tage->page) + tage->used + known_size; max_nob = PAGE_SIZE - tage->used - known_size; if (max_nob <= 0) { printk(KERN_EMERG "negative max_nob: %i\n", max_nob); mask |= D_ERROR; trace_put_tcd(tcd); tcd = NULL; goto console; } needed = 0; if (format1) { va_copy(ap, args); needed = vsnprintf(string_buf, max_nob, format1, ap); va_end(ap); } if (format2) { remain = max_nob - needed; if (remain < 0) remain = 0; va_start(ap, format2); needed += vsnprintf(string_buf+needed, remain, format2, ap); va_end(ap); } if (needed < max_nob) break; } header.ph_len = known_size + needed; debug_buf = (char *)page_address(tage->page) + tage->used; if (spl_debug_binary) { memcpy(debug_buf, &header, sizeof(header)); tage->used += sizeof(header); debug_buf += sizeof(header); } strcpy(debug_buf, file); tage->used += strlen(file) + 1; debug_buf += strlen(file) + 1; if (fn) { strcpy(debug_buf, fn); tage->used += strlen(fn) + 1; debug_buf += strlen(fn) + 1; } __ASSERT(debug_buf == string_buf); tage->used += needed; __ASSERT (tage->used <= PAGE_SIZE); console: if ((mask & spl_debug_printk) == 0) { /* no console output requested */ if (tcd != NULL) trace_put_tcd(tcd); return 1; } if (cdls != NULL) { if (spl_console_ratelimit && cdls->cdls_next != 0 && !time_before(cdls->cdls_next, jiffies)) { /* skipping a console message */ cdls->cdls_count++; if (tcd != NULL) trace_put_tcd(tcd); return 1; } if (time_before(cdls->cdls_next + spl_console_max_delay + (10 * HZ), jiffies)) { /* last timeout was a long time ago */ cdls->cdls_delay /= spl_console_backoff * 4; } else { cdls->cdls_delay *= spl_console_backoff; if (cdls->cdls_delay < spl_console_min_delay) cdls->cdls_delay = spl_console_min_delay; else if (cdls->cdls_delay > spl_console_max_delay) cdls->cdls_delay = spl_console_max_delay; } /* ensure cdls_next is never zero after it's been seen */ cdls->cdls_next = (jiffies + cdls->cdls_delay) | 1; } if (tcd != NULL) { trace_print_to_console(&header, mask, string_buf, needed, file, fn); trace_put_tcd(tcd); } else { string_buf = trace_get_console_buffer(); needed = 0; if (format1 != NULL) { va_copy(ap, args); needed = vsnprintf(string_buf, TRACE_CONSOLE_BUFFER_SIZE, format1, ap); va_end(ap); } if (format2 != NULL) { remain = TRACE_CONSOLE_BUFFER_SIZE - needed; if (remain > 0) { va_start(ap, format2); needed += vsnprintf(string_buf+needed, remain, format2, ap); va_end(ap); } } trace_print_to_console(&header, mask, string_buf, needed, file, fn); trace_put_console_buffer(string_buf); } if (cdls != NULL && cdls->cdls_count != 0) { string_buf = trace_get_console_buffer(); needed = snprintf(string_buf, TRACE_CONSOLE_BUFFER_SIZE, "Skipped %d previous similar message%s\n", cdls->cdls_count, (cdls->cdls_count > 1) ? "s" : ""); trace_print_to_console(&header, mask, string_buf, needed, file, fn); trace_put_console_buffer(string_buf); cdls->cdls_count = 0; } return 0; }