diff options
author | Kay Sievers <kay@vrfy.org> | 2012-05-02 20:29:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-05-07 20:03:27 -0400 |
commit | e11fea92e13fb91c50bacca799a6131c81929986 (patch) | |
tree | 3b9204f4eccc6b488b843d6d00e65dc982c50160 /drivers/char | |
parent | 7ff9554bb578ba02166071d2d487b7fc7d860d62 (diff) |
kmsg: export printk records to the /dev/kmsg interface
Support for multiple concurrent readers of /dev/kmsg, with read(),
seek(), poll() support. Output of message sequence numbers, to allow
userspace log consumers to reliably reconnect and reconstruct their
state at any given time. After open("/dev/kmsg"), read() always
returns *all* buffered records. If only future messages should be
read, SEEK_END can be used. In case records get overwritten while
/dev/kmsg is held open, or records get faster overwritten than they
are read, the next read() will return -EPIPE and the current reading
position gets updated to the next available record. The passed
sequence numbers allow the log consumer to calculate the amount of
lost messages.
[root@mop ~]# cat /dev/kmsg
5,0,0;Linux version 3.4.0-rc1+ (kay@mop) (gcc version 4.7.0 20120315 ...
6,159,423091;ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-ff])
7,160,424069;pci_root PNP0A03:00: host bridge window [io 0x0000-0x0cf7] (ignored)
SUBSYSTEM=acpi
DEVICE=+acpi:PNP0A03:00
6,339,5140900;NET: Registered protocol family 10
30,340,5690716;udevd[80]: starting version 181
6,341,6081421;FDC 0 is a S82078B
6,345,6154686;microcode: CPU0 sig=0x623, pf=0x0, revision=0x0
7,346,6156968;sr 1:0:0:0: Attached scsi CD-ROM sr0
SUBSYSTEM=scsi
DEVICE=+scsi:1:0:0:0
6,347,6289375;microcode: CPU1 sig=0x623, pf=0x0, revision=0x0
Cc: Karel Zak <kzak@redhat.com>
Tested-by: William Douglas <william.douglas@intel.com>
Signed-off-by: Kay Sievers <kay@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/mem.c | 61 |
1 files changed, 1 insertions, 60 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index cf56614479ef..0e7fbfcbd6e6 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -807,65 +807,6 @@ static const struct file_operations oldmem_fops = { | |||
807 | }; | 807 | }; |
808 | #endif | 808 | #endif |
809 | 809 | ||
810 | static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv, | ||
811 | unsigned long count, loff_t pos) | ||
812 | { | ||
813 | char *buf, *line; | ||
814 | int i; | ||
815 | int level = default_message_loglevel; | ||
816 | int facility = 1; /* LOG_USER */ | ||
817 | size_t len = iov_length(iv, count); | ||
818 | ssize_t ret = len; | ||
819 | |||
820 | if (len > 1024) | ||
821 | return -EINVAL; | ||
822 | buf = kmalloc(len+1, GFP_KERNEL); | ||
823 | if (buf == NULL) | ||
824 | return -ENOMEM; | ||
825 | |||
826 | line = buf; | ||
827 | for (i = 0; i < count; i++) { | ||
828 | if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len)) | ||
829 | goto out; | ||
830 | line += iv[i].iov_len; | ||
831 | } | ||
832 | |||
833 | /* | ||
834 | * Extract and skip the syslog prefix <[0-9]*>. Coming from userspace | ||
835 | * the decimal value represents 32bit, the lower 3 bit are the log | ||
836 | * level, the rest are the log facility. | ||
837 | * | ||
838 | * If no prefix or no userspace facility is specified, we | ||
839 | * enforce LOG_USER, to be able to reliably distinguish | ||
840 | * kernel-generated messages from userspace-injected ones. | ||
841 | */ | ||
842 | line = buf; | ||
843 | if (line[0] == '<') { | ||
844 | char *endp = NULL; | ||
845 | |||
846 | i = simple_strtoul(line+1, &endp, 10); | ||
847 | if (endp && endp[0] == '>') { | ||
848 | level = i & 7; | ||
849 | if (i >> 3) | ||
850 | facility = i >> 3; | ||
851 | endp++; | ||
852 | len -= endp - line; | ||
853 | line = endp; | ||
854 | } | ||
855 | } | ||
856 | line[len] = '\0'; | ||
857 | |||
858 | printk_emit(facility, level, NULL, 0, "%s", line); | ||
859 | out: | ||
860 | kfree(buf); | ||
861 | return ret; | ||
862 | } | ||
863 | |||
864 | static const struct file_operations kmsg_fops = { | ||
865 | .aio_write = kmsg_writev, | ||
866 | .llseek = noop_llseek, | ||
867 | }; | ||
868 | |||
869 | static const struct memdev { | 810 | static const struct memdev { |
870 | const char *name; | 811 | const char *name; |
871 | umode_t mode; | 812 | umode_t mode; |
@@ -884,7 +825,7 @@ static const struct memdev { | |||
884 | [7] = { "full", 0666, &full_fops, NULL }, | 825 | [7] = { "full", 0666, &full_fops, NULL }, |
885 | [8] = { "random", 0666, &random_fops, NULL }, | 826 | [8] = { "random", 0666, &random_fops, NULL }, |
886 | [9] = { "urandom", 0666, &urandom_fops, NULL }, | 827 | [9] = { "urandom", 0666, &urandom_fops, NULL }, |
887 | [11] = { "kmsg", 0, &kmsg_fops, NULL }, | 828 | [11] = { "kmsg", 0644, &kmsg_fops, NULL }, |
888 | #ifdef CONFIG_CRASH_DUMP | 829 | #ifdef CONFIG_CRASH_DUMP |
889 | [12] = { "oldmem", 0, &oldmem_fops, NULL }, | 830 | [12] = { "oldmem", 0, &oldmem_fops, NULL }, |
890 | #endif | 831 | #endif |