Эх сурвалжийг харах

lp: cdev lock_kernel() pushdown

Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Jonathan Corbet 17 жил өмнө
parent
commit
abedd296e9
1 өөрчлөгдсөн 26 нэмэгдсэн , 12 устгасан
  1. 26 12
      drivers/char/lp.c

+ 26 - 12
drivers/char/lp.c

@@ -126,6 +126,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
 #include <linux/jiffies.h>
 #include <linux/jiffies.h>
+#include <linux/smp_lock.h>
 
 
 #include <linux/parport.h>
 #include <linux/parport.h>
 #undef LP_STATS
 #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)
 static int lp_open(struct inode * inode, struct file * file)
 {
 {
 	unsigned int minor = iminor(inode);
 	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,
 	/* 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
 	   we may still want to open it to perform ioctl()s.  Therefore we
 	   have commandeered O_NONBLOCK, even though it is being used in
 	   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) {
 		if (status & LP_POUTPA) {
 			printk(KERN_INFO "lp%d out of paper\n", minor);
 			printk(KERN_INFO "lp%d out of paper\n", minor);
 			LP_F(minor) &= ~LP_BUSY;
 			LP_F(minor) &= ~LP_BUSY;
-			return -ENOSPC;
+			ret = -ENOSPC;
+			goto out;
 		} else if (!(status & LP_PSELECD)) {
 		} else if (!(status & LP_PSELECD)) {
 			printk(KERN_INFO "lp%d off-line\n", minor);
 			printk(KERN_INFO "lp%d off-line\n", minor);
 			LP_F(minor) &= ~LP_BUSY;
 			LP_F(minor) &= ~LP_BUSY;
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		} else if (!(status & LP_PERRORP)) {
 		} else if (!(status & LP_PERRORP)) {
 			printk(KERN_ERR "lp%d printer error\n", minor);
 			printk(KERN_ERR "lp%d printer error\n", minor);
 			LP_F(minor) &= ~LP_BUSY;
 			LP_F(minor) &= ~LP_BUSY;
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 		}
 	}
 	}
 	lp_table[minor].lp_buffer = kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
 	lp_table[minor].lp_buffer = kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
 	if (!lp_table[minor].lp_buffer) {
 	if (!lp_table[minor].lp_buffer) {
 		LP_F(minor) &= ~LP_BUSY;
 		LP_F(minor) &= ~LP_BUSY;
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out;
 	}
 	}
 	/* Determine if the peripheral supports ECP mode */
 	/* Determine if the peripheral supports ECP mode */
 	lp_claim_parport_or_block (&lp_table[minor]);
 	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);
 	parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
 	lp_release_parport (&lp_table[minor]);
 	lp_release_parport (&lp_table[minor]);
 	lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
 	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)
 static int lp_release(struct inode * inode, struct file * file)