aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorKay Sievers <kay@vrfy.org>2012-07-09 13:05:10 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-09 13:05:10 -0400
commiteb02dac93708f581c99858a19162af8ca2b6bfcb (patch)
tree2e749f4599eff44107ecedea84eacd51a859a6a5 /kernel
parent68b6507dc554ba015b5ed5e13b1ed4993cdf4024 (diff)
kmsg: /proc/kmsg - support reading of partial log records
Restore support for partial reads of any size on /proc/kmsg, in case the supplied read buffer is smaller than the record size. Some people seem to think is is ia good idea to run: $ dd if=/proc/kmsg bs=1 of=... as a klog bridge. Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=44211 Reported-by: Jukka Ollila <jiiksteri@gmail.com> Signed-off-by: Kay Sievers <kay@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/printk.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/kernel/printk.c b/kernel/printk.c
index f02f1f5ddc30..50c33411442d 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -217,6 +217,7 @@ static DEFINE_RAW_SPINLOCK(logbuf_lock);
217/* the next printk record to read by syslog(READ) or /proc/kmsg */ 217/* the next printk record to read by syslog(READ) or /proc/kmsg */
218static u64 syslog_seq; 218static u64 syslog_seq;
219static u32 syslog_idx; 219static u32 syslog_idx;
220static size_t syslog_partial;
220 221
221/* index and sequence number of the first record stored in the buffer */ 222/* index and sequence number of the first record stored in the buffer */
222static u64 log_first_seq; 223static u64 log_first_seq;
@@ -890,22 +891,33 @@ static int syslog_print(char __user *buf, int size)
890 891
891 while (size > 0) { 892 while (size > 0) {
892 size_t n; 893 size_t n;
894 size_t skip;
893 895
894 raw_spin_lock_irq(&logbuf_lock); 896 raw_spin_lock_irq(&logbuf_lock);
895 if (syslog_seq < log_first_seq) { 897 if (syslog_seq < log_first_seq) {
896 /* messages are gone, move to first one */ 898 /* messages are gone, move to first one */
897 syslog_seq = log_first_seq; 899 syslog_seq = log_first_seq;
898 syslog_idx = log_first_idx; 900 syslog_idx = log_first_idx;
901 syslog_partial = 0;
899 } 902 }
900 if (syslog_seq == log_next_seq) { 903 if (syslog_seq == log_next_seq) {
901 raw_spin_unlock_irq(&logbuf_lock); 904 raw_spin_unlock_irq(&logbuf_lock);
902 break; 905 break;
903 } 906 }
907
908 skip = syslog_partial;
904 msg = log_from_idx(syslog_idx); 909 msg = log_from_idx(syslog_idx);
905 n = msg_print_text(msg, true, text, LOG_LINE_MAX); 910 n = msg_print_text(msg, true, text, LOG_LINE_MAX);
906 if (n <= size) { 911 if (n - syslog_partial <= size) {
912 /* message fits into buffer, move forward */
907 syslog_idx = log_next(syslog_idx); 913 syslog_idx = log_next(syslog_idx);
908 syslog_seq++; 914 syslog_seq++;
915 n -= syslog_partial;
916 syslog_partial = 0;
917 } else if (!len){
918 /* partial read(), remember position */
919 n = size;
920 syslog_partial += n;
909 } else 921 } else
910 n = 0; 922 n = 0;
911 raw_spin_unlock_irq(&logbuf_lock); 923 raw_spin_unlock_irq(&logbuf_lock);
@@ -913,17 +925,15 @@ static int syslog_print(char __user *buf, int size)
913 if (!n) 925 if (!n)
914 break; 926 break;
915 927
916 len += n; 928 if (copy_to_user(buf, text + skip, n)) {
917 size -= n;
918 buf += n;
919 n = copy_to_user(buf - n, text, n);
920
921 if (n) {
922 len -= n;
923 if (!len) 929 if (!len)
924 len = -EFAULT; 930 len = -EFAULT;
925 break; 931 break;
926 } 932 }
933
934 len += n;
935 size -= n;
936 buf += n;
927 } 937 }
928 938
929 kfree(text); 939 kfree(text);
@@ -1107,6 +1117,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
1107 /* messages are gone, move to first one */ 1117 /* messages are gone, move to first one */
1108 syslog_seq = log_first_seq; 1118 syslog_seq = log_first_seq;
1109 syslog_idx = log_first_idx; 1119 syslog_idx = log_first_idx;
1120 syslog_partial = 0;
1110 } 1121 }
1111 if (from_file) { 1122 if (from_file) {
1112 /* 1123 /*
@@ -1129,6 +1140,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
1129 idx = log_next(idx); 1140 idx = log_next(idx);
1130 seq++; 1141 seq++;
1131 } 1142 }
1143 error -= syslog_partial;
1132 } 1144 }
1133 raw_spin_unlock_irq(&logbuf_lock); 1145 raw_spin_unlock_irq(&logbuf_lock);
1134 break; 1146 break;