patch-2.3.15 linux/fs/fifo.c

Next file: linux/fs/ioctl.c
Previous file: linux/fs/fcntl.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.14/linux/fs/fifo.c linux/fs/fifo.c
@@ -12,38 +12,38 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 
-static int fifo_open(struct inode * inode,struct file * filp)
+static int fifo_open(struct inode *inode, struct file *filp)
 {
-	int retval = 0;
-	unsigned long page = 0;
-	struct pipe_inode_info *info, *tmp = NULL;
-
-	if (inode->i_pipe)
-		goto got_it;
-	tmp = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL);
-	if (inode->i_pipe)
-		goto got_it;
-	if (!tmp)
-		goto oom;
-	page = __get_free_page(GFP_KERNEL);
-	if (inode->i_pipe)
-		goto got_it;
-	if (!page)
-		goto oom;
-	inode->i_pipe = tmp;
-	PIPE_LOCK(*inode) = 0;
-	PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
-	PIPE_BASE(*inode) = (char *) page;
-	PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
-	PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
-	init_waitqueue_head(&PIPE_WAIT(*inode));
-	tmp = NULL;	/* no need to free it */
-	page = 0;
+	int ret;
 
-got_it:
+	ret = -ERESTARTSYS;
+	if (down_interruptible(PIPE_SEM(*inode)))
+		goto err_nolock_nocleanup;
+
+	if (! inode->i_pipe) {
+		unsigned long page;
+		struct pipe_inode_info *info;
+
+		info = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!info)
+			goto err_nocleanup;
+		page = __get_free_page(GFP_KERNEL);
+		if (!page) {
+			kfree(info);
+			goto err_nocleanup;
+		}
+
+		inode->i_pipe = info;
 
-	switch( filp->f_mode ) {
+		init_waitqueue_head(PIPE_WAIT(*inode));
+		PIPE_BASE(*inode) = (char *) page;
+		PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
+		PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
+	}
 
+	switch (filp->f_mode) {
 	case 1:
 	/*
 	 *  O_RDONLY
@@ -51,26 +51,26 @@
 	 *  opened, even when there is no process writing the FIFO.
 	 */
 		filp->f_op = &connecting_fifo_fops;
-		if (!PIPE_READERS(*inode)++)
-			wake_up_interruptible(&PIPE_WAIT(*inode));
-		if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) {
-			PIPE_RD_OPENERS(*inode)++;
+		if (PIPE_READERS(*inode)++ == 0)
+			wake_up_interruptible(PIPE_WAIT(*inode));
+
+		if (!(filp->f_flags & O_NONBLOCK)) {
 			while (!PIPE_WRITERS(*inode)) {
-				if (signal_pending(current)) {
-					retval = -ERESTARTSYS;
-					break;
-				}
-				interruptible_sleep_on(&PIPE_WAIT(*inode));
+				if (signal_pending(current))
+					goto err_rd;
+				up(PIPE_SEM(*inode));
+				interruptible_sleep_on(PIPE_WAIT(*inode));
+
+				/* Note that using down_interruptible here
+				   and similar places below is pointless,
+				   since we have to acquire the lock to clean
+				   up properly.  */
+				down(PIPE_SEM(*inode));
 			}
-			if (!--PIPE_RD_OPENERS(*inode))
-				wake_up_interruptible(&PIPE_WAIT(*inode));
 		}
-		while (PIPE_WR_OPENERS(*inode))
-			interruptible_sleep_on(&PIPE_WAIT(*inode));
+
 		if (PIPE_WRITERS(*inode))
 			filp->f_op = &read_fifo_fops;
-		if (retval && !--PIPE_READERS(*inode))
-			wake_up_interruptible(&PIPE_WAIT(*inode));
 		break;
 	
 	case 2:
@@ -79,29 +79,21 @@
 	 *  POSIX.1 says that O_NONBLOCK means return -1 with
 	 *  errno=ENXIO when there is no process reading the FIFO.
 	 */
-		if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) {
-			retval = -ENXIO;
-			break;
-		}
+		ret = -ENXIO;
+		if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode))
+			goto err;
+
 		filp->f_op = &write_fifo_fops;
 		if (!PIPE_WRITERS(*inode)++)
-			wake_up_interruptible(&PIPE_WAIT(*inode));
-		if (!PIPE_READERS(*inode)) {
-			PIPE_WR_OPENERS(*inode)++;
-			while (!PIPE_READERS(*inode)) {
-				if (signal_pending(current)) {
-					retval = -ERESTARTSYS;
-					break;
-				}
-				interruptible_sleep_on(&PIPE_WAIT(*inode));
-			}
-			if (!--PIPE_WR_OPENERS(*inode))
-				wake_up_interruptible(&PIPE_WAIT(*inode));
+			wake_up_interruptible(PIPE_WAIT(*inode));
+
+		while (!PIPE_READERS(*inode)) {
+			if (signal_pending(current))
+				goto err_wr;
+			up(PIPE_SEM(*inode));
+			interruptible_sleep_on(PIPE_WAIT(*inode));
+			down(PIPE_SEM(*inode));
 		}
-		while (PIPE_RD_OPENERS(*inode))
-			interruptible_sleep_on(&PIPE_WAIT(*inode));
-		if (retval && !--PIPE_WRITERS(*inode))
-			wake_up_interruptible(&PIPE_WAIT(*inode));
 		break;
 	
 	case 3:
@@ -112,39 +104,47 @@
 	 *  the process can at least talk to itself.
 	 */
 		filp->f_op = &rdwr_fifo_fops;
-		if (!PIPE_READERS(*inode)++)
-			wake_up_interruptible(&PIPE_WAIT(*inode));
-		while (PIPE_WR_OPENERS(*inode))
-			interruptible_sleep_on(&PIPE_WAIT(*inode));
-		if (!PIPE_WRITERS(*inode)++)
-			wake_up_interruptible(&PIPE_WAIT(*inode));
-		while (PIPE_RD_OPENERS(*inode))
-			interruptible_sleep_on(&PIPE_WAIT(*inode));
+
+		PIPE_READERS(*inode)++;
+		PIPE_WRITERS(*inode)++;
+		if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1)
+			wake_up_interruptible(PIPE_WAIT(*inode));
 		break;
 
 	default:
-		retval = -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
-	if (retval) 
-		goto cleanup;
-out:
-	if (tmp)
-		kfree(tmp);
-	if (page)
-		free_page(page);
-	return retval;
 
-cleanup:
+	/* Ok! */
+	up(PIPE_SEM(*inode));
+	return 0;
+
+err_rd:
+	if (!--PIPE_READERS(*inode))
+		wake_up_interruptible(PIPE_WAIT(*inode));
+	ret = -ERESTARTSYS;
+	goto err;
+
+err_wr:
+	if (!--PIPE_WRITERS(*inode))
+		wake_up_interruptible(PIPE_WAIT(*inode));
+	ret = -ERESTARTSYS;
+	goto err;
+
+err:
 	if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
-		info = inode->i_pipe;
+		struct pipe_inode_info *info = inode->i_pipe;
 		inode->i_pipe = NULL;
 		free_page((unsigned long)info->base);
 		kfree(info);
 	}
-	goto out;
-oom:
-	retval = -ENOMEM;
-	goto out;
+
+err_nocleanup:
+	up(PIPE_SEM(*inode));
+
+err_nolock_nocleanup:
+	return ret;
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)