diff options
-rw-r--r-- | fs/splice.c | 217 | ||||
-rw-r--r-- | include/linux/splice.h | 10 |
2 files changed, 153 insertions, 74 deletions
diff --git a/fs/splice.c b/fs/splice.c index c18aa7e03e2b..fd6b278d447b 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -601,107 +601,176 @@ out: | |||
601 | return ret; | 601 | return ret; |
602 | } | 602 | } |
603 | 603 | ||
604 | static void wakeup_pipe_writers(struct pipe_inode_info *pipe) | ||
605 | { | ||
606 | smp_mb(); | ||
607 | if (waitqueue_active(&pipe->wait)) | ||
608 | wake_up_interruptible(&pipe->wait); | ||
609 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | ||
610 | } | ||
611 | |||
604 | /** | 612 | /** |
605 | * __splice_from_pipe - splice data from a pipe to given actor | 613 | * splice_from_pipe_feed - feed available data from a pipe to a file |
606 | * @pipe: pipe to splice from | 614 | * @pipe: pipe to splice from |
607 | * @sd: information to @actor | 615 | * @sd: information to @actor |
608 | * @actor: handler that splices the data | 616 | * @actor: handler that splices the data |
609 | * | 617 | * |
610 | * Description: | 618 | * Description: |
611 | * This function does little more than loop over the pipe and call | 619 | |
612 | * @actor to do the actual moving of a single struct pipe_buffer to | 620 | * This function loops over the pipe and calls @actor to do the |
613 | * the desired destination. See pipe_to_file, pipe_to_sendpage, or | 621 | * actual moving of a single struct pipe_buffer to the desired |
614 | * pipe_to_user. | 622 | * destination. It returns when there's no more buffers left in |
623 | * the pipe or if the requested number of bytes (@sd->total_len) | ||
624 | * have been copied. It returns a positive number (one) if the | ||
625 | * pipe needs to be filled with more data, zero if the required | ||
626 | * number of bytes have been copied and -errno on error. | ||
615 | * | 627 | * |
628 | * This, together with splice_from_pipe_{begin,end,next}, may be | ||
629 | * used to implement the functionality of __splice_from_pipe() when | ||
630 | * locking is required around copying the pipe buffers to the | ||
631 | * destination. | ||
616 | */ | 632 | */ |
617 | ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, | 633 | int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, |
618 | splice_actor *actor) | 634 | splice_actor *actor) |
619 | { | 635 | { |
620 | int ret, do_wakeup, err; | 636 | int ret; |
621 | |||
622 | ret = 0; | ||
623 | do_wakeup = 0; | ||
624 | |||
625 | for (;;) { | ||
626 | if (pipe->nrbufs) { | ||
627 | struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; | ||
628 | const struct pipe_buf_operations *ops = buf->ops; | ||
629 | 637 | ||
630 | sd->len = buf->len; | 638 | while (pipe->nrbufs) { |
631 | if (sd->len > sd->total_len) | 639 | struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; |
632 | sd->len = sd->total_len; | 640 | const struct pipe_buf_operations *ops = buf->ops; |
633 | 641 | ||
634 | err = actor(pipe, buf, sd); | 642 | sd->len = buf->len; |
635 | if (err <= 0) { | 643 | if (sd->len > sd->total_len) |
636 | if (!ret && err != -ENODATA) | 644 | sd->len = sd->total_len; |
637 | ret = err; | ||
638 | 645 | ||
639 | break; | 646 | ret = actor(pipe, buf, sd); |
640 | } | 647 | if (ret <= 0) { |
648 | if (ret == -ENODATA) | ||
649 | ret = 0; | ||
650 | return ret; | ||
651 | } | ||
652 | buf->offset += ret; | ||
653 | buf->len -= ret; | ||
641 | 654 | ||
642 | ret += err; | 655 | sd->num_spliced += ret; |
643 | buf->offset += err; | 656 | sd->len -= ret; |
644 | buf->len -= err; | 657 | sd->pos += ret; |
658 | sd->total_len -= ret; | ||
645 | 659 | ||
646 | sd->len -= err; | 660 | if (!buf->len) { |
647 | sd->pos += err; | 661 | buf->ops = NULL; |
648 | sd->total_len -= err; | 662 | ops->release(pipe, buf); |
649 | if (sd->len) | 663 | pipe->curbuf = (pipe->curbuf + 1) & (PIPE_BUFFERS - 1); |
650 | continue; | 664 | pipe->nrbufs--; |
665 | if (pipe->inode) | ||
666 | sd->need_wakeup = true; | ||
667 | } | ||
651 | 668 | ||
652 | if (!buf->len) { | 669 | if (!sd->total_len) |
653 | buf->ops = NULL; | 670 | return 0; |
654 | ops->release(pipe, buf); | 671 | } |
655 | pipe->curbuf = (pipe->curbuf + 1) & (PIPE_BUFFERS - 1); | ||
656 | pipe->nrbufs--; | ||
657 | if (pipe->inode) | ||
658 | do_wakeup = 1; | ||
659 | } | ||
660 | 672 | ||
661 | if (!sd->total_len) | 673 | return 1; |
662 | break; | 674 | } |
663 | } | 675 | EXPORT_SYMBOL(splice_from_pipe_feed); |
664 | 676 | ||
665 | if (pipe->nrbufs) | 677 | /** |
666 | continue; | 678 | * splice_from_pipe_next - wait for some data to splice from |
679 | * @pipe: pipe to splice from | ||
680 | * @sd: information about the splice operation | ||
681 | * | ||
682 | * Description: | ||
683 | * This function will wait for some data and return a positive | ||
684 | * value (one) if pipe buffers are available. It will return zero | ||
685 | * or -errno if no more data needs to be spliced. | ||
686 | */ | ||
687 | int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd) | ||
688 | { | ||
689 | while (!pipe->nrbufs) { | ||
667 | if (!pipe->writers) | 690 | if (!pipe->writers) |
668 | break; | 691 | return 0; |
669 | if (!pipe->waiting_writers) { | ||
670 | if (ret) | ||
671 | break; | ||
672 | } | ||
673 | 692 | ||
674 | if (sd->flags & SPLICE_F_NONBLOCK) { | 693 | if (!pipe->waiting_writers && sd->num_spliced) |
675 | if (!ret) | 694 | return 0; |
676 | ret = -EAGAIN; | ||
677 | break; | ||
678 | } | ||
679 | 695 | ||
680 | if (signal_pending(current)) { | 696 | if (sd->flags & SPLICE_F_NONBLOCK) |
681 | if (!ret) | 697 | return -EAGAIN; |
682 | ret = -ERESTARTSYS; | ||
683 | break; | ||
684 | } | ||
685 | 698 | ||
686 | if (do_wakeup) { | 699 | if (signal_pending(current)) |
687 | smp_mb(); | 700 | return -ERESTARTSYS; |
688 | if (waitqueue_active(&pipe->wait)) | 701 | |
689 | wake_up_interruptible_sync(&pipe->wait); | 702 | if (sd->need_wakeup) { |
690 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | 703 | wakeup_pipe_writers(pipe); |
691 | do_wakeup = 0; | 704 | sd->need_wakeup = false; |
692 | } | 705 | } |
693 | 706 | ||
694 | pipe_wait(pipe); | 707 | pipe_wait(pipe); |
695 | } | 708 | } |
696 | 709 | ||
697 | if (do_wakeup) { | 710 | return 1; |
698 | smp_mb(); | 711 | } |
699 | if (waitqueue_active(&pipe->wait)) | 712 | EXPORT_SYMBOL(splice_from_pipe_next); |
700 | wake_up_interruptible(&pipe->wait); | ||
701 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | ||
702 | } | ||
703 | 713 | ||
704 | return ret; | 714 | /** |
715 | * splice_from_pipe_begin - start splicing from pipe | ||
716 | * @pipe: pipe to splice from | ||
717 | * | ||
718 | * Description: | ||
719 | * This function should be called before a loop containing | ||
720 | * splice_from_pipe_next() and splice_from_pipe_feed() to | ||
721 | * initialize the necessary fields of @sd. | ||
722 | */ | ||
723 | void splice_from_pipe_begin(struct splice_desc *sd) | ||
724 | { | ||
725 | sd->num_spliced = 0; | ||
726 | sd->need_wakeup = false; | ||
727 | } | ||
728 | EXPORT_SYMBOL(splice_from_pipe_begin); | ||
729 | |||
730 | /** | ||
731 | * splice_from_pipe_end - finish splicing from pipe | ||
732 | * @pipe: pipe to splice from | ||
733 | * @sd: information about the splice operation | ||
734 | * | ||
735 | * Description: | ||
736 | * This function will wake up pipe writers if necessary. It should | ||
737 | * be called after a loop containing splice_from_pipe_next() and | ||
738 | * splice_from_pipe_feed(). | ||
739 | */ | ||
740 | void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd) | ||
741 | { | ||
742 | if (sd->need_wakeup) | ||
743 | wakeup_pipe_writers(pipe); | ||
744 | } | ||
745 | EXPORT_SYMBOL(splice_from_pipe_end); | ||
746 | |||
747 | /** | ||
748 | * __splice_from_pipe - splice data from a pipe to given actor | ||
749 | * @pipe: pipe to splice from | ||
750 | * @sd: information to @actor | ||
751 | * @actor: handler that splices the data | ||
752 | * | ||
753 | * Description: | ||
754 | * This function does little more than loop over the pipe and call | ||
755 | * @actor to do the actual moving of a single struct pipe_buffer to | ||
756 | * the desired destination. See pipe_to_file, pipe_to_sendpage, or | ||
757 | * pipe_to_user. | ||
758 | * | ||
759 | */ | ||
760 | ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, | ||
761 | splice_actor *actor) | ||
762 | { | ||
763 | int ret; | ||
764 | |||
765 | splice_from_pipe_begin(sd); | ||
766 | do { | ||
767 | ret = splice_from_pipe_next(pipe, sd); | ||
768 | if (ret > 0) | ||
769 | ret = splice_from_pipe_feed(pipe, sd, actor); | ||
770 | } while (ret > 0); | ||
771 | splice_from_pipe_end(pipe, sd); | ||
772 | |||
773 | return sd->num_spliced ? sd->num_spliced : ret; | ||
705 | } | 774 | } |
706 | EXPORT_SYMBOL(__splice_from_pipe); | 775 | EXPORT_SYMBOL(__splice_from_pipe); |
707 | 776 | ||
diff --git a/include/linux/splice.h b/include/linux/splice.h index 528dcb93c2f2..8fc2a635586e 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h | |||
@@ -36,6 +36,8 @@ struct splice_desc { | |||
36 | void *data; /* cookie */ | 36 | void *data; /* cookie */ |
37 | } u; | 37 | } u; |
38 | loff_t pos; /* file position */ | 38 | loff_t pos; /* file position */ |
39 | size_t num_spliced; /* number of bytes already spliced */ | ||
40 | bool need_wakeup; /* need to wake up writer */ | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | struct partial_page { | 43 | struct partial_page { |
@@ -66,6 +68,14 @@ extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *, | |||
66 | splice_actor *); | 68 | splice_actor *); |
67 | extern ssize_t __splice_from_pipe(struct pipe_inode_info *, | 69 | extern ssize_t __splice_from_pipe(struct pipe_inode_info *, |
68 | struct splice_desc *, splice_actor *); | 70 | struct splice_desc *, splice_actor *); |
71 | extern int splice_from_pipe_feed(struct pipe_inode_info *, struct splice_desc *, | ||
72 | splice_actor *); | ||
73 | extern int splice_from_pipe_next(struct pipe_inode_info *, | ||
74 | struct splice_desc *); | ||
75 | extern void splice_from_pipe_begin(struct splice_desc *); | ||
76 | extern void splice_from_pipe_end(struct pipe_inode_info *, | ||
77 | struct splice_desc *); | ||
78 | |||
69 | extern ssize_t splice_to_pipe(struct pipe_inode_info *, | 79 | extern ssize_t splice_to_pipe(struct pipe_inode_info *, |
70 | struct splice_pipe_desc *); | 80 | struct splice_pipe_desc *); |
71 | extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, | 81 | extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, |