static ssize_t pipe_writev(struct file *filp, const struct iovec *_iov, unsigned long nr_segs, loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; ssize_t ret; size_t min; int do_wakeup; struct iovec *iov = (struct iovec *)_iov; size_t total_len; total_len = iov_length(iov, nr_segs); /* Null write succeeds. */ if (unlikely(total_len == 0)) return 0; do_wakeup = 0; ret = 0; min = total_len; if (min > PIPE_BUF) min = 1; down(PIPE_SEM(*inode)); for (;;) { int free; if (!PIPE_READERS(*inode)) { send_sig(SIGPIPE, current, 0); if (!ret) ret = -EPIPE; break; } free = PIPE_FREE(*inode); if (free >= min) { /* transfer data */ ssize_t chars = PIPE_MAX_WCHUNK(*inode); char *pipebuf = PIPE_BASE(*inode) + PIPE_END(*inode); /* Always wakeup, even if the copy fails. Otherwise * we lock up (O_NONBLOCK-)readers that sleep due to * syscall merging. */ do_wakeup = 1; if (chars > total_len) chars = total_len; if (chars > free) chars = free; if (pipe_iov_copy_from_user(pipebuf, iov, chars)) { if (!ret) ret = -EFAULT; break; } ret += chars; PIPE_LEN(*inode) += chars; total_len -= chars; if (!total_len) break; } if (PIPE_FREE(*inode) && ret) { /* handle cyclic data buffers */ min = 1; continue; } if (filp->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); do_wakeup = 0; } PIPE_WAITING_WRITERS(*inode)++; pipe_wait(inode); PIPE_WAITING_WRITERS(*inode)--; } up(PIPE_SEM(*inode)); if (do_wakeup) { wake_up_interruptible(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); } /* * Hack: we turn off atime updates for -RT kernels. * Who uses them on pipes anyway? */ #ifndef CONFIG_PREEMPT_RT if (ret > 0) inode_update_time(inode, 1); /* mtime and ctime */ #endif return ret; }
static ssize_t pipe_write(struct kiocb *iocb, const struct iovec *_iov, unsigned long nr_segs, loff_t ppos) { struct file *filp = iocb->ki_filp; struct inode *inode = filp->f_path.dentry->d_inode; struct pipe_inode_info *pipe; ssize_t ret; int do_wakeup; struct iovec *iov = (struct iovec *)_iov; size_t total_len; ssize_t chars; total_len = iov_length(iov, nr_segs); /* Null write succeeds. */ if (unlikely(total_len == 0)) return 0; do_wakeup = 0; ret = 0; mutex_lock(&inode->i_mutex); pipe = inode->i_pipe; if (!pipe->readers) { send_sig(SIGPIPE, current, 0); ret = -EPIPE; goto out; } /* We try to merge small writes */ chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */ if (pipe->nrbufs && chars != 0) { int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) & (pipe->buffers - 1); struct pipe_buffer *buf = pipe->bufs + lastbuf; const struct pipe_buf_operations *ops = buf->ops; int offset = buf->offset + buf->len; if (ops->can_merge && offset + chars <= PAGE_SIZE) { int error, atomic = 1; void *addr; error = ops->confirm(pipe, buf); if (error) goto out; iov_fault_in_pages_read(iov, chars); redo1: addr = ops->map(pipe, buf, atomic); error = pipe_iov_copy_from_user(offset + addr, iov, chars, atomic); ops->unmap(pipe, buf, addr); ret = error; do_wakeup = 1; if (error) { if (atomic) { atomic = 0; goto redo1; } goto out; } buf->len += chars; total_len -= chars; ret = chars; if (!total_len) goto out; } } for (;;) { int bufs; if (!pipe->readers) { send_sig(SIGPIPE, current, 0); if (!ret) ret = -EPIPE; break; } bufs = pipe->nrbufs; if (bufs < pipe->buffers) { int newbuf = (pipe->curbuf + bufs) & (pipe->buffers-1); struct pipe_buffer *buf = pipe->bufs + newbuf; struct page *page = pipe->tmp_page; char *src; int error, atomic = 1; if (!page) { page = alloc_page(GFP_HIGHUSER); if (unlikely(!page)) { ret = ret ? : -ENOMEM; break; } pipe->tmp_page = page; }
static ssize_t pipe_writev(struct file *filp, const struct iovec *_iov, unsigned long nr_segs, loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; struct pipe_inode_info *info; ssize_t ret; int do_wakeup; struct iovec *iov = (struct iovec *)_iov; size_t total_len; ssize_t chars; total_len = iov_length(iov, nr_segs); /* Null write succeeds. */ if (unlikely(total_len == 0)) return 0; do_wakeup = 0; ret = 0; down(PIPE_SEM(*inode)); info = inode->i_pipe; if (!PIPE_READERS(*inode)) { send_sig(SIGPIPE, current, 0); ret = -EPIPE; goto out; } /* We try to merge small writes */ chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */ if (info->nrbufs && chars != 0) { int lastbuf = (info->curbuf + info->nrbufs - 1) & (PIPE_BUFFERS-1); struct pipe_buffer *buf = info->bufs + lastbuf; struct pipe_buf_operations *ops = buf->ops; int offset = buf->offset + buf->len; if (ops->can_merge && offset + chars <= PAGE_SIZE) { void *addr = ops->map(filp, info, buf); int error = pipe_iov_copy_from_user(offset + addr, iov, chars); ops->unmap(info, buf); ret = error; do_wakeup = 1; if (error) goto out; buf->len += chars; total_len -= chars; ret = chars; if (!total_len) goto out; } } for (;;) { int bufs; if (!PIPE_READERS(*inode)) { send_sig(SIGPIPE, current, 0); if (!ret) ret = -EPIPE; break; } bufs = info->nrbufs; if (bufs < PIPE_BUFFERS) { int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS-1); struct pipe_buffer *buf = info->bufs + newbuf; struct page *page = info->tmp_page; int error; if (!page) { page = alloc_page(GFP_HIGHUSER); if (unlikely(!page)) { ret = ret ? : -ENOMEM; break; } info->tmp_page = page; }