mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
Merge branch 'anton-kgdb' (kgdb dmesg fixups)
Merge emailed kgdb dmesg fixups patches from Anton Vorontsov: "The dmesg command appears to be broken after the printk rework. The old logic in the kdb code makes no sense in terms of current printk/logging storage format, and KDB simply hangs forever upon entering 'dmesg' command. The first patch revives the command by switching to kmsg_dumper iterator. As a side-effect, the code is now much more simpler. A few changes were needed in the printk.c: we needed unlocked variant of the kmsg_dumper iterator, but these can surely wait for 3.6. It's probably too late even for the first patch to go to 3.5, but I'll try to convince otherwise. :-) Here we go: - The current code is broken for sure, and has no hope to work at all. It is a regression - The new code works for me, and probably works for everyone else; - If it compiles (and I urge everyone to compile-test it on your setup), it hardly can make things worse." * Merge emailed patches from Anton Vorontsov: (4 commits) kdb: Switch to nolock variants of kmsg_dump functions printk: Implement some unlocked kmsg_dump functions printk: Remove kdb_syslog_data kdb: Revive dmesg command
This commit is contained in:
commit
9a2bc8603e
@ -55,12 +55,17 @@ struct kmsg_dumper {
|
||||
#ifdef CONFIG_PRINTK
|
||||
void kmsg_dump(enum kmsg_dump_reason reason);
|
||||
|
||||
bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
|
||||
char *line, size_t size, size_t *len);
|
||||
|
||||
bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
|
||||
char *line, size_t size, size_t *len);
|
||||
|
||||
bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
||||
char *buf, size_t size, size_t *len);
|
||||
|
||||
void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper);
|
||||
|
||||
void kmsg_dump_rewind(struct kmsg_dumper *dumper);
|
||||
|
||||
int kmsg_dump_register(struct kmsg_dumper *dumper);
|
||||
@ -71,6 +76,13 @@ static inline void kmsg_dump(enum kmsg_dump_reason reason)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper,
|
||||
bool syslog, const char *line,
|
||||
size_t size, size_t *len)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
|
||||
const char *line, size_t size, size_t *len)
|
||||
{
|
||||
@ -83,6 +95,10 @@ static inline bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void kmsg_dump_rewind(struct kmsg_dumper *dumper)
|
||||
{
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kmsg_dump.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sysrq.h>
|
||||
@ -2040,8 +2041,15 @@ static int kdb_env(int argc, const char **argv)
|
||||
*/
|
||||
static int kdb_dmesg(int argc, const char **argv)
|
||||
{
|
||||
char *syslog_data[4], *start, *end, c = '\0', *p;
|
||||
int diag, logging, logsize, lines = 0, adjust = 0, n;
|
||||
int diag;
|
||||
int logging;
|
||||
int lines = 0;
|
||||
int adjust = 0;
|
||||
int n = 0;
|
||||
int skip = 0;
|
||||
struct kmsg_dumper dumper = { .active = 1 };
|
||||
size_t len;
|
||||
char buf[201];
|
||||
|
||||
if (argc > 2)
|
||||
return KDB_ARGCOUNT;
|
||||
@ -2064,22 +2072,10 @@ static int kdb_dmesg(int argc, const char **argv)
|
||||
kdb_set(2, setargs);
|
||||
}
|
||||
|
||||
/* syslog_data[0,1] physical start, end+1. syslog_data[2,3]
|
||||
* logical start, end+1. */
|
||||
kdb_syslog_data(syslog_data);
|
||||
if (syslog_data[2] == syslog_data[3])
|
||||
return 0;
|
||||
logsize = syslog_data[1] - syslog_data[0];
|
||||
start = syslog_data[2];
|
||||
end = syslog_data[3];
|
||||
#define KDB_WRAP(p) (((p - syslog_data[0]) % logsize) + syslog_data[0])
|
||||
for (n = 0, p = start; p < end; ++p) {
|
||||
c = *KDB_WRAP(p);
|
||||
if (c == '\n')
|
||||
++n;
|
||||
}
|
||||
if (c != '\n')
|
||||
++n;
|
||||
kmsg_dump_rewind_nolock(&dumper);
|
||||
while (kmsg_dump_get_line_nolock(&dumper, 1, NULL, 0, NULL))
|
||||
n++;
|
||||
|
||||
if (lines < 0) {
|
||||
if (adjust >= n)
|
||||
kdb_printf("buffer only contains %d lines, nothing "
|
||||
@ -2087,21 +2083,11 @@ static int kdb_dmesg(int argc, const char **argv)
|
||||
else if (adjust - lines >= n)
|
||||
kdb_printf("buffer only contains %d lines, last %d "
|
||||
"lines printed\n", n, n - adjust);
|
||||
if (adjust) {
|
||||
for (; start < end && adjust; ++start) {
|
||||
if (*KDB_WRAP(start) == '\n')
|
||||
--adjust;
|
||||
}
|
||||
if (start < end)
|
||||
++start;
|
||||
}
|
||||
for (p = start; p < end && lines; ++p) {
|
||||
if (*KDB_WRAP(p) == '\n')
|
||||
++lines;
|
||||
}
|
||||
end = p;
|
||||
skip = adjust;
|
||||
lines = abs(lines);
|
||||
} else if (lines > 0) {
|
||||
int skip = n - (adjust + lines);
|
||||
skip = n - lines - adjust;
|
||||
lines = abs(lines);
|
||||
if (adjust >= n) {
|
||||
kdb_printf("buffer only contains %d lines, "
|
||||
"nothing printed\n", n);
|
||||
@ -2112,35 +2098,24 @@ static int kdb_dmesg(int argc, const char **argv)
|
||||
kdb_printf("buffer only contains %d lines, first "
|
||||
"%d lines printed\n", n, lines);
|
||||
}
|
||||
for (; start < end && skip; ++start) {
|
||||
if (*KDB_WRAP(start) == '\n')
|
||||
--skip;
|
||||
}
|
||||
for (p = start; p < end && lines; ++p) {
|
||||
if (*KDB_WRAP(p) == '\n')
|
||||
--lines;
|
||||
}
|
||||
end = p;
|
||||
} else {
|
||||
lines = n;
|
||||
}
|
||||
/* Do a line at a time (max 200 chars) to reduce protocol overhead */
|
||||
c = '\n';
|
||||
while (start != end) {
|
||||
char buf[201];
|
||||
p = buf;
|
||||
if (KDB_FLAG(CMD_INTERRUPT))
|
||||
return 0;
|
||||
while (start < end && (c = *KDB_WRAP(start)) &&
|
||||
(p - buf) < sizeof(buf)-1) {
|
||||
++start;
|
||||
*p++ = c;
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
if (skip >= n || skip < 0)
|
||||
return 0;
|
||||
|
||||
kmsg_dump_rewind_nolock(&dumper);
|
||||
while (kmsg_dump_get_line_nolock(&dumper, 1, buf, sizeof(buf), &len)) {
|
||||
if (skip) {
|
||||
skip--;
|
||||
continue;
|
||||
}
|
||||
*p = '\0';
|
||||
kdb_printf("%s", buf);
|
||||
if (!lines--)
|
||||
break;
|
||||
|
||||
kdb_printf("%.*s\n", (int)len - 1, buf);
|
||||
}
|
||||
if (c != '\n')
|
||||
kdb_printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -205,7 +205,6 @@ extern char kdb_grep_string[];
|
||||
extern int kdb_grep_leading;
|
||||
extern int kdb_grep_trailing;
|
||||
extern char *kdb_cmds[];
|
||||
extern void kdb_syslog_data(char *syslog_data[]);
|
||||
extern unsigned long kdb_task_state_string(const char *);
|
||||
extern char kdb_task_state_char (const struct task_struct *);
|
||||
extern unsigned long kdb_task_state(const struct task_struct *p,
|
||||
|
119
kernel/printk.c
119
kernel/printk.c
@ -1192,21 +1192,6 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
|
||||
return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KGDB_KDB
|
||||
/* kdb dmesg command needs access to the syslog buffer. do_syslog()
|
||||
* uses locks so it cannot be used during debugging. Just tell kdb
|
||||
* where the start and end of the physical and logical logs are. This
|
||||
* is equivalent to do_syslog(3).
|
||||
*/
|
||||
void kdb_syslog_data(char *syslog_data[4])
|
||||
{
|
||||
syslog_data[0] = log_buf;
|
||||
syslog_data[1] = log_buf + log_buf_len;
|
||||
syslog_data[2] = log_buf + log_first_idx;
|
||||
syslog_data[3] = log_buf + log_next_idx;
|
||||
}
|
||||
#endif /* CONFIG_KGDB_KDB */
|
||||
|
||||
static bool __read_mostly ignore_loglevel;
|
||||
|
||||
static int __init ignore_loglevel_setup(char *str)
|
||||
@ -2524,6 +2509,57 @@ void kmsg_dump(enum kmsg_dump_reason reason)
|
||||
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 log *msg;
|
||||
size_t l = 0;
|
||||
bool ret = false;
|
||||
|
||||
if (!dumper->active)
|
||||
goto out;
|
||||
|
||||
if (dumper->cur_seq < log_first_seq) {
|
||||
/* messages are gone, move to first available one */
|
||||
dumper->cur_seq = log_first_seq;
|
||||
dumper->cur_idx = log_first_idx;
|
||||
}
|
||||
|
||||
/* last entry */
|
||||
if (dumper->cur_seq >= log_next_seq)
|
||||
goto out;
|
||||
|
||||
msg = log_from_idx(dumper->cur_idx);
|
||||
l = msg_print_text(msg, 0, syslog, line, size);
|
||||
|
||||
dumper->cur_idx = 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
|
||||
@ -2545,36 +2581,12 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
|
||||
char *line, size_t size, size_t *len)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct log *msg;
|
||||
size_t l = 0;
|
||||
bool ret = false;
|
||||
|
||||
if (!dumper->active)
|
||||
goto out;
|
||||
bool ret;
|
||||
|
||||
raw_spin_lock_irqsave(&logbuf_lock, flags);
|
||||
if (dumper->cur_seq < log_first_seq) {
|
||||
/* messages are gone, move to first available one */
|
||||
dumper->cur_seq = log_first_seq;
|
||||
dumper->cur_idx = log_first_idx;
|
||||
}
|
||||
|
||||
/* last entry */
|
||||
if (dumper->cur_seq >= log_next_seq) {
|
||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = log_from_idx(dumper->cur_idx);
|
||||
l = msg_print_text(msg, 0, syslog, line, size);
|
||||
|
||||
dumper->cur_idx = log_next(dumper->cur_idx);
|
||||
dumper->cur_seq++;
|
||||
ret = true;
|
||||
ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
|
||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||
out:
|
||||
if (len)
|
||||
*len = l;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kmsg_dump_get_line);
|
||||
@ -2678,6 +2690,24 @@ out:
|
||||
}
|
||||
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 = clear_seq;
|
||||
dumper->cur_idx = clear_idx;
|
||||
dumper->next_seq = log_next_seq;
|
||||
dumper->next_idx = log_next_idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* kmsg_dump_rewind - reset the interator
|
||||
* @dumper: registered kmsg dumper
|
||||
@ -2691,10 +2721,7 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper)
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&logbuf_lock, flags);
|
||||
dumper->cur_seq = clear_seq;
|
||||
dumper->cur_idx = clear_idx;
|
||||
dumper->next_seq = log_next_seq;
|
||||
dumper->next_idx = log_next_idx;
|
||||
kmsg_dump_rewind_nolock(dumper);
|
||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
|
||||
|
Loading…
Reference in New Issue
Block a user