|
@@ -601,107 +601,176 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static void wakeup_pipe_writers(struct pipe_inode_info *pipe)
|
|
|
+{
|
|
|
+ smp_mb();
|
|
|
+ if (waitqueue_active(&pipe->wait))
|
|
|
+ wake_up_interruptible(&pipe->wait);
|
|
|
+ kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
- * __splice_from_pipe - splice data from a pipe to given actor
|
|
|
+ * splice_from_pipe_feed - feed available data from a pipe to a file
|
|
|
* @pipe: pipe to splice from
|
|
|
* @sd: information to @actor
|
|
|
* @actor: handler that splices the data
|
|
|
*
|
|
|
* Description:
|
|
|
- * This function does little more than loop over the pipe and call
|
|
|
- * @actor to do the actual moving of a single struct pipe_buffer to
|
|
|
- * the desired destination. See pipe_to_file, pipe_to_sendpage, or
|
|
|
- * pipe_to_user.
|
|
|
+
|
|
|
+ * This function loops over the pipe and calls @actor to do the
|
|
|
+ * actual moving of a single struct pipe_buffer to the desired
|
|
|
+ * destination. It returns when there's no more buffers left in
|
|
|
+ * the pipe or if the requested number of bytes (@sd->total_len)
|
|
|
+ * have been copied. It returns a positive number (one) if the
|
|
|
+ * pipe needs to be filled with more data, zero if the required
|
|
|
+ * number of bytes have been copied and -errno on error.
|
|
|
*
|
|
|
+ * This, together with splice_from_pipe_{begin,end,next}, may be
|
|
|
+ * used to implement the functionality of __splice_from_pipe() when
|
|
|
+ * locking is required around copying the pipe buffers to the
|
|
|
+ * destination.
|
|
|
*/
|
|
|
-ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
|
|
|
- splice_actor *actor)
|
|
|
+int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd,
|
|
|
+ splice_actor *actor)
|
|
|
{
|
|
|
- int ret, do_wakeup, err;
|
|
|
-
|
|
|
- ret = 0;
|
|
|
- do_wakeup = 0;
|
|
|
-
|
|
|
- for (;;) {
|
|
|
- if (pipe->nrbufs) {
|
|
|
- struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
|
|
|
- const struct pipe_buf_operations *ops = buf->ops;
|
|
|
+ int ret;
|
|
|
|
|
|
- sd->len = buf->len;
|
|
|
- if (sd->len > sd->total_len)
|
|
|
- sd->len = sd->total_len;
|
|
|
+ while (pipe->nrbufs) {
|
|
|
+ struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
|
|
|
+ const struct pipe_buf_operations *ops = buf->ops;
|
|
|
|
|
|
- err = actor(pipe, buf, sd);
|
|
|
- if (err <= 0) {
|
|
|
- if (!ret && err != -ENODATA)
|
|
|
- ret = err;
|
|
|
+ sd->len = buf->len;
|
|
|
+ if (sd->len > sd->total_len)
|
|
|
+ sd->len = sd->total_len;
|
|
|
|
|
|
- break;
|
|
|
- }
|
|
|
+ ret = actor(pipe, buf, sd);
|
|
|
+ if (ret <= 0) {
|
|
|
+ if (ret == -ENODATA)
|
|
|
+ ret = 0;
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ buf->offset += ret;
|
|
|
+ buf->len -= ret;
|
|
|
|
|
|
- ret += err;
|
|
|
- buf->offset += err;
|
|
|
- buf->len -= err;
|
|
|
+ sd->num_spliced += ret;
|
|
|
+ sd->len -= ret;
|
|
|
+ sd->pos += ret;
|
|
|
+ sd->total_len -= ret;
|
|
|
|
|
|
- sd->len -= err;
|
|
|
- sd->pos += err;
|
|
|
- sd->total_len -= err;
|
|
|
- if (sd->len)
|
|
|
- continue;
|
|
|
+ if (!buf->len) {
|
|
|
+ buf->ops = NULL;
|
|
|
+ ops->release(pipe, buf);
|
|
|
+ pipe->curbuf = (pipe->curbuf + 1) & (PIPE_BUFFERS - 1);
|
|
|
+ pipe->nrbufs--;
|
|
|
+ if (pipe->inode)
|
|
|
+ sd->need_wakeup = true;
|
|
|
+ }
|
|
|
|
|
|
- if (!buf->len) {
|
|
|
- buf->ops = NULL;
|
|
|
- ops->release(pipe, buf);
|
|
|
- pipe->curbuf = (pipe->curbuf + 1) & (PIPE_BUFFERS - 1);
|
|
|
- pipe->nrbufs--;
|
|
|
- if (pipe->inode)
|
|
|
- do_wakeup = 1;
|
|
|
- }
|
|
|
+ if (!sd->total_len)
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- if (!sd->total_len)
|
|
|
- break;
|
|
|
- }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(splice_from_pipe_feed);
|
|
|
|
|
|
- if (pipe->nrbufs)
|
|
|
- continue;
|
|
|
+/**
|
|
|
+ * splice_from_pipe_next - wait for some data to splice from
|
|
|
+ * @pipe: pipe to splice from
|
|
|
+ * @sd: information about the splice operation
|
|
|
+ *
|
|
|
+ * Description:
|
|
|
+ * This function will wait for some data and return a positive
|
|
|
+ * value (one) if pipe buffers are available. It will return zero
|
|
|
+ * or -errno if no more data needs to be spliced.
|
|
|
+ */
|
|
|
+int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
|
|
|
+{
|
|
|
+ while (!pipe->nrbufs) {
|
|
|
if (!pipe->writers)
|
|
|
- break;
|
|
|
- if (!pipe->waiting_writers) {
|
|
|
- if (ret)
|
|
|
- break;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
|
|
|
- if (sd->flags & SPLICE_F_NONBLOCK) {
|
|
|
- if (!ret)
|
|
|
- ret = -EAGAIN;
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (!pipe->waiting_writers && sd->num_spliced)
|
|
|
+ return 0;
|
|
|
|
|
|
- if (signal_pending(current)) {
|
|
|
- if (!ret)
|
|
|
- ret = -ERESTARTSYS;
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (sd->flags & SPLICE_F_NONBLOCK)
|
|
|
+ return -EAGAIN;
|
|
|
|
|
|
- if (do_wakeup) {
|
|
|
- smp_mb();
|
|
|
- if (waitqueue_active(&pipe->wait))
|
|
|
- wake_up_interruptible_sync(&pipe->wait);
|
|
|
- kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
|
|
|
- do_wakeup = 0;
|
|
|
+ if (signal_pending(current))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+
|
|
|
+ if (sd->need_wakeup) {
|
|
|
+ wakeup_pipe_writers(pipe);
|
|
|
+ sd->need_wakeup = false;
|
|
|
}
|
|
|
|
|
|
pipe_wait(pipe);
|
|
|
}
|
|
|
|
|
|
- if (do_wakeup) {
|
|
|
- smp_mb();
|
|
|
- if (waitqueue_active(&pipe->wait))
|
|
|
- wake_up_interruptible(&pipe->wait);
|
|
|
- kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
|
|
|
- }
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(splice_from_pipe_next);
|
|
|
|
|
|
- return ret;
|
|
|
+/**
|
|
|
+ * splice_from_pipe_begin - start splicing from pipe
|
|
|
+ * @pipe: pipe to splice from
|
|
|
+ *
|
|
|
+ * Description:
|
|
|
+ * This function should be called before a loop containing
|
|
|
+ * splice_from_pipe_next() and splice_from_pipe_feed() to
|
|
|
+ * initialize the necessary fields of @sd.
|
|
|
+ */
|
|
|
+void splice_from_pipe_begin(struct splice_desc *sd)
|
|
|
+{
|
|
|
+ sd->num_spliced = 0;
|
|
|
+ sd->need_wakeup = false;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(splice_from_pipe_begin);
|
|
|
+
|
|
|
+/**
|
|
|
+ * splice_from_pipe_end - finish splicing from pipe
|
|
|
+ * @pipe: pipe to splice from
|
|
|
+ * @sd: information about the splice operation
|
|
|
+ *
|
|
|
+ * Description:
|
|
|
+ * This function will wake up pipe writers if necessary. It should
|
|
|
+ * be called after a loop containing splice_from_pipe_next() and
|
|
|
+ * splice_from_pipe_feed().
|
|
|
+ */
|
|
|
+void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd)
|
|
|
+{
|
|
|
+ if (sd->need_wakeup)
|
|
|
+ wakeup_pipe_writers(pipe);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(splice_from_pipe_end);
|
|
|
+
|
|
|
+/**
|
|
|
+ * __splice_from_pipe - splice data from a pipe to given actor
|
|
|
+ * @pipe: pipe to splice from
|
|
|
+ * @sd: information to @actor
|
|
|
+ * @actor: handler that splices the data
|
|
|
+ *
|
|
|
+ * Description:
|
|
|
+ * This function does little more than loop over the pipe and call
|
|
|
+ * @actor to do the actual moving of a single struct pipe_buffer to
|
|
|
+ * the desired destination. See pipe_to_file, pipe_to_sendpage, or
|
|
|
+ * pipe_to_user.
|
|
|
+ *
|
|
|
+ */
|
|
|
+ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
|
|
|
+ splice_actor *actor)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ splice_from_pipe_begin(sd);
|
|
|
+ do {
|
|
|
+ ret = splice_from_pipe_next(pipe, sd);
|
|
|
+ if (ret > 0)
|
|
|
+ ret = splice_from_pipe_feed(pipe, sd, actor);
|
|
|
+ } while (ret > 0);
|
|
|
+ splice_from_pipe_end(pipe, sd);
|
|
|
+
|
|
|
+ return sd->num_spliced ? sd->num_spliced : ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(__splice_from_pipe);
|
|
|
|