Received: by 2002:ac0:946b:0:0:0:0:0 with SMTP id j40csp3911928imj; Tue, 12 Feb 2019 06:49:08 -0800 (PST) X-Google-Smtp-Source: AHgI3IY6H5kPmr8qOf3dEzTZWXnjLEvUa29vPzIS/JMUaSnlwUK0NT/D4FuzDPcvIJ+WoWec0uKF X-Received: by 2002:a62:4886:: with SMTP id q6mr4467181pfi.182.1549982948680; Tue, 12 Feb 2019 06:49:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1549982948; cv=none; d=google.com; s=arc-20160816; b=lhXunQlZyte0HBjfhvG1kOOFL1gs1EtTXuVmNwhyB+0J8KxmfvSkid90qkfoOC5CqW S5qvp2nhDXsJfWbukEEd1ZmuEk5W7RZq6GKlSRTjzODVhp6rQaCZZ4PpaFaDORxT+e2J UFUpDLriqp5PhAQrSLQxwAa2h/ZvSaazauzkpxeHAi3DGQclGFnogeQkh3Klq5zCZ1P5 iIIbv9VA+/Tv7TXqLpDPBLAIWgcH9MRTmot0FJo8tLiUKK4jjlZyVmEB+wunzzaIQ2Rv ZvstR18/2/45Ufxtxsj/3GFbz+k5UJkESMn/slaCuF1LViHdUTLPoXxuk1IGXeb+h5DW OGWg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=rHTlVD1wgdLS2wwyoOgmKyiiHkUiMoDwxuySwjHeqvU=; b=iveRkPm+LsoZ9lSaSFI9O+SSHCwgmSsMqZLOyyFECkC2BBEp0pnrcMA4tUTTgDfzWY BZR0Ap2hQdwv2SAD7/GkVuPY0vS4Jm6uk2HXyNG6HxK2yq2xC+b4KmioS8Zwk8RDBy3c H1yL4F3mL28192evOiy5et7Pzebh45PkAEBgGsMMoIhgQB7ZEfaWnLA7AqTPzNI8uZdD OtqJEcutLsUxs8nPGVJZm+B1/rpGibjjV6VR9v1sShi+sQN5hdspCTZFAGUSsiPr44rk cLAtp6/HrDdloLDm3d1B50fp+wMslJmP4U3ifZ416shQpJsoY+JtXSuBfxhVg8CyJbYb fR1g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z10si4163482pgr.379.2019.02.12.06.48.50; Tue, 12 Feb 2019 06:49:08 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730473AbfBLObe (ORCPT + 99 others); Tue, 12 Feb 2019 09:31:34 -0500 Received: from Galois.linutronix.de ([146.0.238.70]:43818 "EHLO Galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730342AbfBLOam (ORCPT ); Tue, 12 Feb 2019 09:30:42 -0500 Received: from [5.158.153.53] (helo=linux.lab.linutronix.de.) by Galois.linutronix.de with esmtpsa (TLS1.2:DHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.80) (envelope-from ) id 1gtZ4u-0005Af-6v; Tue, 12 Feb 2019 15:30:28 +0100 From: John Ogness To: linux-kernel@vger.kernel.org Cc: Peter Zijlstra , Petr Mladek , Sergey Senozhatsky , Steven Rostedt , Daniel Wang , Andrew Morton , Linus Torvalds , Greg Kroah-Hartman , Alan Cox , Jiri Slaby , Peter Feiner , linux-serial@vger.kernel.org, Sergey Senozhatsky Subject: [RFC PATCH v1 22/25] printk: implement /dev/kmsg Date: Tue, 12 Feb 2019 15:30:00 +0100 Message-Id: <20190212143003.48446-23-john.ogness@linutronix.de> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190212143003.48446-1-john.ogness@linutronix.de> References: <20190212143003.48446-1-john.ogness@linutronix.de> X-Linutronix-Spam-Score: -1.0 X-Linutronix-Spam-Level: - X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required, ALL_TRUSTED=-1,SHORTCIRCUIT=-0.0001 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Since printk messages are now logged to a new ring buffer, update the /dev/kmsg functions to pull the messages from there. Signed-off-by: John Ogness --- fs/proc/kmsg.c | 4 +- include/linux/printk.h | 1 + kernel/printk/printk.c | 162 +++++++++++++++++++++++++++++++++---------------- 3 files changed, 113 insertions(+), 54 deletions(-) diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index 4f4a2abb225e..4e62963a87ca 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c @@ -18,8 +18,6 @@ #include #include -extern wait_queue_head_t log_wait; - static int kmsg_open(struct inode * inode, struct file * file) { return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_PROC); @@ -42,7 +40,7 @@ static ssize_t kmsg_read(struct file *file, char __user *buf, static __poll_t kmsg_poll(struct file *file, poll_table *wait) { - poll_wait(file, &log_wait, wait); + poll_wait(file, printk_wait_queue(), wait); if (do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_PROC)) return EPOLLIN | EPOLLRDNORM; return 0; diff --git a/include/linux/printk.h b/include/linux/printk.h index 58bd06d88ea3..bef0b5c5fcbf 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -191,6 +191,7 @@ __printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...); void dump_stack_print_info(const char *log_lvl); void show_regs_print_info(const char *log_lvl); extern asmlinkage void dump_stack(void) __cold; +struct wait_queue_head *printk_wait_queue(void); #else static inline __printf(1, 0) int vprintk(const char *s, va_list args) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 306e7575499c..ed1ec8c23e97 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -637,10 +637,11 @@ static ssize_t msg_print_ext_body(char *buf, size_t size, /* /dev/kmsg - userspace message inject/listen interface */ struct devkmsg_user { u64 seq; - u32 idx; + struct prb_iterator iter; struct ratelimit_state rs; struct mutex lock; char buf[CONSOLE_EXT_LOG_MAX]; + char msgbuf[PRINTK_RECORD_MAX]; }; static __printf(3, 4) __cold @@ -723,9 +724,11 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct devkmsg_user *user = file->private_data; + struct prb_iterator backup_iter; struct printk_log *msg; - size_t len; ssize_t ret; + size_t len; + u64 seq; if (!user) return -EBADF; @@ -734,52 +737,67 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, if (ret) return ret; - logbuf_lock_irq(); - while (user->seq == log_next_seq) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - logbuf_unlock_irq(); - goto out; - } + /* make a backup copy in case there is a problem */ + prb_iter_copy(&backup_iter, &user->iter); - logbuf_unlock_irq(); - ret = wait_event_interruptible(log_wait, - user->seq != log_next_seq); - if (ret) - goto out; - logbuf_lock_irq(); + if (file->f_flags & O_NONBLOCK) { + ret = prb_iter_next(&user->iter, &user->msgbuf[0], + sizeof(user->msgbuf), &seq); + } else { + ret = prb_iter_wait_next(&user->iter, &user->msgbuf[0], + sizeof(user->msgbuf), &seq); } - - if (user->seq < log_first_seq) { - /* our last seen message is gone, return error and reset */ - user->idx = log_first_idx; - user->seq = log_first_seq; + if (ret == 0) { + /* end of list */ + ret = -EAGAIN; + goto out; + } else if (ret == -EINVAL) { + /* iterator invalid, return error and reset */ ret = -EPIPE; - logbuf_unlock_irq(); + prb_iter_init(&user->iter, &printk_rb, &user->seq); + goto out; + } else if (ret < 0) { + /* interrupted by signal */ goto out; } - msg = log_from_idx(user->idx); + if (user->seq == 0) { + user->seq = seq; + } else { + user->seq++; + if (user->seq < seq) { + ret = -EPIPE; + goto restore_out; + } + } + + msg = (struct printk_log *)&user->msgbuf[0]; len = msg_print_ext_header(user->buf, sizeof(user->buf), msg, user->seq); len += msg_print_ext_body(user->buf + len, sizeof(user->buf) - len, log_dict(msg), msg->dict_len, log_text(msg), msg->text_len); - user->idx = log_next(user->idx); - user->seq++; - logbuf_unlock_irq(); - if (len > count) { ret = -EINVAL; - goto out; + goto restore_out; } if (copy_to_user(buf, user->buf, len)) { ret = -EFAULT; - goto out; + goto restore_out; } + ret = len; + goto out; +restore_out: + /* + * There was an error, but this message should not be + * lost because of it. Restore the backup and setup + * seq so that it will work with the next read. + */ + prb_iter_copy(&user->iter, &backup_iter); + user->seq = seq - 1; out: mutex_unlock(&user->lock); return ret; @@ -788,19 +806,21 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf, static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) { struct devkmsg_user *user = file->private_data; - loff_t ret = 0; + loff_t ret; if (!user) return -EBADF; if (offset) return -ESPIPE; - logbuf_lock_irq(); + ret = mutex_lock_interruptible(&user->lock); + if (ret) + return ret; + switch (whence) { case SEEK_SET: /* the first record */ - user->idx = log_first_idx; - user->seq = log_first_seq; + prb_iter_init(&user->iter, &printk_rb, &user->seq); break; case SEEK_DATA: /* @@ -808,40 +828,83 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) * like issued by 'dmesg -c'. Reading /dev/kmsg itself * changes no global state, and does not clear anything. */ - user->idx = clear_idx; - user->seq = clear_seq; + for (;;) { + prb_iter_init(&user->iter, &printk_rb, NULL); + ret = prb_iter_seek(&user->iter, clear_seq); + if (ret > 0) { + /* seeked to clear seq */ + user->seq = clear_seq; + break; + } else if (ret == 0) { + /* + * The end of the list was hit without + * ever seeing the clear seq. Just + * seek to the beginning of the list. + */ + prb_iter_init(&user->iter, &printk_rb, + &user->seq); + break; + } + /* iterator invalid, start over */ + } + ret = 0; break; case SEEK_END: /* after the last record */ - user->idx = log_next_idx; - user->seq = log_next_seq; + for (;;) { + ret = prb_iter_next(&user->iter, NULL, 0, &user->seq); + if (ret == 0) + break; + else if (ret > 0) + continue; + /* iterator invalid, start over */ + prb_iter_init(&user->iter, &printk_rb, &user->seq); + } + ret = 0; break; default: ret = -EINVAL; } - logbuf_unlock_irq(); + + mutex_unlock(&user->lock); return ret; } +struct wait_queue_head *printk_wait_queue(void) +{ + /* FIXME: using prb internals! */ + return printk_rb.wq; +} + static __poll_t devkmsg_poll(struct file *file, poll_table *wait) { struct devkmsg_user *user = file->private_data; + struct prb_iterator iter; __poll_t ret = 0; + int rbret; + u64 seq; if (!user) return EPOLLERR|EPOLLNVAL; - poll_wait(file, &log_wait, wait); + poll_wait(file, printk_wait_queue(), wait); - logbuf_lock_irq(); - if (user->seq < log_next_seq) { - /* return error when data has vanished underneath us */ - if (user->seq < log_first_seq) - ret = EPOLLIN|EPOLLRDNORM|EPOLLERR|EPOLLPRI; - else - ret = EPOLLIN|EPOLLRDNORM; - } - logbuf_unlock_irq(); + mutex_lock(&user->lock); + + /* use copy so no actual iteration takes place */ + prb_iter_copy(&iter, &user->iter); + + rbret = prb_iter_next(&iter, &user->msgbuf[0], + sizeof(user->msgbuf), &seq); + if (rbret == 0) + goto out; + + ret = EPOLLIN|EPOLLRDNORM; + + if (rbret < 0 || (seq - user->seq) != 1) + ret |= EPOLLERR|EPOLLPRI; +out: + mutex_unlock(&user->lock); return ret; } @@ -871,10 +934,7 @@ static int devkmsg_open(struct inode *inode, struct file *file) mutex_init(&user->lock); - logbuf_lock_irq(); - user->idx = log_first_idx; - user->seq = log_first_seq; - logbuf_unlock_irq(); + prb_iter_init(&user->iter, &printk_rb, &user->seq); file->private_data = user; return 0; -- 2.11.0