syslog: fill buffer with more than a single message for SYSLOG_ACTION_READ
The recent changes to the printk buffer management resulted in SYSLOG_ACTION_READ to only return a single message, whereas previously the buffer would get filled as much as possible. As, when too small to fit everything, filling it to the last byte would be pretty ugly with the new code, the patch arranges for as many messages as possible to get returned in a single invocation. User space tools in at least all SLES versions depend on the old behavior. This at once addresses the issue attempted to get fixed with commitb56a39ac26
("printk: return -EINVAL if the message len is bigger than the buf size"), and since that commit widened the possibility for losing a message altogether, the patch here assumes that this other commit would get reverted first (otherwise the patch here won't apply). Furthermore, this patch also addresses the problem dealt with in commit4a77a5a06e
("printk: use mutex lock to stop syslog_seq from going wild"), so I'd recommend reverting that one too (albeit there's no direct collision between the two). Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Kay Sievers <kay@vrfy.org> Cc: Yuanhan Liu <yuanhan.liu@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
6fda135c90
Коммит
116e90b23f
|
@ -862,26 +862,49 @@ static int syslog_print(char __user *buf, int size)
|
|||
{
|
||||
char *text;
|
||||
struct log *msg;
|
||||
int len;
|
||||
int len = 0;
|
||||
|
||||
text = kmalloc(LOG_LINE_MAX, GFP_KERNEL);
|
||||
if (!text)
|
||||
return -ENOMEM;
|
||||
|
||||
raw_spin_lock_irq(&logbuf_lock);
|
||||
if (syslog_seq < log_first_seq) {
|
||||
/* messages are gone, move to first one */
|
||||
syslog_seq = log_first_seq;
|
||||
syslog_idx = log_first_idx;
|
||||
}
|
||||
msg = log_from_idx(syslog_idx);
|
||||
len = msg_print_text(msg, true, text, LOG_LINE_MAX);
|
||||
syslog_idx = log_next(syslog_idx);
|
||||
syslog_seq++;
|
||||
raw_spin_unlock_irq(&logbuf_lock);
|
||||
while (size > 0) {
|
||||
size_t n;
|
||||
|
||||
if (len > 0 && copy_to_user(buf, text, len))
|
||||
len = -EFAULT;
|
||||
raw_spin_lock_irq(&logbuf_lock);
|
||||
if (syslog_seq < log_first_seq) {
|
||||
/* messages are gone, move to first one */
|
||||
syslog_seq = log_first_seq;
|
||||
syslog_idx = log_first_idx;
|
||||
}
|
||||
if (syslog_seq == log_next_seq) {
|
||||
raw_spin_unlock_irq(&logbuf_lock);
|
||||
break;
|
||||
}
|
||||
msg = log_from_idx(syslog_idx);
|
||||
n = msg_print_text(msg, true, text, LOG_LINE_MAX);
|
||||
if (n <= size) {
|
||||
syslog_idx = log_next(syslog_idx);
|
||||
syslog_seq++;
|
||||
} else
|
||||
n = 0;
|
||||
raw_spin_unlock_irq(&logbuf_lock);
|
||||
|
||||
if (!n)
|
||||
break;
|
||||
|
||||
len += n;
|
||||
size -= n;
|
||||
buf += n;
|
||||
n = copy_to_user(buf - n, text, n);
|
||||
|
||||
if (n) {
|
||||
len -= n;
|
||||
if (!len)
|
||||
len = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(text);
|
||||
return len;
|
||||
|
|
Загрузка…
Ссылка в новой задаче