diff options
author | Ingo Molnar <mingo@elte.hu> | 2006-04-10 09:18:35 -0400 |
---|---|---|
committer | Jens Axboe <axboe@suse.de> | 2006-04-10 09:18:35 -0400 |
commit | 3a326a2ce88e71d00ac0d133e314a3342a7709f8 (patch) | |
tree | 3a3cf55be19311c04d195e37baec9f49c4015b18 /fs/splice.c | |
parent | 0b749ce3802428007a37870eb51ba3c0bdf90857 (diff) |
[PATCH] introduce a "kernel-internal pipe object" abstraction
separate out the 'internal pipe object' abstraction, and make it
usable to splice. This cleans up and fixes several aspects of the
internal splice APIs and the pipe code:
- pipes: the allocation and freeing of pipe_inode_info is now more symmetric
and more streamlined with existing kernel practices.
- splice: small micro-optimization: less pointer dereferencing in splice
methods
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Update XFS for the ->splice_read/->splice_write changes.
Signed-off-by: Jens Axboe <axboe@suse.de>
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 122 |
1 files changed, 63 insertions, 59 deletions
diff --git a/fs/splice.c b/fs/splice.c index 9bfd6af0cf45..ed91a62402e0 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -136,34 +136,33 @@ static struct pipe_buf_operations page_cache_pipe_buf_ops = { | |||
136 | * Pipe output worker. This sets up our pipe format with the page cache | 136 | * Pipe output worker. This sets up our pipe format with the page cache |
137 | * pipe buffer operations. Otherwise very similar to the regular pipe_writev(). | 137 | * pipe buffer operations. Otherwise very similar to the regular pipe_writev(). |
138 | */ | 138 | */ |
139 | static ssize_t move_to_pipe(struct inode *inode, struct page **pages, | 139 | static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages, |
140 | int nr_pages, unsigned long offset, | 140 | int nr_pages, unsigned long offset, |
141 | unsigned long len, unsigned int flags) | 141 | unsigned long len, unsigned int flags) |
142 | { | 142 | { |
143 | struct pipe_inode_info *info; | ||
144 | int ret, do_wakeup, i; | 143 | int ret, do_wakeup, i; |
145 | 144 | ||
146 | ret = 0; | 145 | ret = 0; |
147 | do_wakeup = 0; | 146 | do_wakeup = 0; |
148 | i = 0; | 147 | i = 0; |
149 | 148 | ||
150 | mutex_lock(PIPE_MUTEX(*inode)); | 149 | if (pipe->inode) |
150 | mutex_lock(&pipe->inode->i_mutex); | ||
151 | 151 | ||
152 | info = inode->i_pipe; | ||
153 | for (;;) { | 152 | for (;;) { |
154 | int bufs; | 153 | int bufs; |
155 | 154 | ||
156 | if (!PIPE_READERS(*inode)) { | 155 | if (!pipe->readers) { |
157 | send_sig(SIGPIPE, current, 0); | 156 | send_sig(SIGPIPE, current, 0); |
158 | if (!ret) | 157 | if (!ret) |
159 | ret = -EPIPE; | 158 | ret = -EPIPE; |
160 | break; | 159 | break; |
161 | } | 160 | } |
162 | 161 | ||
163 | bufs = info->nrbufs; | 162 | bufs = pipe->nrbufs; |
164 | if (bufs < PIPE_BUFFERS) { | 163 | if (bufs < PIPE_BUFFERS) { |
165 | int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS - 1); | 164 | int newbuf = (pipe->curbuf + bufs) & (PIPE_BUFFERS - 1); |
166 | struct pipe_buffer *buf = info->bufs + newbuf; | 165 | struct pipe_buffer *buf = pipe->bufs + newbuf; |
167 | struct page *page = pages[i++]; | 166 | struct page *page = pages[i++]; |
168 | unsigned long this_len; | 167 | unsigned long this_len; |
169 | 168 | ||
@@ -175,7 +174,7 @@ static ssize_t move_to_pipe(struct inode *inode, struct page **pages, | |||
175 | buf->offset = offset; | 174 | buf->offset = offset; |
176 | buf->len = this_len; | 175 | buf->len = this_len; |
177 | buf->ops = &page_cache_pipe_buf_ops; | 176 | buf->ops = &page_cache_pipe_buf_ops; |
178 | info->nrbufs = ++bufs; | 177 | pipe->nrbufs = ++bufs; |
179 | do_wakeup = 1; | 178 | do_wakeup = 1; |
180 | 179 | ||
181 | ret += this_len; | 180 | ret += this_len; |
@@ -205,25 +204,25 @@ static ssize_t move_to_pipe(struct inode *inode, struct page **pages, | |||
205 | 204 | ||
206 | if (do_wakeup) { | 205 | if (do_wakeup) { |
207 | smp_mb(); | 206 | smp_mb(); |
208 | if (waitqueue_active(PIPE_WAIT(*inode))) | 207 | if (waitqueue_active(&pipe->wait)) |
209 | wake_up_interruptible_sync(PIPE_WAIT(*inode)); | 208 | wake_up_interruptible_sync(&pipe->wait); |
210 | kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, | 209 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); |
211 | POLL_IN); | ||
212 | do_wakeup = 0; | 210 | do_wakeup = 0; |
213 | } | 211 | } |
214 | 212 | ||
215 | PIPE_WAITING_WRITERS(*inode)++; | 213 | pipe->waiting_writers++; |
216 | pipe_wait(inode); | 214 | pipe_wait(pipe); |
217 | PIPE_WAITING_WRITERS(*inode)--; | 215 | pipe->waiting_writers--; |
218 | } | 216 | } |
219 | 217 | ||
220 | mutex_unlock(PIPE_MUTEX(*inode)); | 218 | if (pipe->inode) |
219 | mutex_unlock(&pipe->inode->i_mutex); | ||
221 | 220 | ||
222 | if (do_wakeup) { | 221 | if (do_wakeup) { |
223 | smp_mb(); | 222 | smp_mb(); |
224 | if (waitqueue_active(PIPE_WAIT(*inode))) | 223 | if (waitqueue_active(&pipe->wait)) |
225 | wake_up_interruptible(PIPE_WAIT(*inode)); | 224 | wake_up_interruptible(&pipe->wait); |
226 | kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); | 225 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); |
227 | } | 226 | } |
228 | 227 | ||
229 | while (i < nr_pages) | 228 | while (i < nr_pages) |
@@ -232,8 +231,9 @@ static ssize_t move_to_pipe(struct inode *inode, struct page **pages, | |||
232 | return ret; | 231 | return ret; |
233 | } | 232 | } |
234 | 233 | ||
235 | static int __generic_file_splice_read(struct file *in, struct inode *pipe, | 234 | static int |
236 | size_t len, unsigned int flags) | 235 | __generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, |
236 | size_t len, unsigned int flags) | ||
237 | { | 237 | { |
238 | struct address_space *mapping = in->f_mapping; | 238 | struct address_space *mapping = in->f_mapping; |
239 | unsigned int offset, nr_pages; | 239 | unsigned int offset, nr_pages; |
@@ -298,7 +298,7 @@ static int __generic_file_splice_read(struct file *in, struct inode *pipe, | |||
298 | * Will read pages from given file and fill them into a pipe. | 298 | * Will read pages from given file and fill them into a pipe. |
299 | * | 299 | * |
300 | */ | 300 | */ |
301 | ssize_t generic_file_splice_read(struct file *in, struct inode *pipe, | 301 | ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, |
302 | size_t len, unsigned int flags) | 302 | size_t len, unsigned int flags) |
303 | { | 303 | { |
304 | ssize_t spliced; | 304 | ssize_t spliced; |
@@ -306,6 +306,7 @@ ssize_t generic_file_splice_read(struct file *in, struct inode *pipe, | |||
306 | 306 | ||
307 | ret = 0; | 307 | ret = 0; |
308 | spliced = 0; | 308 | spliced = 0; |
309 | |||
309 | while (len) { | 310 | while (len) { |
310 | ret = __generic_file_splice_read(in, pipe, len, flags); | 311 | ret = __generic_file_splice_read(in, pipe, len, flags); |
311 | 312 | ||
@@ -509,11 +510,10 @@ typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *, | |||
509 | * key here is the 'actor' worker passed in that actually moves the data | 510 | * key here is the 'actor' worker passed in that actually moves the data |
510 | * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. | 511 | * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. |
511 | */ | 512 | */ |
512 | static ssize_t move_from_pipe(struct inode *inode, struct file *out, | 513 | static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, |
513 | size_t len, unsigned int flags, | 514 | size_t len, unsigned int flags, |
514 | splice_actor *actor) | 515 | splice_actor *actor) |
515 | { | 516 | { |
516 | struct pipe_inode_info *info; | ||
517 | int ret, do_wakeup, err; | 517 | int ret, do_wakeup, err; |
518 | struct splice_desc sd; | 518 | struct splice_desc sd; |
519 | 519 | ||
@@ -525,22 +525,22 @@ static ssize_t move_from_pipe(struct inode *inode, struct file *out, | |||
525 | sd.file = out; | 525 | sd.file = out; |
526 | sd.pos = out->f_pos; | 526 | sd.pos = out->f_pos; |
527 | 527 | ||
528 | mutex_lock(PIPE_MUTEX(*inode)); | 528 | if (pipe->inode) |
529 | mutex_lock(&pipe->inode->i_mutex); | ||
529 | 530 | ||
530 | info = inode->i_pipe; | ||
531 | for (;;) { | 531 | for (;;) { |
532 | int bufs = info->nrbufs; | 532 | int bufs = pipe->nrbufs; |
533 | 533 | ||
534 | if (bufs) { | 534 | if (bufs) { |
535 | int curbuf = info->curbuf; | 535 | int curbuf = pipe->curbuf; |
536 | struct pipe_buffer *buf = info->bufs + curbuf; | 536 | struct pipe_buffer *buf = pipe->bufs + curbuf; |
537 | struct pipe_buf_operations *ops = buf->ops; | 537 | struct pipe_buf_operations *ops = buf->ops; |
538 | 538 | ||
539 | sd.len = buf->len; | 539 | sd.len = buf->len; |
540 | if (sd.len > sd.total_len) | 540 | if (sd.len > sd.total_len) |
541 | sd.len = sd.total_len; | 541 | sd.len = sd.total_len; |
542 | 542 | ||
543 | err = actor(info, buf, &sd); | 543 | err = actor(pipe, buf, &sd); |
544 | if (err) { | 544 | if (err) { |
545 | if (!ret && err != -ENODATA) | 545 | if (!ret && err != -ENODATA) |
546 | ret = err; | 546 | ret = err; |
@@ -553,10 +553,10 @@ static ssize_t move_from_pipe(struct inode *inode, struct file *out, | |||
553 | buf->len -= sd.len; | 553 | buf->len -= sd.len; |
554 | if (!buf->len) { | 554 | if (!buf->len) { |
555 | buf->ops = NULL; | 555 | buf->ops = NULL; |
556 | ops->release(info, buf); | 556 | ops->release(pipe, buf); |
557 | curbuf = (curbuf + 1) & (PIPE_BUFFERS - 1); | 557 | curbuf = (curbuf + 1) & (PIPE_BUFFERS - 1); |
558 | info->curbuf = curbuf; | 558 | pipe->curbuf = curbuf; |
559 | info->nrbufs = --bufs; | 559 | pipe->nrbufs = --bufs; |
560 | do_wakeup = 1; | 560 | do_wakeup = 1; |
561 | } | 561 | } |
562 | 562 | ||
@@ -568,9 +568,9 @@ static ssize_t move_from_pipe(struct inode *inode, struct file *out, | |||
568 | 568 | ||
569 | if (bufs) | 569 | if (bufs) |
570 | continue; | 570 | continue; |
571 | if (!PIPE_WRITERS(*inode)) | 571 | if (!pipe->writers) |
572 | break; | 572 | break; |
573 | if (!PIPE_WAITING_WRITERS(*inode)) { | 573 | if (!pipe->waiting_writers) { |
574 | if (ret) | 574 | if (ret) |
575 | break; | 575 | break; |
576 | } | 576 | } |
@@ -589,22 +589,23 @@ static ssize_t move_from_pipe(struct inode *inode, struct file *out, | |||
589 | 589 | ||
590 | if (do_wakeup) { | 590 | if (do_wakeup) { |
591 | smp_mb(); | 591 | smp_mb(); |
592 | if (waitqueue_active(PIPE_WAIT(*inode))) | 592 | if (waitqueue_active(&pipe->wait)) |
593 | wake_up_interruptible_sync(PIPE_WAIT(*inode)); | 593 | wake_up_interruptible_sync(&pipe->wait); |
594 | kill_fasync(PIPE_FASYNC_WRITERS(*inode),SIGIO,POLL_OUT); | 594 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); |
595 | do_wakeup = 0; | 595 | do_wakeup = 0; |
596 | } | 596 | } |
597 | 597 | ||
598 | pipe_wait(inode); | 598 | pipe_wait(pipe); |
599 | } | 599 | } |
600 | 600 | ||
601 | mutex_unlock(PIPE_MUTEX(*inode)); | 601 | if (pipe->inode) |
602 | mutex_unlock(&pipe->inode->i_mutex); | ||
602 | 603 | ||
603 | if (do_wakeup) { | 604 | if (do_wakeup) { |
604 | smp_mb(); | 605 | smp_mb(); |
605 | if (waitqueue_active(PIPE_WAIT(*inode))) | 606 | if (waitqueue_active(&pipe->wait)) |
606 | wake_up_interruptible(PIPE_WAIT(*inode)); | 607 | wake_up_interruptible(&pipe->wait); |
607 | kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); | 608 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); |
608 | } | 609 | } |
609 | 610 | ||
610 | mutex_lock(&out->f_mapping->host->i_mutex); | 611 | mutex_lock(&out->f_mapping->host->i_mutex); |
@@ -616,7 +617,7 @@ static ssize_t move_from_pipe(struct inode *inode, struct file *out, | |||
616 | 617 | ||
617 | /** | 618 | /** |
618 | * generic_file_splice_write - splice data from a pipe to a file | 619 | * generic_file_splice_write - splice data from a pipe to a file |
619 | * @inode: pipe inode | 620 | * @pipe: pipe info |
620 | * @out: file to write to | 621 | * @out: file to write to |
621 | * @len: number of bytes to splice | 622 | * @len: number of bytes to splice |
622 | * @flags: splice modifier flags | 623 | * @flags: splice modifier flags |
@@ -625,11 +626,14 @@ static ssize_t move_from_pipe(struct inode *inode, struct file *out, | |||
625 | * the given pipe inode to the given file. | 626 | * the given pipe inode to the given file. |
626 | * | 627 | * |
627 | */ | 628 | */ |
628 | ssize_t generic_file_splice_write(struct inode *inode, struct file *out, | 629 | ssize_t |
629 | size_t len, unsigned int flags) | 630 | generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, |
631 | size_t len, unsigned int flags) | ||
630 | { | 632 | { |
631 | struct address_space *mapping = out->f_mapping; | 633 | struct address_space *mapping = out->f_mapping; |
632 | ssize_t ret = move_from_pipe(inode, out, len, flags, pipe_to_file); | 634 | ssize_t ret; |
635 | |||
636 | ret = move_from_pipe(pipe, out, len, flags, pipe_to_file); | ||
633 | 637 | ||
634 | /* | 638 | /* |
635 | * if file or inode is SYNC and we actually wrote some data, sync it | 639 | * if file or inode is SYNC and we actually wrote some data, sync it |
@@ -664,10 +668,10 @@ EXPORT_SYMBOL(generic_file_splice_write); | |||
664 | * is involved. | 668 | * is involved. |
665 | * | 669 | * |
666 | */ | 670 | */ |
667 | ssize_t generic_splice_sendpage(struct inode *inode, struct file *out, | 671 | ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, |
668 | size_t len, unsigned int flags) | 672 | size_t len, unsigned int flags) |
669 | { | 673 | { |
670 | return move_from_pipe(inode, out, len, flags, pipe_to_sendpage); | 674 | return move_from_pipe(pipe, out, len, flags, pipe_to_sendpage); |
671 | } | 675 | } |
672 | 676 | ||
673 | EXPORT_SYMBOL(generic_splice_sendpage); | 677 | EXPORT_SYMBOL(generic_splice_sendpage); |
@@ -675,8 +679,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); | |||
675 | /* | 679 | /* |
676 | * Attempt to initiate a splice from pipe to file. | 680 | * Attempt to initiate a splice from pipe to file. |
677 | */ | 681 | */ |
678 | static long do_splice_from(struct inode *pipe, struct file *out, size_t len, | 682 | static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, |
679 | unsigned int flags) | 683 | size_t len, unsigned int flags) |
680 | { | 684 | { |
681 | loff_t pos; | 685 | loff_t pos; |
682 | int ret; | 686 | int ret; |
@@ -698,8 +702,8 @@ static long do_splice_from(struct inode *pipe, struct file *out, size_t len, | |||
698 | /* | 702 | /* |
699 | * Attempt to initiate a splice from a file to a pipe. | 703 | * Attempt to initiate a splice from a file to a pipe. |
700 | */ | 704 | */ |
701 | static long do_splice_to(struct file *in, struct inode *pipe, size_t len, | 705 | static long do_splice_to(struct file *in, struct pipe_inode_info *pipe, |
702 | unsigned int flags) | 706 | size_t len, unsigned int flags) |
703 | { | 707 | { |
704 | loff_t pos, isize, left; | 708 | loff_t pos, isize, left; |
705 | int ret; | 709 | int ret; |
@@ -732,14 +736,14 @@ static long do_splice_to(struct file *in, struct inode *pipe, size_t len, | |||
732 | static long do_splice(struct file *in, struct file *out, size_t len, | 736 | static long do_splice(struct file *in, struct file *out, size_t len, |
733 | unsigned int flags) | 737 | unsigned int flags) |
734 | { | 738 | { |
735 | struct inode *pipe; | 739 | struct pipe_inode_info *pipe; |
736 | 740 | ||
737 | pipe = in->f_dentry->d_inode; | 741 | pipe = in->f_dentry->d_inode->i_pipe; |
738 | if (pipe->i_pipe) | 742 | if (pipe) |
739 | return do_splice_from(pipe, out, len, flags); | 743 | return do_splice_from(pipe, out, len, flags); |
740 | 744 | ||
741 | pipe = out->f_dentry->d_inode; | 745 | pipe = out->f_dentry->d_inode->i_pipe; |
742 | if (pipe->i_pipe) | 746 | if (pipe) |
743 | return do_splice_to(in, pipe, len, flags); | 747 | return do_splice_to(in, pipe, len, flags); |
744 | 748 | ||
745 | return -EINVAL; | 749 | return -EINVAL; |