Commit 6af67d8205cf65fbaaa743edc7ebb46e486e34ff

Authored by Mark Fasheh
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

... ... @@ -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 /*
... ... @@ -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)
... ... @@ -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);