|
|
@@ -183,79 +183,41 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
|
|
|
struct splice_pipe_desc *spd)
|
|
|
{
|
|
|
unsigned int spd_pages = spd->nr_pages;
|
|
|
- int ret, do_wakeup, page_nr;
|
|
|
+ int ret = 0, page_nr = 0;
|
|
|
|
|
|
if (!spd_pages)
|
|
|
return 0;
|
|
|
|
|
|
- ret = 0;
|
|
|
- do_wakeup = 0;
|
|
|
- page_nr = 0;
|
|
|
-
|
|
|
- pipe_lock(pipe);
|
|
|
-
|
|
|
- for (;;) {
|
|
|
- if (!pipe->readers) {
|
|
|
- send_sig(SIGPIPE, current, 0);
|
|
|
- if (!ret)
|
|
|
- ret = -EPIPE;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (pipe->nrbufs < pipe->buffers) {
|
|
|
- int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
|
|
|
- struct pipe_buffer *buf = pipe->bufs + newbuf;
|
|
|
-
|
|
|
- buf->page = spd->pages[page_nr];
|
|
|
- buf->offset = spd->partial[page_nr].offset;
|
|
|
- buf->len = spd->partial[page_nr].len;
|
|
|
- buf->private = spd->partial[page_nr].private;
|
|
|
- buf->ops = spd->ops;
|
|
|
- if (spd->flags & SPLICE_F_GIFT)
|
|
|
- buf->flags |= PIPE_BUF_FLAG_GIFT;
|
|
|
-
|
|
|
- pipe->nrbufs++;
|
|
|
- page_nr++;
|
|
|
- ret += buf->len;
|
|
|
-
|
|
|
- if (pipe->files)
|
|
|
- do_wakeup = 1;
|
|
|
+ if (unlikely(!pipe->readers)) {
|
|
|
+ send_sig(SIGPIPE, current, 0);
|
|
|
+ ret = -EPIPE;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
- if (!--spd->nr_pages)
|
|
|
- break;
|
|
|
- if (pipe->nrbufs < pipe->buffers)
|
|
|
- continue;
|
|
|
+ while (pipe->nrbufs < pipe->buffers) {
|
|
|
+ int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
|
|
|
+ struct pipe_buffer *buf = pipe->bufs + newbuf;
|
|
|
|
|
|
- break;
|
|
|
- }
|
|
|
+ buf->page = spd->pages[page_nr];
|
|
|
+ buf->offset = spd->partial[page_nr].offset;
|
|
|
+ buf->len = spd->partial[page_nr].len;
|
|
|
+ buf->private = spd->partial[page_nr].private;
|
|
|
+ buf->ops = spd->ops;
|
|
|
+ if (spd->flags & SPLICE_F_GIFT)
|
|
|
+ buf->flags |= PIPE_BUF_FLAG_GIFT;
|
|
|
|
|
|
- if (spd->flags & SPLICE_F_NONBLOCK) {
|
|
|
- if (!ret)
|
|
|
- ret = -EAGAIN;
|
|
|
- break;
|
|
|
- }
|
|
|
+ pipe->nrbufs++;
|
|
|
+ page_nr++;
|
|
|
+ ret += buf->len;
|
|
|
|
|
|
- if (signal_pending(current)) {
|
|
|
- if (!ret)
|
|
|
- ret = -ERESTARTSYS;
|
|
|
+ if (!--spd->nr_pages)
|
|
|
break;
|
|
|
- }
|
|
|
-
|
|
|
- if (do_wakeup) {
|
|
|
- wakeup_pipe_readers(pipe);
|
|
|
- do_wakeup = 0;
|
|
|
- }
|
|
|
-
|
|
|
- pipe->waiting_writers++;
|
|
|
- pipe_wait(pipe);
|
|
|
- pipe->waiting_writers--;
|
|
|
}
|
|
|
|
|
|
- pipe_unlock(pipe);
|
|
|
-
|
|
|
- if (do_wakeup)
|
|
|
- wakeup_pipe_readers(pipe);
|
|
|
+ if (!ret)
|
|
|
+ ret = -EAGAIN;
|
|
|
|
|
|
+out:
|
|
|
while (page_nr < spd_pages)
|
|
|
spd->spd_release(spd, page_nr++);
|
|
|
|
|
|
@@ -1339,6 +1301,20 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
|
|
|
}
|
|
|
EXPORT_SYMBOL(do_splice_direct);
|
|
|
|
|
|
+static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
|
|
|
+{
|
|
|
+ while (pipe->nrbufs == pipe->buffers) {
|
|
|
+ if (flags & SPLICE_F_NONBLOCK)
|
|
|
+ return -EAGAIN;
|
|
|
+ if (signal_pending(current))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+ pipe->waiting_writers++;
|
|
|
+ pipe_wait(pipe);
|
|
|
+ pipe->waiting_writers--;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
|
|
|
struct pipe_inode_info *opipe,
|
|
|
size_t len, unsigned int flags);
|
|
|
@@ -1421,8 +1397,13 @@ static long do_splice(struct file *in, loff_t __user *off_in,
|
|
|
offset = in->f_pos;
|
|
|
}
|
|
|
|
|
|
- ret = do_splice_to(in, &offset, opipe, len, flags);
|
|
|
-
|
|
|
+ pipe_lock(opipe);
|
|
|
+ ret = wait_for_space(opipe, flags);
|
|
|
+ if (!ret)
|
|
|
+ ret = do_splice_to(in, &offset, opipe, len, flags);
|
|
|
+ pipe_unlock(opipe);
|
|
|
+ if (ret > 0)
|
|
|
+ wakeup_pipe_readers(opipe);
|
|
|
if (!off_in)
|
|
|
in->f_pos = offset;
|
|
|
else if (copy_to_user(off_in, &offset, sizeof(loff_t)))
|
|
|
@@ -1546,14 +1527,20 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
- spd.nr_pages = get_iovec_page_array(&from, spd.pages,
|
|
|
- spd.partial,
|
|
|
- spd.nr_pages_max);
|
|
|
- if (spd.nr_pages <= 0)
|
|
|
- ret = spd.nr_pages;
|
|
|
- else
|
|
|
- ret = splice_to_pipe(pipe, &spd);
|
|
|
-
|
|
|
+ pipe_lock(pipe);
|
|
|
+ ret = wait_for_space(pipe, flags);
|
|
|
+ if (!ret) {
|
|
|
+ spd.nr_pages = get_iovec_page_array(&from, spd.pages,
|
|
|
+ spd.partial,
|
|
|
+ spd.nr_pages_max);
|
|
|
+ if (spd.nr_pages <= 0)
|
|
|
+ ret = spd.nr_pages;
|
|
|
+ else
|
|
|
+ ret = splice_to_pipe(pipe, &spd);
|
|
|
+ }
|
|
|
+ pipe_unlock(pipe);
|
|
|
+ if (ret > 0)
|
|
|
+ wakeup_pipe_readers(pipe);
|
|
|
splice_shrink_spd(&spd);
|
|
|
kfree(iov);
|
|
|
return ret;
|