RE: [PATCH] printk: replacing the raw_spin_lock/unlock withraw_spin_lock_irqsave/irqrestore

From: Liu, Chuansheng
Date: Mon Jul 02 2012 - 18:01:19 EST


Thanks your pointing out. New patch as below:

From: liu chuansheng <chuansheng.liu@xxxxxxxxx>
Subject: [PATCH] printk: replacing the raw_spin_lock/unlock with raw_spin_lock/unlock_irq

In function devkmsg_read/writev/llseek/poll/open()..., the function
raw_spin_lock/unlock is used, there is potential deadlock case happening.
CPU1: thread1 doing the cat /dev/kmsg:
raw_spin_lock(&logbuf_lock);
while (user->seq == log_next_seq) {
when thread1 run here, at this time one interrupt is coming on CPU1 and running
based on this thread,if the interrupt handle called the printk which need the
logbuf_lock spin also, it will cause deadlock.

So we should use raw_spin_lock/unlock_irq here.

Signed-off-by: liu chuansheng <chuansheng.liu@xxxxxxxxx>
---
kernel/printk.c | 24 ++++++++++++------------
1 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/kernel/printk.c b/kernel/printk.c
index dba1821..12886cd 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -430,20 +430,20 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
ret = mutex_lock_interruptible(&user->lock);
if (ret)
return ret;
- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
while (user->seq == log_next_seq) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
goto out;
}

- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
ret = wait_event_interruptible(log_wait,
user->seq != log_next_seq);
if (ret)
goto out;
- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
}

if (user->seq < log_first_seq) {
@@ -451,7 +451,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
user->idx = log_first_idx;
user->seq = log_first_seq;
ret = -EPIPE;
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
goto out;
}

@@ -501,7 +501,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,

user->idx = log_next(user->idx);
user->seq++;
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);

if (len > count) {
ret = -EINVAL;
@@ -528,7 +528,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
if (offset)
return -ESPIPE;

- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
switch (whence) {
case SEEK_SET:
/* the first record */
@@ -552,7 +552,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
default:
ret = -EINVAL;
}
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);
return ret;
}

@@ -566,14 +566,14 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)

poll_wait(file, &log_wait, wait);

- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
if (user->seq < log_next_seq) {
/* return error when data has vanished underneath us */
if (user->seq < log_first_seq)
ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
ret = POLLIN|POLLRDNORM;
}
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);

return ret;
}
@@ -597,10 +597,10 @@ static int devkmsg_open(struct inode *inode, struct file *file)

mutex_init(&user->lock);

- raw_spin_lock(&logbuf_lock);
+ raw_spin_lock_irq(&logbuf_lock);
user->idx = log_first_idx;
user->seq = log_first_seq;
- raw_spin_unlock(&logbuf_lock);
+ raw_spin_unlock_irq(&logbuf_lock);

file->private_data = user;
return 0;
--
1.7.0.4


> -----Original Message-----
> From: Kay Sievers [mailto:kay@xxxxxxxx]
> Sent: Tuesday, July 03, 2012 5:01 AM
> To: Liu, Chuansheng
> Cc: 'linux-kernel@xxxxxxxxxxxxxxx' (linux-kernel@xxxxxxxxxxxxxxx);
> a.p.zijlstra@xxxxxxxxx; gregkh@xxxxxxxxxxxxxxxxxxx; mingo@xxxxxxx
> Subject: Re: [PATCH] printk: replacing the raw_spin_lock/unlock with
> raw_spin_lock_irqsave/irqrestore
>
> On Mon, Jul 2, 2012 at 12:36 PM, Liu, Chuansheng <chuansheng.liu@xxxxxxxxx>
> wrote:
> > From: liu chuansheng <chuansheng.liu@xxxxxxxxx>
> > Subject: [PATCH] printk: replacing the raw_spin_lock/unlock with
> > raw_spin_lock_irqsave/irqrestore
> >
> > In function devkmsg_read/writev/llseek/poll/open()..., the function
> > raw_spin_lock/unlock is used, there is potential deadlock case happening.
> > CPU1: thread1 doing the cat /dev/kmsg:
> > raw_spin_lock(&logbuf_lock);
> > while (user->seq == log_next_seq) { when thread1 run here, at
> > this time one interrupt is coming on CPU1 and running based on this
> > thread,if the interrupt handle called the printk which need the
> > logbuf_lock spin also, it will cause deadlock.
> >
> > So we should use raw_spin_lock_irq_save/irqrestore here.
>
> They are all handling a system call, isn't raw_spin_lock_irq() without the flag
> restoration good enough then?
>
> Thanks,
> Kay
N‹§²æìr¸›yúèšØb²X¬¶ÇvØ^–)Þ{.nÇ+‰·¥Š{±‘êçzX§¶›¡Ü}©ž²ÆzÚ&j:+v‰¨¾«‘êçzZ+€Ê+zf£¢·hšˆ§~†­†Ûiÿûàz¹®w¥¢¸?™¨è­Ú&¢)ßf”ù^jÇy§m…á@A«a¶Úÿ 0¶ìh®å’i