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.

Acked-by: Kay Sievers <kay@vrfy.org>
Signed-off-by: liu chuansheng <chuansheng.liu@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
liu chuansheng 2012-07-06 09:50:08 -07:00 committed by Greg Kroah-Hartman
parent 6887a4131d
commit 5c53d819c7
1 changed files with 12 additions and 12 deletions

View File

@ -430,20 +430,20 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
ret = mutex_lock_interruptible(&user->lock); ret = mutex_lock_interruptible(&user->lock);
if (ret) if (ret)
return ret; return ret;
raw_spin_lock(&logbuf_lock); raw_spin_lock_irq(&logbuf_lock);
while (user->seq == log_next_seq) { while (user->seq == log_next_seq) {
if (file->f_flags & O_NONBLOCK) { if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN; ret = -EAGAIN;
raw_spin_unlock(&logbuf_lock); raw_spin_unlock_irq(&logbuf_lock);
goto out; goto out;
} }
raw_spin_unlock(&logbuf_lock); raw_spin_unlock_irq(&logbuf_lock);
ret = wait_event_interruptible(log_wait, ret = wait_event_interruptible(log_wait,
user->seq != log_next_seq); user->seq != log_next_seq);
if (ret) if (ret)
goto out; goto out;
raw_spin_lock(&logbuf_lock); raw_spin_lock_irq(&logbuf_lock);
} }
if (user->seq < log_first_seq) { 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->idx = log_first_idx;
user->seq = log_first_seq; user->seq = log_first_seq;
ret = -EPIPE; ret = -EPIPE;
raw_spin_unlock(&logbuf_lock); raw_spin_unlock_irq(&logbuf_lock);
goto out; goto out;
} }
@ -501,7 +501,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
user->idx = log_next(user->idx); user->idx = log_next(user->idx);
user->seq++; user->seq++;
raw_spin_unlock(&logbuf_lock); raw_spin_unlock_irq(&logbuf_lock);
if (len > count) { if (len > count) {
ret = -EINVAL; ret = -EINVAL;
@ -528,7 +528,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
if (offset) if (offset)
return -ESPIPE; return -ESPIPE;
raw_spin_lock(&logbuf_lock); raw_spin_lock_irq(&logbuf_lock);
switch (whence) { switch (whence) {
case SEEK_SET: case SEEK_SET:
/* the first record */ /* the first record */
@ -552,7 +552,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
raw_spin_unlock(&logbuf_lock); raw_spin_unlock_irq(&logbuf_lock);
return ret; return ret;
} }
@ -566,14 +566,14 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
poll_wait(file, &log_wait, wait); poll_wait(file, &log_wait, wait);
raw_spin_lock(&logbuf_lock); raw_spin_lock_irq(&logbuf_lock);
if (user->seq < log_next_seq) { if (user->seq < log_next_seq) {
/* return error when data has vanished underneath us */ /* return error when data has vanished underneath us */
if (user->seq < log_first_seq) if (user->seq < log_first_seq)
ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI; ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
ret = POLLIN|POLLRDNORM; ret = POLLIN|POLLRDNORM;
} }
raw_spin_unlock(&logbuf_lock); raw_spin_unlock_irq(&logbuf_lock);
return ret; return ret;
} }
@ -597,10 +597,10 @@ static int devkmsg_open(struct inode *inode, struct file *file)
mutex_init(&user->lock); mutex_init(&user->lock);
raw_spin_lock(&logbuf_lock); raw_spin_lock_irq(&logbuf_lock);
user->idx = log_first_idx; user->idx = log_first_idx;
user->seq = log_first_seq; user->seq = log_first_seq;
raw_spin_unlock(&logbuf_lock); raw_spin_unlock_irq(&logbuf_lock);
file->private_data = user; file->private_data = user;
return 0; return 0;