diff options
Diffstat (limited to 'fs/fifo.c')
-rw-r--r-- | fs/fifo.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/fs/fifo.c b/fs/fifo.c new file mode 100644 index 000000000..ecd9bc232 --- /dev/null +++ b/fs/fifo.c @@ -0,0 +1,161 @@ +/* + * linux/fs/fifo.c + * + * written by Paul H. Hargrove + */ + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/fcntl.h> + +static int fifo_open(struct inode * inode,struct file * filp) +{ + int retval = 0; + unsigned long page; + + switch( filp->f_mode ) { + + case 1: + /* + * O_RDONLY + * POSIX.1 says that O_NONBLOCK means return with the FIFO + * 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)++; + while (!PIPE_WRITERS(*inode)) { + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + interruptible_sleep_on(&PIPE_WAIT(*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: + /* + * O_WRONLY + * 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; + } + 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 (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + interruptible_sleep_on(&PIPE_WAIT(*inode)); + } + if (!--PIPE_WR_OPENERS(*inode)) + wake_up_interruptible(&PIPE_WAIT(*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: + /* + * O_RDWR + * POSIX.1 leaves this case "undefined" when O_NONBLOCK is set. + * This implementation will NEVER block on a O_RDWR open, since + * 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)); + break; + + default: + retval = -EINVAL; + } + if (retval || PIPE_BASE(*inode)) + return retval; + page = __get_free_page(GFP_KERNEL); + if (PIPE_BASE(*inode)) { + free_page(page); + return 0; + } + if (!page) + return -ENOMEM; + PIPE_LOCK(*inode) = 0; + PIPE_START(*inode) = PIPE_LEN(*inode) = 0; + PIPE_BASE(*inode) = (char *) page; + return 0; +} + +/* + * Dummy default file-operations: the only thing this does + * is contain the open that then fills in the correct operations + * depending on the access mode of the file... + */ +static struct file_operations def_fifo_fops = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + fifo_open, /* will set read or write pipe_fops */ + NULL, + NULL +}; + +static struct inode_operations fifo_inode_operations = { + &def_fifo_fops, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +void init_fifo(struct inode * inode) +{ + inode->i_op = &fifo_inode_operations; + inode->i_pipe = 1; + PIPE_LOCK(*inode) = 0; + PIPE_BASE(*inode) = NULL; + PIPE_START(*inode) = PIPE_LEN(*inode) = 0; + PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; + PIPE_WAIT(*inode) = NULL; + PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; +} |