/* * callback from kmsg_dump. (s2,l2) has the most recently * written bytes, older bytes are in (s1,l1). Save as much * as we can from the end of the buffer. */ static void pstore_dump(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason) { unsigned long total = 0; const char *why; u64 id; unsigned int part = 1; unsigned long flags = 0; int is_locked = 0; int ret; why = get_reason_str(reason); if (pstore_cannot_block_path(reason)) { is_locked = spin_trylock_irqsave(&psinfo->buf_lock, flags); if (!is_locked) { pr_err("pstore dump routine blocked in %s path, may corrupt error record\n" , in_nmi() ? "NMI" : why); } } else spin_lock_irqsave(&psinfo->buf_lock, flags); oopscount++; while (total < kmsg_bytes) { char *dst; unsigned long size; int hsize; int zipped_len = -1; size_t len; bool compressed; size_t total_len; if (big_oops_buf && is_locked) { dst = big_oops_buf; hsize = sprintf(dst, "%s#%d Part%u\n", why, oopscount, part); size = big_oops_buf_sz - hsize; if (!kmsg_dump_get_buffer(dumper, true, dst + hsize, size, &len)) break; zipped_len = pstore_compress(dst, psinfo->buf, hsize + len, psinfo->bufsize); if (zipped_len > 0) { compressed = true; total_len = zipped_len; } else { compressed = false; total_len = copy_kmsg_to_buffer(hsize, len); } } else { dst = psinfo->buf; hsize = sprintf(dst, "%s#%d Part%u\n", why, oopscount, part); size = psinfo->bufsize - hsize; dst += hsize; if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len)) break; compressed = false; total_len = hsize + len; } ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part, oopscount, compressed, total_len, psinfo); if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted()) pstore_new_entry = 1; total += total_len; part++; } if (pstore_cannot_block_path(reason)) { if (is_locked) spin_unlock_irqrestore(&psinfo->buf_lock, flags); } else spin_unlock_irqrestore(&psinfo->buf_lock, flags); }
/* * callback from kmsg_dump. Save as much as we can (up to kmsg_bytes) from the * end of the buffer. */ static void pstore_dump(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason) { unsigned long total = 0; const char *why; unsigned int part = 1; int ret; why = get_reason_str(reason); if (down_trylock(&psinfo->buf_lock)) { /* Failed to acquire lock: give up if we cannot wait. */ if (pstore_cannot_wait(reason)) { pr_err("dump skipped in %s path: may corrupt error record\n", in_nmi() ? "NMI" : why); return; } if (down_interruptible(&psinfo->buf_lock)) { pr_err("could not grab semaphore?!\n"); return; } } oopscount++; while (total < kmsg_bytes) { char *dst; size_t dst_size; int header_size; int zipped_len = -1; size_t dump_size; struct pstore_record record; pstore_record_init(&record, psinfo); record.type = PSTORE_TYPE_DMESG; record.count = oopscount; record.reason = reason; record.part = part; record.buf = psinfo->buf; if (big_oops_buf) { dst = big_oops_buf; dst_size = big_oops_buf_sz; } else { dst = psinfo->buf; dst_size = psinfo->bufsize; } /* Write dump header. */ header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why, oopscount, part); dst_size -= header_size; /* Write dump contents. */ if (!kmsg_dump_get_buffer(dumper, true, dst + header_size, dst_size, &dump_size)) break; if (big_oops_buf) { zipped_len = pstore_compress(dst, psinfo->buf, header_size + dump_size, psinfo->bufsize); if (zipped_len > 0) { record.compressed = true; record.size = zipped_len; } else { record.size = copy_kmsg_to_buffer(header_size, dump_size); } } else { record.size = header_size + dump_size; } ret = psinfo->write(&record); if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted()) pstore_new_entry = 1; total += record.size; part++; } up(&psinfo->buf_lock); }