You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'driver-core-3.5-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core and printk fixes from Greg Kroah-Hartman: "Here are some fixes for 3.5-rc4 that resolve the kmsg problems that people have reported showing up after the printk and kmsg changes went into 3.5-rc1. There are also a smattering of other tiny fixes for the extcon and hyper-v drivers that people have reported. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'driver-core-3.5-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: extcon: max8997: Add missing kfree for info->edev in max8997_muic_remove() extcon: Set platform drvdata in gpio_extcon_probe() and fix irq leak extcon: Fix wrong index in max8997_extcon_cable[] kmsg - kmsg_dump() fix CONFIG_PRINTK=n compilation printk: return -EINVAL if the message len is bigger than the buf size printk: use mutex lock to stop syslog_seq from going wild kmsg - kmsg_dump() use iterator to receive log buffer content vme: change maintainer e-mail address Extcon: Don't try to create duplicate link names driver core: fixup reversed deferred probe order printk: Fix alignment of buf causing crash on ARM EABI Tools: hv: verify origin of netlink connector message
This commit is contained in:
+215
-40
@@ -227,10 +227,10 @@ static u32 clear_idx;
|
||||
#define LOG_LINE_MAX 1024
|
||||
|
||||
/* record buffer */
|
||||
#if !defined(CONFIG_64BIT) || defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||||
#define LOG_ALIGN 4
|
||||
#else
|
||||
#define LOG_ALIGN 8
|
||||
#define LOG_ALIGN __alignof__(struct log)
|
||||
#endif
|
||||
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
|
||||
static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
|
||||
@@ -414,7 +414,9 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
|
||||
if (!user)
|
||||
return -EBADF;
|
||||
|
||||
mutex_lock(&user->lock);
|
||||
ret = mutex_lock_interruptible(&user->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
raw_spin_lock(&logbuf_lock);
|
||||
while (user->seq == log_next_seq) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
@@ -878,7 +880,9 @@ static int syslog_print(char __user *buf, int size)
|
||||
syslog_seq++;
|
||||
raw_spin_unlock_irq(&logbuf_lock);
|
||||
|
||||
if (len > 0 && copy_to_user(buf, text, len))
|
||||
if (len > size)
|
||||
len = -EINVAL;
|
||||
else if (len > 0 && copy_to_user(buf, text, len))
|
||||
len = -EFAULT;
|
||||
|
||||
kfree(text);
|
||||
@@ -909,7 +913,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
||||
/*
|
||||
* Find first record that fits, including all following records,
|
||||
* into the user-provided buffer for this dump.
|
||||
*/
|
||||
*/
|
||||
seq = clear_seq;
|
||||
idx = clear_idx;
|
||||
while (seq < log_next_seq) {
|
||||
@@ -919,6 +923,8 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
||||
idx = log_next(idx);
|
||||
seq++;
|
||||
}
|
||||
|
||||
/* move first record forward until length fits into the buffer */
|
||||
seq = clear_seq;
|
||||
idx = clear_idx;
|
||||
while (len > size && seq < log_next_seq) {
|
||||
@@ -929,7 +935,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
|
||||
seq++;
|
||||
}
|
||||
|
||||
/* last message in this dump */
|
||||
/* last message fitting into this dump */
|
||||
next_seq = log_next_seq;
|
||||
|
||||
len = 0;
|
||||
@@ -974,6 +980,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
||||
{
|
||||
bool clear = false;
|
||||
static int saved_console_loglevel = -1;
|
||||
static DEFINE_MUTEX(syslog_mutex);
|
||||
int error;
|
||||
|
||||
error = check_syslog_permissions(type, from_file);
|
||||
@@ -1000,11 +1007,17 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
error = wait_event_interruptible(log_wait,
|
||||
syslog_seq != log_next_seq);
|
||||
error = mutex_lock_interruptible(&syslog_mutex);
|
||||
if (error)
|
||||
goto out;
|
||||
error = wait_event_interruptible(log_wait,
|
||||
syslog_seq != log_next_seq);
|
||||
if (error) {
|
||||
mutex_unlock(&syslog_mutex);
|
||||
goto out;
|
||||
}
|
||||
error = syslog_print(buf, len);
|
||||
mutex_unlock(&syslog_mutex);
|
||||
break;
|
||||
/* Read/clear last kernel messages */
|
||||
case SYSLOG_ACTION_READ_CLEAR:
|
||||
@@ -2300,48 +2313,210 @@ 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
|
||||
*
|
||||
* Iterate through each of the dump devices and call the oops/panic
|
||||
* callbacks with the log buffer.
|
||||
* 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)
|
||||
{
|
||||
u64 idx;
|
||||
struct kmsg_dumper *dumper;
|
||||
const char *s1, *s2;
|
||||
unsigned long l1, l2;
|
||||
unsigned long flags;
|
||||
|
||||
if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
|
||||
return;
|
||||
|
||||
/* Theoretically, the log could move on after we do this, but
|
||||
there's not a lot we can do about that. The new messages
|
||||
will overwrite the start of what we dump. */
|
||||
|
||||
raw_spin_lock_irqsave(&logbuf_lock, flags);
|
||||
if (syslog_seq < log_first_seq)
|
||||
idx = syslog_idx;
|
||||
else
|
||||
idx = log_first_idx;
|
||||
|
||||
if (idx > log_next_idx) {
|
||||
s1 = log_buf;
|
||||
l1 = log_next_idx;
|
||||
|
||||
s2 = log_buf + idx;
|
||||
l2 = log_buf_len - idx;
|
||||
} else {
|
||||
s1 = "";
|
||||
l1 = 0;
|
||||
|
||||
s2 = log_buf + idx;
|
||||
l2 = log_next_idx - idx;
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(dumper, &dump_list, list)
|
||||
dumper->dump(dumper, reason, s1, l1, s2, l2);
|
||||
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(&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;
|
||||
raw_spin_unlock_irqrestore(&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 - 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;
|
||||
struct log *msg;
|
||||
size_t l = 0;
|
||||
bool ret = false;
|
||||
|
||||
if (!dumper->active)
|
||||
goto out;
|
||||
|
||||
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, syslog,
|
||||
line, size);
|
||||
|
||||
dumper->cur_idx = log_next(dumper->cur_idx);
|
||||
dumper->cur_seq++;
|
||||
ret = true;
|
||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||
out:
|
||||
if (len)
|
||||
*len = l;
|
||||
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
|
||||
* @line: 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;
|
||||
size_t l = 0;
|
||||
bool ret = false;
|
||||
|
||||
if (!dumper->active)
|
||||
goto out;
|
||||
|
||||
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 >= dumper->next_seq) {
|
||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* calculate length of entire buffer */
|
||||
seq = dumper->cur_seq;
|
||||
idx = dumper->cur_idx;
|
||||
while (seq < dumper->next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
|
||||
l += msg_print_text(msg, true, NULL, 0);
|
||||
idx = log_next(idx);
|
||||
seq++;
|
||||
}
|
||||
|
||||
/* move first record forward until length fits into the buffer */
|
||||
seq = dumper->cur_seq;
|
||||
idx = dumper->cur_idx;
|
||||
while (l > size && seq < dumper->next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
|
||||
l -= msg_print_text(msg, true, NULL, 0);
|
||||
idx = log_next(idx);
|
||||
seq++;
|
||||
}
|
||||
|
||||
/* last message in next interation */
|
||||
next_seq = seq;
|
||||
next_idx = idx;
|
||||
|
||||
l = 0;
|
||||
while (seq < dumper->next_seq) {
|
||||
struct log *msg = log_from_idx(idx);
|
||||
|
||||
l += msg_print_text(msg, syslog,
|
||||
buf + l, size - l);
|
||||
|
||||
idx = log_next(idx);
|
||||
seq++;
|
||||
}
|
||||
|
||||
dumper->next_seq = next_seq;
|
||||
dumper->next_idx = next_idx;
|
||||
ret = true;
|
||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||
out:
|
||||
if (len)
|
||||
*len = l;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
|
||||
|
||||
/**
|
||||
* 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(&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;
|
||||
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user