struct inode* pipe_new(struct inode* inode) { unsigned long page; page = __get_free_page(GFP_USER); if (!page) return NULL; inode->i_pipe = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); if (!inode->i_pipe) goto fail_page; 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; PIPE_WAITING_WRITERS(*inode) = 0; PIPE_RCOUNTER(*inode) = PIPE_WCOUNTER(*inode) = 1; *PIPE_FASYNC_READERS(*inode) = *PIPE_FASYNC_WRITERS(*inode) = NULL; return inode; fail_page: free_page(page); return NULL; }
static ssize_t pipe_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count }; return pipe_writev(filp, &iov, 1, ppos); } static ssize_t bad_pipe_r(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { return -EBADF; } static ssize_t bad_pipe_w(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { return -EBADF; } static int pipe_ioctl(struct inode *pino, struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd) { case FIONREAD: return put_user(PIPE_LEN(*pino), (int __user *)arg); default: return -EINVAL; } } /* No kernel lock held - fine */ static unsigned int pipe_poll(struct file *filp, poll_table *wait) { unsigned int mask; struct inode *inode = filp->f_dentry->d_inode; poll_wait(filp, PIPE_WAIT(*inode), wait); /* Reading only -- no need for acquiring the semaphore. */ mask = POLLIN | POLLRDNORM; if (PIPE_EMPTY(*inode)) mask = POLLOUT | POLLWRNORM; if (!PIPE_WRITERS(*inode) && filp->f_version != PIPE_WCOUNTER(*inode)) mask |= POLLHUP; if (!PIPE_READERS(*inode)) mask |= POLLERR; return mask; }
/* No kernel lock held - fine */ static unsigned int pipe_poll(struct file *filp, poll_table *wait) { unsigned int mask; struct inode *inode = filp->f_dentry->d_inode; poll_wait(filp, PIPE_WAIT(*inode), wait); /* Reading only -- no need for acquiring the semaphore. */ mask = POLLIN | POLLRDNORM; if (PIPE_EMPTY(*inode)) mask = POLLOUT | POLLWRNORM; if (!PIPE_WRITERS(*inode) && filp->f_version != PIPE_WCOUNTER(*inode)) mask |= POLLHUP; if (!PIPE_READERS(*inode)) mask |= POLLERR; return mask; }
static int fifo_open(struct inode *inode, struct file *filp) { int ret; ret = -ERESTARTSYS; lock_kernel(); if (down_interruptible(PIPE_SEM(*inode))) goto err_nolock_nocleanup; if (!inode->i_pipe) { ret = -ENOMEM; if(!pipe_new(inode)) goto err_nocleanup; } filp->f_version = 0; 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 = &read_fifo_fops; PIPE_RCOUNTER(*inode)++; if (PIPE_READERS(*inode)++ == 0) wake_up_partner(inode); if (!PIPE_WRITERS(*inode)) { if ((filp->f_flags & O_NONBLOCK)) { /* suppress POLLHUP until we have * seen a writer */ filp->f_version = PIPE_WCOUNTER(*inode); } else { wait_for_partner(inode, &PIPE_WCOUNTER(*inode)); if(signal_pending(current)) goto err_rd; } } 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. */ ret = -ENXIO; if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) goto err; filp->f_op = &write_fifo_fops; PIPE_WCOUNTER(*inode)++; if (!PIPE_WRITERS(*inode)++) wake_up_partner(inode); if (!PIPE_READERS(*inode)) { wait_for_partner(inode, &PIPE_RCOUNTER(*inode)); if (signal_pending(current)) goto err_wr; } 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; PIPE_READERS(*inode)++; PIPE_WRITERS(*inode)++; PIPE_RCOUNTER(*inode)++; PIPE_WCOUNTER(*inode)++; if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1) wake_up_partner(inode); break; default: ret = -EINVAL; goto err; } /* Ok! */ up(PIPE_SEM(*inode)); unlock_kernel(); 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)) { struct pipe_inode_info *info = inode->i_pipe; inode->i_pipe = NULL; free_page((unsigned long)info->base); kfree(info); } err_nocleanup: up(PIPE_SEM(*inode)); err_nolock_nocleanup: unlock_kernel(); return ret; }