Skip to content

Commit

Permalink
printk: replacing the raw_spin_lock/unlock with raw_spin_lock/unlock_irq
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
liu chuansheng authored and Greg Kroah-Hartman committed Jul 6, 2012
1 parent 6887a41 commit 5c53d81
Showing 1 changed file with 12 additions and 12 deletions.
24 changes: 12 additions & 12 deletions kernel/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,28 +430,28 @@ 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) {
/* our last seen message is gone, return error and reset */
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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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 */
Expand All @@ -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;
}

Expand All @@ -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;
}
Expand All @@ -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;
Expand Down

0 comments on commit 5c53d81

Please sign in to comment.