diff options
author | Jonathan Corbet <corbet@lwn.net> | 2008-05-15 21:29:38 +0400 |
---|---|---|
committer | Jonathan Corbet <corbet@lwn.net> | 2008-06-21 00:05:48 +0400 |
commit | abedd296e97a5d943e76999de97253f1b62a4846 (patch) | |
tree | 01c24863beedaf1546845cc74f8cf65f856b7c2e /drivers/char | |
parent | 12ead6b098b65dd21d3ed4fcccf20025dbe86cc2 (diff) | |
download | linux-abedd296e97a5d943e76999de97253f1b62a4846.tar.xz |
lp: cdev lock_kernel() pushdown
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/lp.c | 38 |
1 files changed, 26 insertions, 12 deletions
diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 60ac642752be..71abb4c33aa2 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -126,6 +126,7 @@ #include <linux/device.h> #include <linux/wait.h> #include <linux/jiffies.h> +#include <linux/smp_lock.h> #include <linux/parport.h> #undef LP_STATS @@ -489,14 +490,21 @@ static ssize_t lp_read(struct file * file, char __user * buf, static int lp_open(struct inode * inode, struct file * file) { unsigned int minor = iminor(inode); + int ret = 0; - if (minor >= LP_NO) - return -ENXIO; - if ((LP_F(minor) & LP_EXIST) == 0) - return -ENXIO; - if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor))) - return -EBUSY; - + lock_kernel(); + if (minor >= LP_NO) { + ret = -ENXIO; + goto out; + } + if ((LP_F(minor) & LP_EXIST) == 0) { + ret = -ENXIO; + goto out; + } + if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor))) { + ret = -EBUSY; + goto out; + } /* If ABORTOPEN is set and the printer is offline or out of paper, we may still want to open it to perform ioctl()s. Therefore we have commandeered O_NONBLOCK, even though it is being used in @@ -510,21 +518,25 @@ static int lp_open(struct inode * inode, struct file * file) if (status & LP_POUTPA) { printk(KERN_INFO "lp%d out of paper\n", minor); LP_F(minor) &= ~LP_BUSY; - return -ENOSPC; + ret = -ENOSPC; + goto out; } else if (!(status & LP_PSELECD)) { printk(KERN_INFO "lp%d off-line\n", minor); LP_F(minor) &= ~LP_BUSY; - return -EIO; + ret = -EIO; + goto out; } else if (!(status & LP_PERRORP)) { printk(KERN_ERR "lp%d printer error\n", minor); LP_F(minor) &= ~LP_BUSY; - return -EIO; + ret = -EIO; + goto out; } } lp_table[minor].lp_buffer = kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); if (!lp_table[minor].lp_buffer) { LP_F(minor) &= ~LP_BUSY; - return -ENOMEM; + ret = -ENOMEM; + goto out; } /* Determine if the peripheral supports ECP mode */ lp_claim_parport_or_block (&lp_table[minor]); @@ -540,7 +552,9 @@ static int lp_open(struct inode * inode, struct file * file) parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT); lp_release_parport (&lp_table[minor]); lp_table[minor].current_mode = IEEE1284_MODE_COMPAT; - return 0; +out: + unlock_kernel(); + return ret; } static int lp_release(struct inode * inode, struct file * file) |