patch-2.1.106 linux/drivers/net/ppp.c

Next file: linux/drivers/net/wavelan.c
Previous file: linux/drivers/net/net_init.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.105/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
@@ -8,7 +8,9 @@
  *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
  *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
  *
- *  ==FILEVERSION 980501==
+ *  Machine hang caused by NULLing a live wait queue fix. <Alan.Cox@linux.org>
+ *
+ *  ==FILEVERSION 980608==
  *
  *  NOTE TO MAINTAINERS:
  *     If you modify this file at all, please set the number above to the
@@ -206,6 +208,7 @@
 	CHECK_PPP_MAGIC(ppp); \
 	if (!ppp->inuse) { \
 		printk (ppp_warning, __LINE__); \
+		return; \
 	} \
 } while (0)
 
@@ -415,8 +418,6 @@
 	ppp->ubuf	= NULL;
 	ppp->cbuf	= NULL;
 	ppp->slcomp	= NULL;
-	ppp->read_wait	= NULL;
-	ppp->write_wait = NULL;
 	ppp->last_xmit	= jiffies - flag_time;
 	ppp->last_recv  = jiffies;
 
@@ -1706,7 +1707,6 @@
 {
 	struct ppp *ppp = tty2ppp (tty);
 	__u8 c;
-	int error;
 	ssize_t len, ret;
 
 #define GETC(c)						\
@@ -1720,41 +1720,40 @@
  */
 	if (!ppp)
 		return -EIO;
-
-	/* if (ppp->magic != PPP_MAGIC)
-		return -EIO; */
-
 	CHECK_PPP (-ENXIO);
 
 /*
  * Before we attempt to write the frame to the user, ensure that the
  * user has access to the pages for the total buffer length.
  */
-	error = verify_area (VERIFY_WRITE, buf, nr);
-	if (error != 0)
-		return (error);
+	if (verify_area (VERIFY_WRITE, buf, nr))
+		return -EFAULT;
+
+/*
+ * Increment the module use count so that the module can't get unloaded
+ * while we're sleeping below.  The problem is that ppp_tty_close() can
+ * get called (as a result of a hangup from the tty) while we're sleeping.
+ */
+	MOD_INC_USE_COUNT;
 
 /*
  * Acquire the read lock.
  */
 	for (;;) {
+		ret = 0;
 		ppp = tty2ppp (tty);
 		if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
 		    || tty != ppp->tty)
-			return 0;
+			goto done;
 
 		if (test_and_set_bit (0, &ppp->ubuf->locked) != 0) {
-#if 0
-			if (ppp->flags & SC_DEBUG)
-				printk (KERN_DEBUG
-				     "ppp_tty_read: sleeping(ubuf)\n");
-#endif
 			current->timeout = 0;
 			current->state	 = TASK_INTERRUPTIBLE;
-			schedule ();
+			schedule();
 
+			ret = -EINTR;
 			if (signal_pending(current))
-				return -EINTR;
+				goto done;
 			continue;
 		}
 
@@ -1777,17 +1776,14 @@
  */
 		/* no data */
 		clear_bit (0, &ppp->ubuf->locked);
+		ret = -EAGAIN;
 		if (file->f_flags & O_NONBLOCK)
-			return -EAGAIN;
+			goto done;
 		current->timeout = 0;
-#if 0
-		if (ppp->flags & SC_DEBUG)
-			printk (KERN_DEBUG
-				"ppp_tty_read: sleeping(read_wait)\n");
-#endif
 		interruptible_sleep_on (&ppp->read_wait);
+		ret = -EINTR;
 		if (signal_pending(current))
-			return -EINTR;
+			goto done;
 	}
 
 /*
@@ -1802,7 +1798,7 @@
 				"ppp: read of %lu bytes too small for %ld "
 				"frame\n", (unsigned long) nr, (long) len + 2);
 		ppp->stats.ppp_ierrors++;
-		error = -EOVERFLOW;
+		ret = -EOVERFLOW;
 		goto out;
 	}
 
@@ -1810,35 +1806,32 @@
  * Fake the insertion of the ADDRESS and CONTROL information because these
  * were not saved in the buffer.
  */
-	error = put_user((u_char) PPP_ALLSTATIONS, buf);
-	if (error)
-		goto out;
-	++buf;
-	error = put_user((u_char) PPP_UI, buf);
-	if (error)
+	ret = -EFAULT;
+	if (put_user((u_char) PPP_ALLSTATIONS, buf)
+	    || put_user((u_char) PPP_UI, buf+1))
 		goto out;
-	++buf;
+	buf += 2;
 
 /*
  * Copy the received data from the buffer to the caller's area.
  */
-	ret = len + 2; 	/* Account for ADDRESS and CONTROL bytes */
+	nr = len + 2; 	/* Account for ADDRESS and CONTROL bytes */
 	while (len-- > 0) {
 		GETC (c);
-		error = put_user(c, buf);
-		if (error)
+		if (put_user(c, buf))
 			goto out;
 		++buf;
 	}
-
-	clear_bit (0, &ppp->ubuf->locked);
-	return ret;
+	ret = nr;
 
 out:
-	ppp->ubuf->tail += len;
-	ppp->ubuf->tail &= ppp->ubuf->size;
-	clear_bit (0, &ppp->ubuf->locked);
-	return error;
+	if (len > 0)
+		ppp->ubuf->tail = (ppp->ubuf->tail + len) & ppp->ubuf->size;
+	clear_bit(0, &ppp->ubuf->locked);
+
+done:
+	MOD_DEC_USE_COUNT;
+	return ret;
 #undef GETC
 }
 
@@ -2100,6 +2093,14 @@
 	error = -EFAULT;
 	if (copy_from_user(new_data, data, count))
 		goto out_free;
+
+/*
+ * Increment the module use count so that the module can't get unloaded
+ * while we're sleeping below.  The problem is that ppp_tty_close() can
+ * get called (as a result of a hangup from the tty) while we're sleeping.
+ */
+	MOD_INC_USE_COUNT;
+
 /*
  * Lock this PPP unit so we will be the only writer,
  * sleeping if necessary.
@@ -2131,7 +2132,7 @@
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&ppp->write_wait, &wait);
 	if (error)
-		goto out_free;
+		goto out_free_dec;
 
 /*
  * Change the LQR frame
@@ -2154,6 +2155,8 @@
 	}
 	error = count;
 
+out_free_dec:
+	MOD_DEC_USE_COUNT;
 out_free:
 	kfree (new_data);
 out:
@@ -2619,6 +2622,7 @@
 			dev->name);
 
 	CHECK_PPP (-ENXIO);
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -2631,6 +2635,7 @@
 {
 	struct ppp *ppp = dev2ppp (dev);
 
+	MOD_DEC_USE_COUNT;
 	if (ppp2tty (ppp) == NULL) {
 		return -ENXIO;
 	}
@@ -3094,6 +3099,8 @@
 		ppp_last->next = ppp;
 	ppp_last = ppp;
 	ppp->next = 0;
+	ppp->read_wait	= NULL;
+	ppp->write_wait = NULL;
 
 	dev = ppp2dev(ppp);
 	dev->next      = NULL;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov