mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-24 15:42:32 +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
4 changed files with 122 additions and 105 deletions
|
@ -55,12 +55,17 @@ struct kmsg_dumper {
|
||||||
#ifdef CONFIG_PRINTK
|
#ifdef CONFIG_PRINTK
|
||||||
void kmsg_dump(enum kmsg_dump_reason reason);
|
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,
|
bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
|
||||||
char *line, size_t size, size_t *len);
|
char *line, size_t size, size_t *len);
|
||||||
|
|
||||||
bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
|
||||||
char *buf, size_t size, size_t *len);
|
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);
|
void kmsg_dump_rewind(struct kmsg_dumper *dumper);
|
||||||
|
|
||||||
int kmsg_dump_register(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,
|
static inline bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
|
||||||
const char *line, size_t size, size_t *len)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline void kmsg_dump_rewind(struct kmsg_dumper *dumper)
|
static inline void kmsg_dump_rewind(struct kmsg_dumper *dumper)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kmsg_dump.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/sysrq.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)
|
static int kdb_dmesg(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
char *syslog_data[4], *start, *end, c = '\0', *p;
|
int diag;
|
||||||
int diag, logging, logsize, lines = 0, adjust = 0, n;
|
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)
|
if (argc > 2)
|
||||||
return KDB_ARGCOUNT;
|
return KDB_ARGCOUNT;
|
||||||
|
@ -2064,22 +2072,10 @@ static int kdb_dmesg(int argc, const char **argv)
|
||||||
kdb_set(2, setargs);
|
kdb_set(2, setargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* syslog_data[0,1] physical start, end+1. syslog_data[2,3]
|
kmsg_dump_rewind_nolock(&dumper);
|
||||||
* logical start, end+1. */
|
while (kmsg_dump_get_line_nolock(&dumper, 1, NULL, 0, NULL))
|
||||||
kdb_syslog_data(syslog_data);
|
n++;
|
||||||
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;
|
|
||||||
if (lines < 0) {
|
if (lines < 0) {
|
||||||
if (adjust >= n)
|
if (adjust >= n)
|
||||||
kdb_printf("buffer only contains %d lines, nothing "
|
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)
|
else if (adjust - lines >= n)
|
||||||
kdb_printf("buffer only contains %d lines, last %d "
|
kdb_printf("buffer only contains %d lines, last %d "
|
||||||
"lines printed\n", n, n - adjust);
|
"lines printed\n", n, n - adjust);
|
||||||
if (adjust) {
|
skip = adjust;
|
||||||
for (; start < end && adjust; ++start) {
|
lines = abs(lines);
|
||||||
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;
|
|
||||||
} else if (lines > 0) {
|
} else if (lines > 0) {
|
||||||
int skip = n - (adjust + lines);
|
skip = n - lines - adjust;
|
||||||
|
lines = abs(lines);
|
||||||
if (adjust >= n) {
|
if (adjust >= n) {
|
||||||
kdb_printf("buffer only contains %d lines, "
|
kdb_printf("buffer only contains %d lines, "
|
||||||
"nothing printed\n", n);
|
"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 "
|
kdb_printf("buffer only contains %d lines, first "
|
||||||
"%d lines printed\n", n, lines);
|
"%d lines printed\n", n, lines);
|
||||||
}
|
}
|
||||||
for (; start < end && skip; ++start) {
|
} else {
|
||||||
if (*KDB_WRAP(start) == '\n')
|
lines = n;
|
||||||
--skip;
|
|
||||||
}
|
|
||||||
for (p = start; p < end && lines; ++p) {
|
|
||||||
if (*KDB_WRAP(p) == '\n')
|
|
||||||
--lines;
|
|
||||||
}
|
|
||||||
end = p;
|
|
||||||
}
|
}
|
||||||
/* Do a line at a time (max 200 chars) to reduce protocol overhead */
|
|
||||||
c = '\n';
|
if (skip >= n || skip < 0)
|
||||||
while (start != end) {
|
return 0;
|
||||||
char buf[201];
|
|
||||||
p = buf;
|
kmsg_dump_rewind_nolock(&dumper);
|
||||||
if (KDB_FLAG(CMD_INTERRUPT))
|
while (kmsg_dump_get_line_nolock(&dumper, 1, buf, sizeof(buf), &len)) {
|
||||||
return 0;
|
if (skip) {
|
||||||
while (start < end && (c = *KDB_WRAP(start)) &&
|
skip--;
|
||||||
(p - buf) < sizeof(buf)-1) {
|
continue;
|
||||||
++start;
|
|
||||||
*p++ = c;
|
|
||||||
if (c == '\n')
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
*p = '\0';
|
if (!lines--)
|
||||||
kdb_printf("%s", buf);
|
break;
|
||||||
|
|
||||||
|
kdb_printf("%.*s\n", (int)len - 1, buf);
|
||||||
}
|
}
|
||||||
if (c != '\n')
|
|
||||||
kdb_printf("\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,6 @@ extern char kdb_grep_string[];
|
||||||
extern int kdb_grep_leading;
|
extern int kdb_grep_leading;
|
||||||
extern int kdb_grep_trailing;
|
extern int kdb_grep_trailing;
|
||||||
extern char *kdb_cmds[];
|
extern char *kdb_cmds[];
|
||||||
extern void kdb_syslog_data(char *syslog_data[]);
|
|
||||||
extern unsigned long kdb_task_state_string(const char *);
|
extern unsigned long kdb_task_state_string(const char *);
|
||||||
extern char kdb_task_state_char (const struct task_struct *);
|
extern char kdb_task_state_char (const struct task_struct *);
|
||||||
extern unsigned long kdb_task_state(const struct task_struct *p,
|
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);
|
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 bool __read_mostly ignore_loglevel;
|
||||||
|
|
||||||
static int __init ignore_loglevel_setup(char *str)
|
static int __init ignore_loglevel_setup(char *str)
|
||||||
|
@ -2524,6 +2509,57 @@ void kmsg_dump(enum kmsg_dump_reason reason)
|
||||||
rcu_read_unlock();
|
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
|
* kmsg_dump_get_line - retrieve one kmsg log line
|
||||||
* @dumper: registered kmsg dumper
|
* @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)
|
char *line, size_t size, size_t *len)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct log *msg;
|
bool ret;
|
||||||
size_t l = 0;
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
if (!dumper->active)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&logbuf_lock, flags);
|
raw_spin_lock_irqsave(&logbuf_lock, flags);
|
||||||
if (dumper->cur_seq < log_first_seq) {
|
ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
|
||||||
/* 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;
|
|
||||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||||
out:
|
|
||||||
if (len)
|
|
||||||
*len = l;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kmsg_dump_get_line);
|
EXPORT_SYMBOL_GPL(kmsg_dump_get_line);
|
||||||
|
@ -2678,6 +2690,24 @@ out:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
|
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
|
* kmsg_dump_rewind - reset the interator
|
||||||
* @dumper: registered kmsg dumper
|
* @dumper: registered kmsg dumper
|
||||||
|
@ -2691,10 +2721,7 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&logbuf_lock, flags);
|
raw_spin_lock_irqsave(&logbuf_lock, flags);
|
||||||
dumper->cur_seq = clear_seq;
|
kmsg_dump_rewind_nolock(dumper);
|
||||||
dumper->cur_idx = clear_idx;
|
|
||||||
dumper->next_seq = log_next_seq;
|
|
||||||
dumper->next_idx = log_next_idx;
|
|
||||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
|
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue