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
909909 /*
910910 * Find first record that fits, including all following records,
911911 * into the user-provided buffer for this dump.
912− */
912+ */
913913 seq = clear_seq;
914914 idx = clear_idx;
915915 while (seq < log_next_seq) {
@@ -919,6 +919,8 @@ static int syslog_print_all(char __user *buf, int size, bool clear) · 3 unmodified lines
919919 idx = log_next(idx);
920920 seq++;
921921 }
922+
923+ /* move first record forward until length fits into the buffer */
922924 seq = clear_seq;
923925 idx = clear_idx;
924926 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
929931 seq++;
930932 }
931933
932− /* last message in this dump */
934+ /* last message fitting into this dump */
933935 next_seq = log_next_seq;
934936
935937 len = 0;
@@ -2300,48 +2302,210 @@ module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); · 1364 unmodified lines
23002302 * kmsg_dump - dump kernel log to kernel message dumpers.
23012303 * @reason: the reason (oops, panic etc) for dumping
23022304 *
2303− * Iterate through each of the dump devices and call the oops/panic
2304− * callbacks with the log buffer.
2305+ * Call each of the registered dumper's dump() callback, which can
2306+ * retrieve the kmsg records with kmsg_dump_get_line() or
2307+ * kmsg_dump_get_buffer().
23052308 */
23062309 void kmsg_dump(enum kmsg_dump_reason reason)
23072310 {
2308− u64 idx;
23092311 struct kmsg_dumper *dumper;
2310− const char *s1, *s2;
2311− unsigned long l1, l2;
23122312 unsigned long flags;
23132313
23142314 if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
23152315 return;
23162316
2317− /* Theoretically, the log could move on after we do this, but
2318− there's not a lot we can do about that. The new messages
2319− will overwrite the start of what we dump. */
2317+ rcu_read_lock();
2318+ list_for_each_entry_rcu(dumper, &dump_list, list) {
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+ */
2358+bool 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;
23202368
23212369 raw_spin_lock_irqsave(&logbuf_lock, flags);
2322− if (syslog_seq < log_first_seq)
2323− idx = syslog_idx;
2324− else
2325− idx = log_first_idx;
2370+ if (dumper->cur_seq < log_first_seq) {
2371+ /* messages are gone, move to first available one */
2372+ dumper->cur_seq = log_first_seq;
2373+ dumper->cur_idx = log_first_idx;
2374+ }
23262375
2327− if (idx > log_next_idx) {
2328− s1 = log_buf;
2329− l1 = log_next_idx;
2376+ /* last entry */
2377+ if (dumper->cur_seq >= log_next_seq) {
2378+ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2379+ goto out;
2380+ }
23302381
2331− s2 = log_buf + idx;
2332− l2 = log_buf_len - idx;
2333− } else {
2334− s1 = "";
2335− l1 = 0;
2382+ msg = log_from_idx(dumper->cur_idx);
2383+ l = msg_print_text(msg, syslog,
2384+ line, size);
2385+
2386+ dumper->cur_idx = log_next(dumper->cur_idx);
2387+ dumper->cur_seq++;
2388+ ret = true;
2389+ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2390+out:
2391+ if (len)
2392+ *len = l;
2393+ return ret;
2394+}
2395+EXPORT_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+ */
2416+bool 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);
23362459
2337− s2 = log_buf + idx;
2338− l2 = log_next_idx - idx;
2460+ l -= msg_print_text(msg, true, NULL, 0);
2461+ idx = log_next(idx);
2462+ seq++;
23392463 }
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;
23402483 raw_spin_unlock_irqrestore(&logbuf_lock, flags);
2484+out:
2485+ if (len)
2486+ *len = l;
2487+ return ret;
2488+}
2489+EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
23412490
2342− rcu_read_lock();
2343− list_for_each_entry_rcu(dumper, &dump_list, list)
2344− dumper->dump(dumper, reason, s1, l1, s2, l2);
2345− rcu_read_unlock();
2491+/**
2492+ * kmsg_dump_rewind - reset the interator
2493+ * @dumper: registered kmsg dumper
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+ */
2499+void 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);
23462509 }
2510+EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
23472511 #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