aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/printk.c
diff options
context:
space:
mode:
authorJan Beulich <JBeulich@suse.com>2012-06-22 11:36:09 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-26 15:37:36 -0400
commit116e90b23f74d303e8d607c7a7d54f60f14ab9f2 (patch)
treebec5bed13a74539d2741334593cdd7f2fc4241c5 /kernel/printk.c
parent6fda135c908d0f38a0167adcbd71094572e3059b (diff)
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 commit b56a39ac263e5b8cafedd551a49c2105e68b98c2 ("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 commit 4a77a5a06ec66ed05199b301e7c25f42f979afdc ("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>
Diffstat (limited to 'kernel/printk.c')
-rw-r--r--kernel/printk.c51
1 files changed, 37 insertions, 14 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index ff05361962e1..cdfba44fedf0 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -862,26 +862,49 @@ static int syslog_print(char __user *buf, int size)
862{ 862{
863 char *text; 863 char *text;
864 struct log *msg; 864 struct log *msg;
865 int len; 865 int len = 0;
866 866
867 text = kmalloc(LOG_LINE_MAX, GFP_KERNEL); 867 text = kmalloc(LOG_LINE_MAX, GFP_KERNEL);
868 if (!text) 868 if (!text)
869 return -ENOMEM; 869 return -ENOMEM;
870 870
871 raw_spin_lock_irq(&logbuf_lock); 871 while (size > 0) {
872 if (syslog_seq < log_first_seq) { 872 size_t n;
873 /* messages are gone, move to first one */ 873
874 syslog_seq = log_first_seq; 874 raw_spin_lock_irq(&logbuf_lock);
875 syslog_idx = log_first_idx; 875 if (syslog_seq < log_first_seq) {
876 } 876 /* messages are gone, move to first one */
877 msg = log_from_idx(syslog_idx); 877 syslog_seq = log_first_seq;
878 len = msg_print_text(msg, true, text, LOG_LINE_MAX); 878 syslog_idx = log_first_idx;
879 syslog_idx = log_next(syslog_idx); 879 }
880 syslog_seq++; 880 if (syslog_seq == log_next_seq) {
881 raw_spin_unlock_irq(&logbuf_lock); 881 raw_spin_unlock_irq(&logbuf_lock);
882 break;
883 }
884 msg = log_from_idx(syslog_idx);
885 n = msg_print_text(msg, true, text, LOG_LINE_MAX);
886 if (n <= size) {
887 syslog_idx = log_next(syslog_idx);
888 syslog_seq++;
889 } else
890 n = 0;
891 raw_spin_unlock_irq(&logbuf_lock);
892
893 if (!n)
894 break;
882 895
883 if (len > 0 && copy_to_user(buf, text, len)) 896 len += n;
884 len = -EFAULT; 897 size -= n;
898 buf += n;
899 n = copy_to_user(buf - n, text, n);
900
901 if (n) {
902 len -= n;
903 if (!len)
904 len = -EFAULT;
905 break;
906 }
907 }
885 908
886 kfree(text); 909 kfree(text);
887 return len; 910 return len;