diff options
author | Kay Sievers <kay@vrfy.org> | 2012-07-09 13:05:10 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-09 13:05:10 -0400 |
commit | eb02dac93708f581c99858a19162af8ca2b6bfcb (patch) | |
tree | 2e749f4599eff44107ecedea84eacd51a859a6a5 /kernel | |
parent | 68b6507dc554ba015b5ed5e13b1ed4993cdf4024 (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.c | 28 |
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 */ |
218 | static u64 syslog_seq; | 218 | static u64 syslog_seq; |
219 | static u32 syslog_idx; | 219 | static u32 syslog_idx; |
220 | static 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 */ |
222 | static u64 log_first_seq; | 223 | static 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; |