[Devel,RHEL7,COMMIT] ve/printk: fix __vprintk_emit after rebase to RHEL7.3 beta

Submitted by Konstantin Khorenko on Nov. 9, 2016, 2:21 p.m.

Details

Message ID 201611091421.uA9ELc51010520@finist_cl7.x64_64.work.ct
State New
Series "ve/printk: fix __vprintk_emit after rebase to RHEL7.3 beta"
Headers show

Commit Message

Konstantin Khorenko Nov. 9, 2016, 2:21 p.m.
The commit is pushed to "branch-rh7-3.10.0-493.vz7.25.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-493.el7
------>
commit d3c72648bd62dc0c2e002389a1d92179d4ce3d7b
Author: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Date:   Wed Nov 9 18:21:38 2016 +0400

    ve/printk: fix __vprintk_emit after rebase to RHEL7.3 beta
    
    1. In case of ENOMEM from log_state_init do:
      a) reset logbuf_cpu as we are just about to unlock logbuf_lock
      b) unlock logbuf_lock
      c) enable lockdep back
      d) restore irqs
    same as in the end before if (!in_sched) but we don't want to enter
    these if-block with log variable uninitialized, so goto does not fit
    well.
    
    2. Take logbuf_lock and disable interrupts before operating
    with log
    
    3. Also move our log wake up into if (!in_sched) if-block as when
    called from printk_deferred, __vprintk_emit should not call up(),
    that can lead to deadlock on scheduler rq locks.
    
    Those changes are needed after commit 458df9fd4815 ("printk: remove
    separate printk_sched buffers and use printk buf instead")
    
    Note: now we do not use ve_printk from scheduler but in future
    we might need some kind of ve_printk_deferred for it.
    
    https://jira.sw.ru/browse/PSBM-54820
    
    Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
    Reviewed-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
 kernel/printk.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/kernel/printk.c b/kernel/printk.c
index ae835e3..a332be1 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1676,10 +1676,11 @@  static int __vprintk_emit(struct log_state *log,
 
 	err = log_state_init(log);
 	if (err) {
+		logbuf_cpu = UINT_MAX;
 		raw_spin_unlock(&logbuf_lock);
-		printed_len = err;
 		lockdep_on();
-		goto out;
+		local_irq_restore(flags);
+		return err;
 	}
 
 	if (recursion_bug) {
@@ -1789,20 +1790,21 @@  static int __vprintk_emit(struct log_state *log,
 		 * /dev/kmsg and syslog() users.
 		 */
 		if (log != &init_log_state) {
+			raw_spin_lock_irqsave(&logbuf_lock, flags);
 			if (log->seen_seq != log->next_seq && !oops_in_progress) {
 				log->seen_seq = log->next_seq;
 				need_wake = true;
 			}
 			logbuf_cpu = UINT_MAX;
-			raw_spin_unlock(&logbuf_lock);
+			raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 		} else if (console_trylock_for_printk())
 			console_unlock();
 		preempt_enable();
 		lockdep_on();
+
+		if (need_wake)
+			wake_up_interruptible(&log->wait);
 	}
-out:
-	if (need_wake)
-		wake_up_interruptible(&log->wait);
 
 	return printed_len;
 }
@@ -1881,6 +1883,10 @@  asmlinkage int ve_vprintk(int dst, const char *fmt, va_list args)
 	return r;
 }
 
+/*
+ * Do not use it from scheduler code - can lead to deadlocks.
+ */
+
 asmlinkage int ve_printk(int dst, const char *fmt, ...)
 {
 	va_list args;