1/*
2 *  linux/fs/fifo.c
3 *
4 *  written by Paul H. Hargrove
5 *
6 *  Fixes:
7 *	10-06-1999, AV: fixed OOM handling in fifo_open(), moved
8 *			initialization there, switched to external
9 *			allocation of pipe_inode_info.
10 */
11
12#include <linux/mm.h>
13#include <linux/slab.h>
14#include <linux/fs.h>
15#include <linux/sched.h>
16#include <linux/pipe_fs_i.h>
17
18static void wait_for_partner(struct inode* inode, unsigned int *cnt)
19{
20	int cur = *cnt;
21
22	while (cur == *cnt) {
23		pipe_wait(inode->i_pipe);
24		if (signal_pending(current))
25			break;
26	}
27}
28
29static void wake_up_partner(struct inode* inode)
30{
31	wake_up_interruptible(&inode->i_pipe->wait);
32}
33
34static int fifo_open(struct inode *inode, struct file *filp)
35{
36	struct pipe_inode_info *pipe;
37	int ret;
38
39	mutex_lock(&inode->i_mutex);
40	pipe = inode->i_pipe;
41	if (!pipe) {
42		ret = -ENOMEM;
43		pipe = alloc_pipe_info(inode);
44		if (!pipe)
45			goto err_nocleanup;
46		inode->i_pipe = pipe;
47	}
48	filp->f_version = 0;
49
50	/* We can only do regular read/write on fifos */
51	filp->f_mode &= (FMODE_READ | FMODE_WRITE);
52
53	switch (filp->f_mode) {
54	case 1:
55	/*
56	 *  O_RDONLY
57	 *  POSIX.1 says that O_NONBLOCK means return with the FIFO
58	 *  opened, even when there is no process writing the FIFO.
59	 */
60		filp->f_op = &read_fifo_fops;
61		pipe->r_counter++;
62		if (pipe->readers++ == 0)
63			wake_up_partner(inode);
64
65		if (!pipe->writers) {
66			if ((filp->f_flags & O_NONBLOCK)) {
67				/* suppress POLLHUP until we have
68				 * seen a writer */
69				filp->f_version = pipe->w_counter;
70			} else
71			{
72				wait_for_partner(inode, &pipe->w_counter);
73				if(signal_pending(current))
74					goto err_rd;
75			}
76		}
77		break;
78
79	case 2:
80	/*
81	 *  O_WRONLY
82	 *  POSIX.1 says that O_NONBLOCK means return -1 with
83	 *  errno=ENXIO when there is no process reading the FIFO.
84	 */
85		ret = -ENXIO;
86		if ((filp->f_flags & O_NONBLOCK) && !pipe->readers)
87			goto err;
88
89		filp->f_op = &write_fifo_fops;
90		pipe->w_counter++;
91		if (!pipe->writers++)
92			wake_up_partner(inode);
93
94		if (!pipe->readers) {
95			wait_for_partner(inode, &pipe->r_counter);
96			if (signal_pending(current))
97				goto err_wr;
98		}
99		break;
100
101	case 3:
102	/*
103	 *  O_RDWR
104	 *  POSIX.1 leaves this case "undefined" when O_NONBLOCK is set.
105	 *  This implementation will NEVER block on a O_RDWR open, since
106	 *  the process can at least talk to itself.
107	 */
108		filp->f_op = &rdwr_fifo_fops;
109
110		pipe->readers++;
111		pipe->writers++;
112		pipe->r_counter++;
113		pipe->w_counter++;
114		if (pipe->readers == 1 || pipe->writers == 1)
115			wake_up_partner(inode);
116		break;
117
118	default:
119		ret = -EINVAL;
120		goto err;
121	}
122
123	/* Ok! */
124	mutex_unlock(&inode->i_mutex);
125	return 0;
126
127err_rd:
128	if (!--pipe->readers)
129		wake_up_interruptible(&pipe->wait);
130	ret = -ERESTARTSYS;
131	goto err;
132
133err_wr:
134	if (!--pipe->writers)
135		wake_up_interruptible(&pipe->wait);
136	ret = -ERESTARTSYS;
137	goto err;
138
139err:
140	if (!pipe->readers && !pipe->writers)
141		free_pipe_info(inode);
142
143err_nocleanup:
144	mutex_unlock(&inode->i_mutex);
145	return ret;
146}
147
148/*
149 * Dummy default file-operations: the only thing this does
150 * is contain the open that then fills in the correct operations
151 * depending on the access mode of the file...
152 */
153const struct file_operations def_fifo_fops = {
154	.open		= fifo_open,	/* will set read or write pipe_fops */
155};
156