The patch titled Subject: printk: move kmsg_dump functions to separate file has been added to the -mm tree. Its filename is printk-move-kmsg_dump-functions-to-separate-file.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/SubmitChecklist when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Joe Perches <joe@xxxxxxxxxxx> Subject: printk: move kmsg_dump functions to separate file Generic restructuring. Create kmsg_dump.c, add to Makefile and remove from printk.c Signed-off-by: Joe Perches <joe@xxxxxxxxxxx> Cc: Kay Sievers <kay@xxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- kernel/printk/Makefile | 1 kernel/printk/kmsg_dump.c | 328 ++++++++++++++++++++++++++++++++++++ kernel/printk/printk.c | 318 ---------------------------------- 3 files changed, 329 insertions(+), 318 deletions(-) diff -puN kernel/printk/Makefile~printk-move-kmsg_dump-functions-to-separate-file kernel/printk/Makefile --- a/kernel/printk/Makefile~printk-move-kmsg_dump-functions-to-separate-file +++ a/kernel/printk/Makefile @@ -2,4 +2,5 @@ obj-y = printk.o obj-y += printk_log.o obj-y += devkmsg.o obj-y += printk_syslog.o +obj-y += kmsg_dump.o obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o diff -puN /dev/null kernel/printk/kmsg_dump.c --- /dev/null +++ a/kernel/printk/kmsg_dump.c @@ -0,0 +1,328 @@ +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/kexec.h> +#include <linux/moduleparam.h> +#include <linux/export.h> +#include <linux/kmsg_dump.h> +#include <linux/rculist.h> +#include <linux/stat.h> + +#include "printk_log.h" + +static DEFINE_SPINLOCK(dump_list_lock); +static LIST_HEAD(dump_list); + +/** + * kmsg_dump_register - register a kernel log dumper. + * @dumper: pointer to the kmsg_dumper structure + * + * Adds a kernel log dumper to the system. The dump callback in the + * structure will be called when the kernel oopses or panics and must be + * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise. + */ +int kmsg_dump_register(struct kmsg_dumper *dumper) +{ + unsigned long flags; + int err = -EBUSY; + + /* The dump callback needs to be set */ + if (!dumper->dump) + return -EINVAL; + + spin_lock_irqsave(&dump_list_lock, flags); + /* Don't allow registering multiple times */ + if (!dumper->registered) { + dumper->registered = 1; + list_add_tail_rcu(&dumper->list, &dump_list); + err = 0; + } + spin_unlock_irqrestore(&dump_list_lock, flags); + + return err; +} +EXPORT_SYMBOL_GPL(kmsg_dump_register); + +/** + * kmsg_dump_unregister - unregister a kmsg dumper. + * @dumper: pointer to the kmsg_dumper structure + * + * Removes a dump device from the system. Returns zero on success and + * %-EINVAL otherwise. + */ +int kmsg_dump_unregister(struct kmsg_dumper *dumper) +{ + unsigned long flags; + int err = -EINVAL; + + spin_lock_irqsave(&dump_list_lock, flags); + if (dumper->registered) { + dumper->registered = 0; + list_del_rcu(&dumper->list); + err = 0; + } + spin_unlock_irqrestore(&dump_list_lock, flags); + synchronize_rcu(); + + return err; +} +EXPORT_SYMBOL_GPL(kmsg_dump_unregister); + +static bool always_kmsg_dump; +module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); + +/** + * kmsg_dump - dump kernel log to kernel message dumpers. + * @reason: the reason (oops, panic etc) for dumping + * + * Call each of the registered dumper's dump() callback, which can + * retrieve the kmsg records with kmsg_dump_get_line() or + * kmsg_dump_get_buffer(). + */ +void kmsg_dump(enum kmsg_dump_reason reason) +{ + struct kmsg_dumper *dumper; + unsigned long flags; + + if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(dumper, &dump_list, list) { + if (dumper->max_reason && reason > dumper->max_reason) + continue; + + /* initialize iterator with data about the stored records */ + dumper->active = true; + + raw_spin_lock_irqsave(&printk_logbuf_lock, flags); + dumper->cur_seq = printk_log_clear_seq; + dumper->cur_idx = printk_log_clear_idx; + dumper->next_seq = printk_log_next_seq; + dumper->next_idx = printk_log_next_idx; + raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); + + /* invoke dumper which will iterate over records */ + dumper->dump(dumper, reason); + + /* reset iterator */ + dumper->active = false; + } + rcu_read_unlock(); +} + +/** + * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) + * @dumper: registered kmsg dumper + * @syslog: include the "<4>" prefixes + * @line: buffer to copy the line to + * @size: maximum size of the buffer + * @len: length of line placed into buffer + * + * Start at the beginning of the kmsg buffer, with the oldest kmsg + * record, and copy one record into the provided buffer. + * + * Consecutive calls will return the next available record moving + * towards the end of the buffer with the youngest messages. + * + * A return value of FALSE indicates that there are no more records to + * read. + * + * The function is similar to kmsg_dump_get_line(), but grabs no locks. + */ +bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, + char *line, size_t size, size_t *len) +{ + struct printk_log *msg; + size_t l = 0; + bool ret = false; + + if (!dumper->active) + goto out; + + if (dumper->cur_seq < printk_log_first_seq) { + /* messages are gone, move to first available one */ + dumper->cur_seq = printk_log_first_seq; + dumper->cur_idx = printk_log_first_idx; + } + + /* last entry */ + if (dumper->cur_seq >= printk_log_next_seq) + goto out; + + msg = printk_log_from_idx(dumper->cur_idx); + l = printk_msg_print_text(msg, 0, syslog, line, size); + + dumper->cur_idx = printk_log_next(dumper->cur_idx); + dumper->cur_seq++; + ret = true; +out: + if (len) + *len = l; + return ret; +} + +/** + * kmsg_dump_get_line - retrieve one kmsg log line + * @dumper: registered kmsg dumper + * @syslog: include the "<4>" prefixes + * @line: buffer to copy the line to + * @size: maximum size of the buffer + * @len: length of line placed into buffer + * + * Start at the beginning of the kmsg buffer, with the oldest kmsg + * record, and copy one record into the provided buffer. + * + * Consecutive calls will return the next available record moving + * towards the end of the buffer with the youngest messages. + * + * A return value of FALSE indicates that there are no more records to + * read. + */ +bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, + char *line, size_t size, size_t *len) +{ + unsigned long flags; + bool ret; + + raw_spin_lock_irqsave(&printk_logbuf_lock, flags); + ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len); + raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(kmsg_dump_get_line); + +/** + * kmsg_dump_get_buffer - copy kmsg log lines + * @dumper: registered kmsg dumper + * @syslog: include the "<4>" prefixes + * @buf: buffer to copy the line to + * @size: maximum size of the buffer + * @len: length of line placed into buffer + * + * Start at the end of the kmsg buffer and fill the provided buffer + * with as many of the the *youngest* kmsg records that fit into it. + * If the buffer is large enough, all available kmsg records will be + * copied with a single call. + * + * Consecutive calls will fill the buffer with the next block of + * available older records, not including the earlier retrieved ones. + * + * A return value of FALSE indicates that there are no more records to + * read. + */ +bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, + char *buf, size_t size, size_t *len) +{ + unsigned long flags; + u64 seq; + u32 idx; + u64 next_seq; + u32 next_idx; + enum printk_log_flags prev; + size_t l = 0; + bool ret = false; + + if (!dumper->active) + goto out; + + raw_spin_lock_irqsave(&printk_logbuf_lock, flags); + if (dumper->cur_seq < printk_log_first_seq) { + /* messages are gone, move to first available one */ + dumper->cur_seq = printk_log_first_seq; + dumper->cur_idx = printk_log_first_idx; + } + + /* last entry */ + if (dumper->cur_seq >= dumper->next_seq) { + raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); + goto out; + } + + /* calculate length of entire buffer */ + seq = dumper->cur_seq; + idx = dumper->cur_idx; + prev = 0; + while (seq < dumper->next_seq) { + struct printk_log *msg = printk_log_from_idx(idx); + + l += printk_msg_print_text(msg, prev, true, NULL, 0); + idx = printk_log_next(idx); + seq++; + prev = msg->flags; + } + + /* move first record forward until length fits into the buffer */ + seq = dumper->cur_seq; + idx = dumper->cur_idx; + prev = 0; + while (l > size && seq < dumper->next_seq) { + struct printk_log *msg = printk_log_from_idx(idx); + + l -= printk_msg_print_text(msg, prev, true, NULL, 0); + idx = printk_log_next(idx); + seq++; + prev = msg->flags; + } + + /* last message in next interation */ + next_seq = seq; + next_idx = idx; + + l = 0; + prev = 0; + while (seq < dumper->next_seq) { + struct printk_log *msg = printk_log_from_idx(idx); + + l += printk_msg_print_text(msg, prev, syslog, buf + l, size - l); + idx = printk_log_next(idx); + seq++; + prev = msg->flags; + } + + dumper->next_seq = next_seq; + dumper->next_idx = next_idx; + ret = true; + raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); +out: + if (len) + *len = l; + return ret; +} +EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); + +/** + * kmsg_dump_rewind_nolock - reset the interator (unlocked version) + * @dumper: registered kmsg dumper + * + * Reset the dumper's iterator so that kmsg_dump_get_line() and + * kmsg_dump_get_buffer() can be called again and used multiple + * times within the same dumper.dump() callback. + * + * The function is similar to kmsg_dump_rewind(), but grabs no locks. + */ +void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) +{ + dumper->cur_seq = printk_log_clear_seq; + dumper->cur_idx = printk_log_clear_idx; + dumper->next_seq = printk_log_next_seq; + dumper->next_idx = printk_log_next_idx; +} + +/** + * kmsg_dump_rewind - reset the interator + * @dumper: registered kmsg dumper + * + * Reset the dumper's iterator so that kmsg_dump_get_line() and + * kmsg_dump_get_buffer() can be called again and used multiple + * times within the same dumper.dump() callback. + */ +void kmsg_dump_rewind(struct kmsg_dumper *dumper) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&printk_logbuf_lock, flags); + kmsg_dump_rewind_nolock(dumper); + raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); +} +EXPORT_SYMBOL_GPL(kmsg_dump_rewind); diff -puN kernel/printk/printk.c~printk-move-kmsg_dump-functions-to-separate-file kernel/printk/printk.c --- a/kernel/printk/printk.c~printk-move-kmsg_dump-functions-to-separate-file +++ a/kernel/printk/printk.c @@ -33,7 +33,6 @@ #include <linux/kexec.h> #include <linux/kdb.h> #include <linux/ratelimit.h> -#include <linux/kmsg_dump.h> #include <linux/cpu.h> #include <linux/notifier.h> #include <linux/rculist.h> @@ -1513,321 +1512,4 @@ bool printk_timed_ratelimit(unsigned lon } EXPORT_SYMBOL(printk_timed_ratelimit); -static DEFINE_SPINLOCK(dump_list_lock); -static LIST_HEAD(dump_list); - -/** - * kmsg_dump_register - register a kernel log dumper. - * @dumper: pointer to the kmsg_dumper structure - * - * Adds a kernel log dumper to the system. The dump callback in the - * structure will be called when the kernel oopses or panics and must be - * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise. - */ -int kmsg_dump_register(struct kmsg_dumper *dumper) -{ - unsigned long flags; - int err = -EBUSY; - - /* The dump callback needs to be set */ - if (!dumper->dump) - return -EINVAL; - - spin_lock_irqsave(&dump_list_lock, flags); - /* Don't allow registering multiple times */ - if (!dumper->registered) { - dumper->registered = 1; - list_add_tail_rcu(&dumper->list, &dump_list); - err = 0; - } - spin_unlock_irqrestore(&dump_list_lock, flags); - - return err; -} -EXPORT_SYMBOL_GPL(kmsg_dump_register); - -/** - * kmsg_dump_unregister - unregister a kmsg dumper. - * @dumper: pointer to the kmsg_dumper structure - * - * Removes a dump device from the system. Returns zero on success and - * %-EINVAL otherwise. - */ -int kmsg_dump_unregister(struct kmsg_dumper *dumper) -{ - unsigned long flags; - int err = -EINVAL; - - spin_lock_irqsave(&dump_list_lock, flags); - if (dumper->registered) { - dumper->registered = 0; - list_del_rcu(&dumper->list); - err = 0; - } - spin_unlock_irqrestore(&dump_list_lock, flags); - synchronize_rcu(); - - return err; -} -EXPORT_SYMBOL_GPL(kmsg_dump_unregister); - -static bool always_kmsg_dump; -module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); - -/** - * kmsg_dump - dump kernel log to kernel message dumpers. - * @reason: the reason (oops, panic etc) for dumping - * - * Call each of the registered dumper's dump() callback, which can - * retrieve the kmsg records with kmsg_dump_get_line() or - * kmsg_dump_get_buffer(). - */ -void kmsg_dump(enum kmsg_dump_reason reason) -{ - struct kmsg_dumper *dumper; - unsigned long flags; - - if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump) - return; - - rcu_read_lock(); - list_for_each_entry_rcu(dumper, &dump_list, list) { - if (dumper->max_reason && reason > dumper->max_reason) - continue; - - /* initialize iterator with data about the stored records */ - dumper->active = true; - - raw_spin_lock_irqsave(&printk_logbuf_lock, flags); - dumper->cur_seq = printk_log_clear_seq; - dumper->cur_idx = printk_log_clear_idx; - dumper->next_seq = printk_log_next_seq; - dumper->next_idx = printk_log_next_idx; - raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); - - /* invoke dumper which will iterate over records */ - dumper->dump(dumper, reason); - - /* reset iterator */ - dumper->active = false; - } - rcu_read_unlock(); -} - -/** - * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @line: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the beginning of the kmsg buffer, with the oldest kmsg - * record, and copy one record into the provided buffer. - * - * Consecutive calls will return the next available record moving - * towards the end of the buffer with the youngest messages. - * - * A return value of FALSE indicates that there are no more records to - * read. - * - * The function is similar to kmsg_dump_get_line(), but grabs no locks. - */ -bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, - char *line, size_t size, size_t *len) -{ - struct printk_log *msg; - size_t l = 0; - bool ret = false; - - if (!dumper->active) - goto out; - - if (dumper->cur_seq < printk_log_first_seq) { - /* messages are gone, move to first available one */ - dumper->cur_seq = printk_log_first_seq; - dumper->cur_idx = printk_log_first_idx; - } - - /* last entry */ - if (dumper->cur_seq >= printk_log_next_seq) - goto out; - - msg = printk_log_from_idx(dumper->cur_idx); - l = printk_msg_print_text(msg, 0, syslog, line, size); - - dumper->cur_idx = printk_log_next(dumper->cur_idx); - dumper->cur_seq++; - ret = true; -out: - if (len) - *len = l; - return ret; -} - -/** - * kmsg_dump_get_line - retrieve one kmsg log line - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @line: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the beginning of the kmsg buffer, with the oldest kmsg - * record, and copy one record into the provided buffer. - * - * Consecutive calls will return the next available record moving - * towards the end of the buffer with the youngest messages. - * - * A return value of FALSE indicates that there are no more records to - * read. - */ -bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, - char *line, size_t size, size_t *len) -{ - unsigned long flags; - bool ret; - - raw_spin_lock_irqsave(&printk_logbuf_lock, flags); - ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len); - raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(kmsg_dump_get_line); - -/** - * kmsg_dump_get_buffer - copy kmsg log lines - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @buf: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the end of the kmsg buffer and fill the provided buffer - * with as many of the the *youngest* kmsg records that fit into it. - * If the buffer is large enough, all available kmsg records will be - * copied with a single call. - * - * Consecutive calls will fill the buffer with the next block of - * available older records, not including the earlier retrieved ones. - * - * A return value of FALSE indicates that there are no more records to - * read. - */ -bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, - char *buf, size_t size, size_t *len) -{ - unsigned long flags; - u64 seq; - u32 idx; - u64 next_seq; - u32 next_idx; - enum printk_log_flags prev; - size_t l = 0; - bool ret = false; - - if (!dumper->active) - goto out; - - raw_spin_lock_irqsave(&printk_logbuf_lock, flags); - if (dumper->cur_seq < printk_log_first_seq) { - /* messages are gone, move to first available one */ - dumper->cur_seq = printk_log_first_seq; - dumper->cur_idx = printk_log_first_idx; - } - - /* last entry */ - if (dumper->cur_seq >= dumper->next_seq) { - raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); - goto out; - } - - /* calculate length of entire buffer */ - seq = dumper->cur_seq; - idx = dumper->cur_idx; - prev = 0; - while (seq < dumper->next_seq) { - struct printk_log *msg = printk_log_from_idx(idx); - - l += printk_msg_print_text(msg, prev, true, NULL, 0); - idx = printk_log_next(idx); - seq++; - prev = msg->flags; - } - - /* move first record forward until length fits into the buffer */ - seq = dumper->cur_seq; - idx = dumper->cur_idx; - prev = 0; - while (l > size && seq < dumper->next_seq) { - struct printk_log *msg = printk_log_from_idx(idx); - - l -= printk_msg_print_text(msg, prev, true, NULL, 0); - idx = printk_log_next(idx); - seq++; - prev = msg->flags; - } - - /* last message in next interation */ - next_seq = seq; - next_idx = idx; - - l = 0; - prev = 0; - while (seq < dumper->next_seq) { - struct printk_log *msg = printk_log_from_idx(idx); - - l += printk_msg_print_text(msg, prev, syslog, buf + l, size - l); - idx = printk_log_next(idx); - seq++; - prev = msg->flags; - } - - dumper->next_seq = next_seq; - dumper->next_idx = next_idx; - ret = true; - raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); -out: - if (len) - *len = l; - return ret; -} -EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); - -/** - * kmsg_dump_rewind_nolock - reset the interator (unlocked version) - * @dumper: registered kmsg dumper - * - * Reset the dumper's iterator so that kmsg_dump_get_line() and - * kmsg_dump_get_buffer() can be called again and used multiple - * times within the same dumper.dump() callback. - * - * The function is similar to kmsg_dump_rewind(), but grabs no locks. - */ -void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) -{ - dumper->cur_seq = printk_log_clear_seq; - dumper->cur_idx = printk_log_clear_idx; - dumper->next_seq = printk_log_next_seq; - dumper->next_idx = printk_log_next_idx; -} - -/** - * kmsg_dump_rewind - reset the interator - * @dumper: registered kmsg dumper - * - * Reset the dumper's iterator so that kmsg_dump_get_line() and - * kmsg_dump_get_buffer() can be called again and used multiple - * times within the same dumper.dump() callback. - */ -void kmsg_dump_rewind(struct kmsg_dumper *dumper) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&printk_logbuf_lock, flags); - kmsg_dump_rewind_nolock(dumper); - raw_spin_unlock_irqrestore(&printk_logbuf_lock, flags); -} -EXPORT_SYMBOL_GPL(kmsg_dump_rewind); #endif _ Patches currently in -mm which might be from joe@xxxxxxxxxxx are printk-move-to-separate-directory-for-easier-modification.patch printk-add-console_cmdlineh.patch printk-move-braille-console-support-into-separate-braille-files.patch printk-use-pointer-for-console_cmdline-indexing.patch printk-rename-struct-log-to-struct-printk_log.patch printk-rename-log_buf-and-__log_buf_len.patch printk-rename-log_first-and-log_next-variables.patch printk-rename-log_foo-variables-and-functions.patch printk-rename-enum-log_flags-to-printk_log_flags.patch printk-rename-log_wait-to-printk_log_wait.patch printk-rename-logbuf_lock-to-printk_logbuf_lock.patch printk-rename-clear_seq-and-clear_idx-variables.patch printk-remove-static-from-printk_-variables.patch printk-rename-log_align-to-printk_log_align.patch printk-add-and-use-printk_logh.patch printk-add-printk_logc.patch printk-make-wait_queue_head_t-printk_log_wait-extern.patch printk-rename-and-move-2-defines-to-printk_logh.patch printk-move-devkmsg-bits-to-separate-file.patch printk-prefix-print_time-and-msg_print_text-with-printk_.patch printk-move-functions-printk_print_time-and-printk_msg_print_text.patch printk-add-printk_syslogc-and-h.patch printk-move-kmsg_dump-functions-to-separate-file.patch maintainers-networking-drivers-matches-too-much.patch checkpatch-improve-network-block-comment-style-checking.patch kstrto-add-documentation.patch simple_strto-annotate-function-as-obsolete.patch -- To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html