Skip to content

Commit e11fea9

Browse files
kaysieversgregkh
authored andcommitted
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 <[email protected]> Tested-by: William Douglas <[email protected]> Signed-off-by: Kay Sievers <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 7ff9554 commit e11fea9

File tree

3 files changed

+316
-60
lines changed

3 files changed

+316
-60
lines changed

drivers/char/mem.c

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -807,65 +807,6 @@ static const struct file_operations oldmem_fops = {
807807
};
808808
#endif
809809

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-
869810
static const struct memdev {
870811
const char *name;
871812
umode_t mode;
@@ -884,7 +825,7 @@ static const struct memdev {
884825
[7] = { "full", 0666, &full_fops, NULL },
885826
[8] = { "random", 0666, &random_fops, NULL },
886827
[9] = { "urandom", 0666, &urandom_fops, NULL },
887-
[11] = { "kmsg", 0, &kmsg_fops, NULL },
828+
[11] = { "kmsg", 0644, &kmsg_fops, NULL },
888829
#ifdef CONFIG_CRASH_DUMP
889830
[12] = { "oldmem", 0, &oldmem_fops, NULL },
890831
#endif

include/linux/printk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ extern void dump_stack(void) __cold;
300300
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
301301
#endif
302302

303+
extern const struct file_operations kmsg_fops;
304+
303305
enum {
304306
DUMP_PREFIX_NONE,
305307
DUMP_PREFIX_ADDRESS,

0 commit comments

Comments
 (0)