History

kmsg - kmsg_dump() use iterator to receive log buffer content

Provide an iterator to receive the log buffer content, and convert all kmsg_dump() users to it. The structured data in the kmsg buffer now contains binary data, which should no longer be copied verbatim to the kmsg_dump() users. The iterator should provide reliable access to the buffer data, and also supports proper log line-aware chunking of data while iterating.

Kay Sievers committed 14 years ago

Commit e2ae7151 parent 1bd289d6 files · +258 −137Browse files

Unified · Split

6 files
  1. arch/powerpc/platforms/pseries/nvram.c +7 −54
  2. arch/x86/platform/mrst/early_printk_mrst.c +5 −8
  3. drivers/mtd/mtdoops.c +4 −18
  4. fs/pstore/platform.c +12 −22
  5. include/linux/kmsg_dump.h +38 −7
  6. kernel/printk.c +192 −28
arch/powerpc/platforms/pseries/nvram.c+7−54
@@ -68,9 +68,7 @@ static const char *pseries_nvram_os_partitions[] = { · 67 unmodified lines
68};68};
69 69
70static void oops_to_nvram(struct kmsg_dumper *dumper,70static void oops_to_nvram(struct kmsg_dumper *dumper,
71 enum kmsg_dump_reason reason,71 enum kmsg_dump_reason reason);
72 const char *old_msgs, unsigned long old_len,
73 const char *new_msgs, unsigned long new_len);
74 72
75static struct kmsg_dumper nvram_kmsg_dumper = {73static struct kmsg_dumper nvram_kmsg_dumper = {
76 .dump = oops_to_nvram74 .dump = oops_to_nvram
@@ -503,28 +501,6 @@ int __init pSeries_nvram_init(void) · 426 unmodified lines
503 return 0;501 return 0;
504}502}
505 503
506/*
507 * Try to capture the last capture_len bytes of the printk buffer. Return
508 * the amount actually captured.
509 */
510static size_t capture_last_msgs(const char *old_msgs, size_t old_len,
511 const char *new_msgs, size_t new_len,
512 char *captured, size_t capture_len)
513{
514 if (new_len >= capture_len) {
515 memcpy(captured, new_msgs + (new_len - capture_len),
516 capture_len);
517 return capture_len;
518 } else {
519 /* Grab the end of old_msgs. */
520 size_t old_tail_len = min(old_len, capture_len - new_len);
521 memcpy(captured, old_msgs + (old_len - old_tail_len),
522 old_tail_len);
523 memcpy(captured + old_tail_len, new_msgs, new_len);
524 return old_tail_len + new_len;
525 }
526}
527
528/*504/*
529 * Are we using the ibm,rtas-log for oops/panic reports? And if so,505 * Are we using the ibm,rtas-log for oops/panic reports? And if so,
530 * would logging this oops/panic overwrite an RTAS event that rtas_errd506 * would logging this oops/panic overwrite an RTAS event that rtas_errd
@@ -541,27 +517,6 @@ static int clobbering_unread_rtas_event(void) · 10 unmodified lines
541 NVRAM_RTAS_READ_TIMEOUT);517 NVRAM_RTAS_READ_TIMEOUT);
542}518}
543 519
544/* Squeeze out each line's <n> severity prefix. */
545static size_t elide_severities(char *buf, size_t len)
546{
547 char *in, *out, *buf_end = buf + len;
548 /* Assume a <n> at the very beginning marks the start of a line. */
549 int newline = 1;
550
551 in = out = buf;
552 while (in < buf_end) {
553 if (newline && in+3 <= buf_end &&
554 *in == '<' && isdigit(in[1]) && in[2] == '>') {
555 in += 3;
556 newline = 0;
557 } else {
558 newline = (*in == '\n');
559 *out++ = *in++;
560 }
561 }
562 return out - buf;
563}
564
565/* Derived from logfs_compress() */520/* Derived from logfs_compress() */
566static int nvram_compress(const void *in, void *out, size_t inlen,521static int nvram_compress(const void *in, void *out, size_t inlen,
567 size_t outlen)522 size_t outlen)
@@ -619,9 +574,7 @@ static int zip_oops(size_t text_len) · 51 unmodified lines
619 * partition. If that's too much, go back and capture uncompressed text.574 * partition. If that's too much, go back and capture uncompressed text.
620 */575 */
621static void oops_to_nvram(struct kmsg_dumper *dumper,576static void oops_to_nvram(struct kmsg_dumper *dumper,
622 enum kmsg_dump_reason reason,577 enum kmsg_dump_reason reason)
623 const char *old_msgs, unsigned long old_len,
624 const char *new_msgs, unsigned long new_len)
625{578{
626 static unsigned int oops_count = 0;579 static unsigned int oops_count = 0;
627 static bool panicking = false;580 static bool panicking = false;
@@ -660,14 +613,14 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, · 32 unmodified lines
660 return;613 return;
661 614
662 if (big_oops_buf) {615 if (big_oops_buf) {
663 text_len = capture_last_msgs(old_msgs, old_len,616 kmsg_dump_get_buffer(dumper, false,
664 new_msgs, new_len, big_oops_buf, big_oops_buf_sz);617 big_oops_buf, big_oops_buf_sz, &text_len);
665 text_len = elide_severities(big_oops_buf, text_len);
666 rc = zip_oops(text_len);618 rc = zip_oops(text_len);
667 }619 }
668 if (rc != 0) {620 if (rc != 0) {
669 text_len = capture_last_msgs(old_msgs, old_len,621 kmsg_dump_rewind(dumper);
670 new_msgs, new_len, oops_data, oops_data_sz);622 kmsg_dump_get_buffer(dumper, true,
623 oops_data, oops_data_sz, &text_len);
671 err_type = ERR_TYPE_KERNEL_PANIC;624 err_type = ERR_TYPE_KERNEL_PANIC;
672 *oops_len = (u16) text_len;625 *oops_len = (u16) text_len;
673 }626 }
arch/x86/platform/mrst/early_printk_mrst.c+5−8
@@ -110,19 +110,16 @@ static struct kmsg_dumper dw_dumper; · 109 unmodified lines
110static int dumper_registered;110static int dumper_registered;
111 111
112static void dw_kmsg_dump(struct kmsg_dumper *dumper,112static void dw_kmsg_dump(struct kmsg_dumper *dumper,
113 enum kmsg_dump_reason reason,113 enum kmsg_dump_reason reason)
114 const char *s1, unsigned long l1,
115 const char *s2, unsigned long l2)
116{114{
117 int i;115 static char line[1024];
116 size_t len;
118 117
119 /* When run to this, we'd better re-init the HW */118 /* When run to this, we'd better re-init the HW */
120 mrst_early_console_init();119 mrst_early_console_init();
121 120
122 for (i = 0; i < l1; i++)121 while (kmsg_dump_get_line(dumper, true, line, sizeof(line), &len))
123 early_mrst_console.write(&early_mrst_console, s1 + i, 1);122 early_mrst_console.write(&early_mrst_console, line, len);
124 for (i = 0; i < l2; i++)
125 early_mrst_console.write(&early_mrst_console, s2 + i, 1);
126}123}
127 124
128/* Set the ratio rate to 115200, 8n1, IRQ disabled */125/* Set the ratio rate to 115200, 8n1, IRQ disabled */
drivers/mtd/mtdoops.c+4−18
@@ -304,32 +304,17 @@ static void find_next_position(struct mtdoops_context *cxt) · 303 unmodified lines
304}304}
305 305
306static void mtdoops_do_dump(struct kmsg_dumper *dumper,306static void mtdoops_do_dump(struct kmsg_dumper *dumper,
307 enum kmsg_dump_reason reason, const char *s1, unsigned long l1,307 enum kmsg_dump_reason reason)
308 const char *s2, unsigned long l2)
309{308{
310 struct mtdoops_context *cxt = container_of(dumper,309 struct mtdoops_context *cxt = container_of(dumper,
311 struct mtdoops_context, dump);310 struct mtdoops_context, dump);
312 unsigned long s1_start, s2_start;
313 unsigned long l1_cpy, l2_cpy;
314 char *dst;
315
316 if (reason != KMSG_DUMP_OOPS &&
317 reason != KMSG_DUMP_PANIC)
318 return;
319 311
320 /* Only dump oopses if dump_oops is set */312 /* Only dump oopses if dump_oops is set */
321 if (reason == KMSG_DUMP_OOPS && !dump_oops)313 if (reason == KMSG_DUMP_OOPS && !dump_oops)
322 return;314 return;
323 315
324 dst = cxt->oops_buf + MTDOOPS_HEADER_SIZE; /* Skip the header */316 kmsg_dump_get_buffer(dumper, true, cxt->oops_buf + MTDOOPS_HEADER_SIZE,
325 l2_cpy = min(l2, record_size - MTDOOPS_HEADER_SIZE);317 record_size - MTDOOPS_HEADER_SIZE, NULL);
326 l1_cpy = min(l1, record_size - MTDOOPS_HEADER_SIZE - l2_cpy);
327
328 s2_start = l2 - l2_cpy;
329 s1_start = l1 - l1_cpy;
330
331 memcpy(dst, s1 + s1_start, l1_cpy);
332 memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
333 318
334 /* Panics must be written immediately */319 /* Panics must be written immediately */
335 if (reason != KMSG_DUMP_OOPS)320 if (reason != KMSG_DUMP_OOPS)
@@ -375,6 +360,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) · 39 unmodified lines
375 return;360 return;
376 }361 }
377 362
363 cxt->dump.max_reason = KMSG_DUMP_OOPS;
378 cxt->dump.dump = mtdoops_do_dump;364 cxt->dump.dump = mtdoops_do_dump;
379 err = kmsg_dump_register(&cxt->dump);365 err = kmsg_dump_register(&cxt->dump);
380 if (err) {366 if (err) {
fs/pstore/platform.c+12−22
@@ -94,20 +94,15 @@ static const char *get_reason_str(enum kmsg_dump_reason reason) · 93 unmodified lines
94 * as we can from the end of the buffer.94 * as we can from the end of the buffer.
95 */95 */
96static void pstore_dump(struct kmsg_dumper *dumper,96static void pstore_dump(struct kmsg_dumper *dumper,
97 enum kmsg_dump_reason reason,97 enum kmsg_dump_reason reason)
98 const char *s1, unsigned long l1,
99 const char *s2, unsigned long l2)
100{98{
101 unsigned long s1_start, s2_start;99 unsigned long total = 0;
102 unsigned long l1_cpy, l2_cpy;
103 unsigned long size, total = 0;
104 char *dst;
105 const char *why;100 const char *why;
106 u64 id;101 u64 id;
107 int hsize, ret;
108 unsigned int part = 1;102 unsigned int part = 1;
109 unsigned long flags = 0;103 unsigned long flags = 0;
110 int is_locked = 0;104 int is_locked = 0;
105 int ret;
111 106
112 why = get_reason_str(reason);107 why = get_reason_str(reason);
113 108
@@ -119,30 +114,25 @@ static void pstore_dump(struct kmsg_dumper *dumper, · 5 unmodified lines
119 spin_lock_irqsave(&psinfo->buf_lock, flags);114 spin_lock_irqsave(&psinfo->buf_lock, flags);
120 oopscount++;115 oopscount++;
121 while (total < kmsg_bytes) {116 while (total < kmsg_bytes) {
117 char *dst;
118 unsigned long size;
119 int hsize;
120 size_t len;
121
122 dst = psinfo->buf;122 dst = psinfo->buf;
123 hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);123 hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);
124 size = psinfo->bufsize - hsize;124 size = psinfo->bufsize - hsize;
125 dst += hsize;125 dst += hsize;
126 126
127 l2_cpy = min(l2, size);127 if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len))
128 l1_cpy = min(l1, size - l2_cpy);
129
130 if (l1_cpy + l2_cpy == 0)
131 break;128 break;
132 129
133 s2_start = l2 - l2_cpy;
134 s1_start = l1 - l1_cpy;
135
136 memcpy(dst, s1 + s1_start, l1_cpy);
137 memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
138
139 ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,130 ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
140 hsize + l1_cpy + l2_cpy, psinfo);131 hsize + len, psinfo);
141 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())132 if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
142 pstore_new_entry = 1;133 pstore_new_entry = 1;
143 l1 -= l1_cpy;134
144 l2 -= l2_cpy;135 total += hsize + len;
145 total += l1_cpy + l2_cpy;
146 part++;136 part++;
147 }137 }
148 if (in_nmi()) {138 if (in_nmi()) {
include/linux/kmsg_dump.h+38−7
@@ -21,6 +21,7 @@ · 20 unmodified lines
21 * is passed to the kernel.21 * is passed to the kernel.
22 */22 */
23enum kmsg_dump_reason {23enum kmsg_dump_reason {
24 KMSG_DUMP_UNDEF,
24 KMSG_DUMP_PANIC,25 KMSG_DUMP_PANIC,
25 KMSG_DUMP_OOPS,26 KMSG_DUMP_OOPS,
26 KMSG_DUMP_EMERG,27 KMSG_DUMP_EMERG,
@@ -31,23 +32,37 @@ enum kmsg_dump_reason { · 4 unmodified lines
31 32
32/**33/**
33 * struct kmsg_dumper - kernel crash message dumper structure34 * struct kmsg_dumper - kernel crash message dumper structure
34 * @dump: The callback which gets called on crashes. The buffer is passed
35 * as two sections, where s1 (length l1) contains the older
36 * messages and s2 (length l2) contains the newer.
37 * @list: Entry in the dumper list (private)35 * @list: Entry in the dumper list (private)
36 * @dump: Call into dumping code which will retrieve the data with
37 * through the record iterator
38 * @max_reason: filter for highest reason number that should be dumped
38 * @registered: Flag that specifies if this is already registered39 * @registered: Flag that specifies if this is already registered
39 */40 */
40struct kmsg_dumper {41struct kmsg_dumper {
41 void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason,
42 const char *s1, unsigned long l1,
43 const char *s2, unsigned long l2);
44 struct list_head list;42 struct list_head list;
45 int registered;43 void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason);
44 enum kmsg_dump_reason max_reason;
45 bool active;
46 bool registered;
47
48 /* private state of the kmsg iterator */
49 u32 cur_idx;
50 u32 next_idx;
51 u64 cur_seq;
52 u64 next_seq;
46};53};
47 54
48#ifdef CONFIG_PRINTK55#ifdef CONFIG_PRINTK
49void kmsg_dump(enum kmsg_dump_reason reason);56void kmsg_dump(enum kmsg_dump_reason reason);
50 57
58bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
59 char *line, size_t size, size_t *len);
60
61bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
62 char *buf, size_t size, size_t *len);
63
64void kmsg_dump_rewind(struct kmsg_dumper *dumper);
65
51int kmsg_dump_register(struct kmsg_dumper *dumper);66int kmsg_dump_register(struct kmsg_dumper *dumper);
52 67
53int kmsg_dump_unregister(struct kmsg_dumper *dumper);68int kmsg_dump_unregister(struct kmsg_dumper *dumper);
@@ -56,6 +71,22 @@ static inline void kmsg_dump(enum kmsg_dump_reason reason) · 2 unmodified lines
56{71{
57}72}
58 73
74bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
75 const char *line, size_t size, size_t *len)
76{
77 return false;
78}
79
80bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
81 char *buf, size_t size, size_t *len)
82{
83 return false;
84}
85
86void kmsg_dump_rewind(struct kmsg_dumper *dumper)
87{
88}
89
59static inline int kmsg_dump_register(struct kmsg_dumper *dumper)90static inline int kmsg_dump_register(struct kmsg_dumper *dumper)
60{91{
61 return -EINVAL;92 return -EINVAL;
kernel/printk.c+192−28
@@ -909,7 +909,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) · 908 unmodified lines
909 /*909 /*
910 * Find first record that fits, including all following records,910 * Find first record that fits, including all following records,
911 * into the user-provided buffer for this dump.911 * into the user-provided buffer for this dump.
912 */912 */
913 seq = clear_seq;913 seq = clear_seq;
914 idx = clear_idx;914 idx = clear_idx;
915 while (seq < log_next_seq) {915 while (seq < log_next_seq) {
@@ -919,6 +919,8 @@ static int syslog_print_all(char __user *buf, int size, bool clear) · 3 unmodified lines
919 idx = log_next(idx);919 idx = log_next(idx);
920 seq++;920 seq++;
921 }921 }
922
923 /* move first record forward until length fits into the buffer */
922 seq = clear_seq;924 seq = clear_seq;
923 idx = clear_idx;925 idx = clear_idx;
924 while (len > size && seq < log_next_seq) {926 while (len > size && seq < log_next_seq) {
@@ -929,7 +931,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) · 4 unmodified lines
929 seq++;931 seq++;
930 }932 }
931 933
932 /* last message in this dump */934 /* last message fitting into this dump */
933 next_seq = log_next_seq;935 next_seq = log_next_seq;
934 936
935 len = 0;937 len = 0;
@@ -2300,48 +2302,210 @@ module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); · 1364 unmodified lines
2300 * kmsg_dump - dump kernel log to kernel message dumpers.2302 * kmsg_dump - dump kernel log to kernel message dumpers.
2301 * @reason: the reason (oops, panic etc) for dumping2303 * @reason: the reason (oops, panic etc) for dumping
2302 *2304 *
2303 * Iterate through each of the dump devices and call the oops/panic2305 * Call each of the registered dumper's dump() callback, which can
2304 * callbacks with the log buffer.2306 * retrieve the kmsg records with kmsg_dump_get_line() or
2307 * kmsg_dump_get_buffer().
2305 */2308 */
2306void kmsg_dump(enum kmsg_dump_reason reason)2309void kmsg_dump(enum kmsg_dump_reason reason)
2307{2310{
2308 u64 idx;
2309 struct kmsg_dumper *dumper;2311 struct kmsg_dumper *dumper;
2310 const char *s1, *s2;
2311 unsigned long l1, l2;
2312 unsigned long flags;2312 unsigned long flags;
2313 2313
2314 if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)2314 if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
2315 return;2315 return;
2316 2316
2317 /* Theoretically, the log could move on after we do this, but2317 rcu_read_lock();
2318 there's not a lot we can do about that. The new messages2318 list_for_each_entry_rcu(dumper, &dump_list, list) {
2319 will overwrite the start of what we dump. */2319 if (dumper->max_reason && reason > dumper->max_reason)
2320 continue;
2321
2322 /* initialize iterator with data about the stored records */
2323 dumper->active = true;
2324
2325 raw_spin_lock_irqsave(&logbuf_lock, flags);
2326 dumper->cur_seq = clear_seq;
2327 dumper->cur_idx = clear_idx;
2328 dumper->next_seq = log_next_seq;
2329 dumper->next_idx = log_next_idx;
2330 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2331
2332 /* invoke dumper which will iterate over records */
2333 dumper->dump(dumper, reason);
2334
2335 /* reset iterator */
2336 dumper->active = false;
2337 }
2338 rcu_read_unlock();
2339}
2340
2341/**
2342 * kmsg_dump_get_line - retrieve one kmsg log line
2343 * @dumper: registered kmsg dumper
2344 * @syslog: include the "<4>" prefixes
2345 * @line: buffer to copy the line to
2346 * @size: maximum size of the buffer
2347 * @len: length of line placed into buffer
2348 *
2349 * Start at the beginning of the kmsg buffer, with the oldest kmsg
2350 * record, and copy one record into the provided buffer.
2351 *
2352 * Consecutive calls will return the next available record moving
2353 * towards the end of the buffer with the youngest messages.
2354 *
2355 * A return value of FALSE indicates that there are no more records to
2356 * read.
2357 */
2358bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
2359 char *line, size_t size, size_t *len)
2360{
2361 unsigned long flags;
2362 struct log *msg;
2363 size_t l = 0;
2364 bool ret = false;
2365
2366 if (!dumper->active)
2367 goto out;
2320 2368
2321 raw_spin_lock_irqsave(&logbuf_lock, flags);2369 raw_spin_lock_irqsave(&logbuf_lock, flags);
2322 if (syslog_seq < log_first_seq)2370 if (dumper->cur_seq < log_first_seq) {
2323 idx = syslog_idx;2371 /* messages are gone, move to first available one */
2324 else2372 dumper->cur_seq = log_first_seq;
2325 idx = log_first_idx;2373 dumper->cur_idx = log_first_idx;
2374 }
2326 2375
2327 if (idx > log_next_idx) {2376 /* last entry */
2328 s1 = log_buf;2377 if (dumper->cur_seq >= log_next_seq) {
2329 l1 = log_next_idx;2378 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2379 goto out;
2380 }
2330 2381
2331 s2 = log_buf + idx;2382 msg = log_from_idx(dumper->cur_idx);
2332 l2 = log_buf_len - idx;2383 l = msg_print_text(msg, syslog,
2333 } else {2384 line, size);
2334 s1 = "";2385
2335 l1 = 0;2386 dumper->cur_idx = log_next(dumper->cur_idx);
2387 dumper->cur_seq++;
2388 ret = true;
2389 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2390out:
2391 if (len)
2392 *len = l;
2393 return ret;
2394}
2395EXPORT_SYMBOL_GPL(kmsg_dump_get_line);
2396
2397/**
2398 * kmsg_dump_get_buffer - copy kmsg log lines
2399 * @dumper: registered kmsg dumper
2400 * @syslog: include the "<4>" prefixes
2401 * @line: buffer to copy the line to
2402 * @size: maximum size of the buffer
2403 * @len: length of line placed into buffer
2404 *
2405 * Start at the end of the kmsg buffer and fill the provided buffer
2406 * with as many of the the *youngest* kmsg records that fit into it.
2407 * If the buffer is large enough, all available kmsg records will be
2408 * copied with a single call.
2409 *
2410 * Consecutive calls will fill the buffer with the next block of
2411 * available older records, not including the earlier retrieved ones.
2412 *
2413 * A return value of FALSE indicates that there are no more records to
2414 * read.
2415 */
2416bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
2417 char *buf, size_t size, size_t *len)
2418{
2419 unsigned long flags;
2420 u64 seq;
2421 u32 idx;
2422 u64 next_seq;
2423 u32 next_idx;
2424 size_t l = 0;
2425 bool ret = false;
2426
2427 if (!dumper->active)
2428 goto out;
2429
2430 raw_spin_lock_irqsave(&logbuf_lock, flags);
2431 if (dumper->cur_seq < log_first_seq) {
2432 /* messages are gone, move to first available one */
2433 dumper->cur_seq = log_first_seq;
2434 dumper->cur_idx = log_first_idx;
2435 }
2436
2437 /* last entry */
2438 if (dumper->cur_seq >= dumper->next_seq) {
2439 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2440 goto out;
2441 }
2442
2443 /* calculate length of entire buffer */
2444 seq = dumper->cur_seq;
2445 idx = dumper->cur_idx;
2446 while (seq < dumper->next_seq) {
2447 struct log *msg = log_from_idx(idx);
2448
2449 l += msg_print_text(msg, true, NULL, 0);
2450 idx = log_next(idx);
2451 seq++;
2452 }
2453
2454 /* move first record forward until length fits into the buffer */
2455 seq = dumper->cur_seq;
2456 idx = dumper->cur_idx;
2457 while (l > size && seq < dumper->next_seq) {
2458 struct log *msg = log_from_idx(idx);
2336 2459
2337 s2 = log_buf + idx;2460 l -= msg_print_text(msg, true, NULL, 0);
2338 l2 = log_next_idx - idx;2461 idx = log_next(idx);
2462 seq++;
2339 }2463 }
2464
2465 /* last message in next interation */
2466 next_seq = seq;
2467 next_idx = idx;
2468
2469 l = 0;
2470 while (seq < dumper->next_seq) {
2471 struct log *msg = log_from_idx(idx);
2472
2473 l += msg_print_text(msg, syslog,
2474 buf + l, size - l);
2475
2476 idx = log_next(idx);
2477 seq++;
2478 }
2479
2480 dumper->next_seq = next_seq;
2481 dumper->next_idx = next_idx;
2482 ret = true;
2340 raw_spin_unlock_irqrestore(&logbuf_lock, flags);2483 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2484out:
2485 if (len)
2486 *len = l;
2487 return ret;
2488}
2489EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
2341 2490
2342 rcu_read_lock();2491/**
2343 list_for_each_entry_rcu(dumper, &dump_list, list)2492 * kmsg_dump_rewind - reset the interator
2344 dumper->dump(dumper, reason, s1, l1, s2, l2);2493 * @dumper: registered kmsg dumper
2345 rcu_read_unlock();2494 *
2495 * Reset the dumper's iterator so that kmsg_dump_get_line() and
2496 * kmsg_dump_get_buffer() can be called again and used multiple
2497 * times within the same dumper.dump() callback.
2498 */
2499void kmsg_dump_rewind(struct kmsg_dumper *dumper)
2500{
2501 unsigned long flags;
2502
2503 raw_spin_lock_irqsave(&logbuf_lock, flags);
2504 dumper->cur_seq = clear_seq;
2505 dumper->cur_idx = clear_idx;
2506 dumper->next_seq = log_next_seq;
2507 dumper->next_idx = log_next_idx;
2508 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2346}2509}
2510EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
2347#endif2511#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t