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

Showing the changes to kernel (1 of 6 files). Show all

Unified · Split

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