Commit 6af67d8205cf65fbaaa743edc7ebb46e486e34ff
1 parent
fa41045fcb
ocfs2: Use own splice write actor
We need to fill holes during a splice write. Provide our own splice write actor which can call ocfs2_file_buffered_write() with a splice-specific callback. Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Showing 3 changed files with 162 additions and 1 deletions Side-by-side Diff
fs/ocfs2/aops.c
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | #include <linux/pagemap.h> |
26 | 26 | #include <asm/byteorder.h> |
27 | 27 | #include <linux/swap.h> |
28 | +#include <linux/pipe_fs_i.h> | |
28 | 29 | |
29 | 30 | #define MLOG_MASK_PREFIX ML_FILE_IO |
30 | 31 | #include <cluster/masklog.h> |
... | ... | @@ -746,6 +747,74 @@ |
746 | 747 | } while (bh != head); |
747 | 748 | |
748 | 749 | return ret; |
750 | +} | |
751 | + | |
752 | +/* | |
753 | + * This will copy user data from the buffer page in the splice | |
754 | + * context. | |
755 | + * | |
756 | + * For now, we ignore SPLICE_F_MOVE as that would require some extra | |
757 | + * communication out all the way to ocfs2_write(). | |
758 | + */ | |
759 | +int ocfs2_map_and_write_splice_data(struct inode *inode, | |
760 | + struct ocfs2_write_ctxt *wc, u64 *p_blkno, | |
761 | + unsigned int *ret_from, unsigned int *ret_to) | |
762 | +{ | |
763 | + int ret; | |
764 | + unsigned int to, from, cluster_start, cluster_end; | |
765 | + char *src, *dst; | |
766 | + struct ocfs2_splice_write_priv *sp = wc->w_private; | |
767 | + struct pipe_buffer *buf = sp->s_buf; | |
768 | + unsigned long bytes, src_from; | |
769 | + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
770 | + | |
771 | + ocfs2_figure_cluster_boundaries(osb, wc->w_cpos, &cluster_start, | |
772 | + &cluster_end); | |
773 | + | |
774 | + from = sp->s_offset; | |
775 | + src_from = sp->s_buf_offset; | |
776 | + bytes = wc->w_count; | |
777 | + | |
778 | + if (wc->w_large_pages) { | |
779 | + /* | |
780 | + * For cluster size < page size, we have to | |
781 | + * calculate pos within the cluster and obey | |
782 | + * the rightmost boundary. | |
783 | + */ | |
784 | + bytes = min(bytes, (unsigned long)(osb->s_clustersize | |
785 | + - (wc->w_pos & (osb->s_clustersize - 1)))); | |
786 | + } | |
787 | + to = from + bytes; | |
788 | + | |
789 | + if (wc->w_this_page_new) | |
790 | + ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode, | |
791 | + cluster_start, cluster_end, 1); | |
792 | + else | |
793 | + ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode, | |
794 | + from, to, 0); | |
795 | + if (ret) { | |
796 | + mlog_errno(ret); | |
797 | + goto out; | |
798 | + } | |
799 | + | |
800 | + BUG_ON(from > PAGE_CACHE_SIZE); | |
801 | + BUG_ON(to > PAGE_CACHE_SIZE); | |
802 | + BUG_ON(from > osb->s_clustersize); | |
803 | + BUG_ON(to > osb->s_clustersize); | |
804 | + | |
805 | + src = buf->ops->map(sp->s_pipe, buf, 1); | |
806 | + dst = kmap_atomic(wc->w_this_page, KM_USER1); | |
807 | + memcpy(dst + from, src + src_from, bytes); | |
808 | + kunmap_atomic(wc->w_this_page, KM_USER1); | |
809 | + buf->ops->unmap(sp->s_pipe, buf, src); | |
810 | + | |
811 | + wc->w_finished_copy = 1; | |
812 | + | |
813 | + *ret_from = from; | |
814 | + *ret_to = to; | |
815 | +out: | |
816 | + | |
817 | + return bytes ? (unsigned int)bytes : ret; | |
749 | 818 | } |
750 | 819 | |
751 | 820 | /* |
fs/ocfs2/aops.h
... | ... | @@ -80,6 +80,20 @@ |
80 | 80 | unsigned int *ret_from, |
81 | 81 | unsigned int *ret_to); |
82 | 82 | |
83 | +struct ocfs2_splice_write_priv { | |
84 | + struct splice_desc *s_sd; | |
85 | + struct pipe_buffer *s_buf; | |
86 | + struct pipe_inode_info *s_pipe; | |
87 | + /* Neither offset value is ever larger than one page */ | |
88 | + unsigned int s_offset; | |
89 | + unsigned int s_buf_offset; | |
90 | +}; | |
91 | +int ocfs2_map_and_write_splice_data(struct inode *inode, | |
92 | + struct ocfs2_write_ctxt *wc, | |
93 | + u64 *p_blkno, | |
94 | + unsigned int *ret_from, | |
95 | + unsigned int *ret_to); | |
96 | + | |
83 | 97 | /* all ocfs2_dio_end_io()'s fault */ |
84 | 98 | #define ocfs2_iocb_is_rw_locked(iocb) \ |
85 | 99 | test_bit(0, (unsigned long *)&iocb->private) |
fs/ocfs2/file.c
... | ... | @@ -1603,6 +1603,84 @@ |
1603 | 1603 | return written ? written : ret; |
1604 | 1604 | } |
1605 | 1605 | |
1606 | +static int ocfs2_splice_write_actor(struct pipe_inode_info *pipe, | |
1607 | + struct pipe_buffer *buf, | |
1608 | + struct splice_desc *sd) | |
1609 | +{ | |
1610 | + int ret, count, total = 0; | |
1611 | + ssize_t copied = 0; | |
1612 | + struct ocfs2_splice_write_priv sp; | |
1613 | + | |
1614 | + ret = buf->ops->pin(pipe, buf); | |
1615 | + if (ret) | |
1616 | + goto out; | |
1617 | + | |
1618 | + sp.s_sd = sd; | |
1619 | + sp.s_buf = buf; | |
1620 | + sp.s_pipe = pipe; | |
1621 | + sp.s_offset = sd->pos & ~PAGE_CACHE_MASK; | |
1622 | + sp.s_buf_offset = buf->offset; | |
1623 | + | |
1624 | + count = sd->len; | |
1625 | + if (count + sp.s_offset > PAGE_CACHE_SIZE) | |
1626 | + count = PAGE_CACHE_SIZE - sp.s_offset; | |
1627 | + | |
1628 | + do { | |
1629 | + /* | |
1630 | + * splice wants us to copy up to one page at a | |
1631 | + * time. For pagesize > cluster size, this means we | |
1632 | + * might enter ocfs2_buffered_write_cluster() more | |
1633 | + * than once, so keep track of our progress here. | |
1634 | + */ | |
1635 | + copied = ocfs2_buffered_write_cluster(sd->file, | |
1636 | + (loff_t)sd->pos + total, | |
1637 | + count, | |
1638 | + ocfs2_map_and_write_splice_data, | |
1639 | + &sp); | |
1640 | + if (copied < 0) { | |
1641 | + mlog_errno(copied); | |
1642 | + ret = copied; | |
1643 | + goto out; | |
1644 | + } | |
1645 | + | |
1646 | + count -= copied; | |
1647 | + sp.s_offset += copied; | |
1648 | + sp.s_buf_offset += copied; | |
1649 | + total += copied; | |
1650 | + } while (count); | |
1651 | + | |
1652 | + ret = 0; | |
1653 | +out: | |
1654 | + | |
1655 | + return total ? total : ret; | |
1656 | +} | |
1657 | + | |
1658 | +static ssize_t __ocfs2_file_splice_write(struct pipe_inode_info *pipe, | |
1659 | + struct file *out, | |
1660 | + loff_t *ppos, | |
1661 | + size_t len, | |
1662 | + unsigned int flags) | |
1663 | +{ | |
1664 | + int ret, err; | |
1665 | + struct address_space *mapping = out->f_mapping; | |
1666 | + struct inode *inode = mapping->host; | |
1667 | + | |
1668 | + ret = __splice_from_pipe(pipe, out, ppos, len, flags, | |
1669 | + ocfs2_splice_write_actor); | |
1670 | + if (ret > 0) { | |
1671 | + *ppos += ret; | |
1672 | + | |
1673 | + if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { | |
1674 | + err = generic_osync_inode(inode, mapping, | |
1675 | + OSYNC_METADATA|OSYNC_DATA); | |
1676 | + if (err) | |
1677 | + ret = err; | |
1678 | + } | |
1679 | + } | |
1680 | + | |
1681 | + return ret; | |
1682 | +} | |
1683 | + | |
1606 | 1684 | static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, |
1607 | 1685 | struct file *out, |
1608 | 1686 | loff_t *ppos, |
... | ... | @@ -1633,7 +1711,7 @@ |
1633 | 1711 | } |
1634 | 1712 | |
1635 | 1713 | /* ok, we're done with i_size and alloc work */ |
1636 | - ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags); | |
1714 | + ret = __ocfs2_file_splice_write(pipe, out, ppos, len, flags); | |
1637 | 1715 | |
1638 | 1716 | out_unlock: |
1639 | 1717 | ocfs2_rw_unlock(inode, 1); |