aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorMark Fasheh <mark.fasheh@oracle.com>2007-03-06 20:24:46 -0500
committerMark Fasheh <mark.fasheh@oracle.com>2007-04-26 18:02:34 -0400
commit6af67d8205cf65fbaaa743edc7ebb46e486e34ff (patch)
tree1aadef5c71e4f8905477a813b1bd0a35e62ccbee /fs/ocfs2
parentfa41045fcbf78269991d5aebb1820fc51534f05d (diff)
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>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/aops.c69
-rw-r--r--fs/ocfs2/aops.h14
-rw-r--r--fs/ocfs2/file.c80
3 files changed, 162 insertions, 1 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 605c82a93f01..014f4f52809c 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -25,6 +25,7 @@
25#include <linux/pagemap.h> 25#include <linux/pagemap.h>
26#include <asm/byteorder.h> 26#include <asm/byteorder.h>
27#include <linux/swap.h> 27#include <linux/swap.h>
28#include <linux/pipe_fs_i.h>
28 29
29#define MLOG_MASK_PREFIX ML_FILE_IO 30#define MLOG_MASK_PREFIX ML_FILE_IO
30#include <cluster/masklog.h> 31#include <cluster/masklog.h>
@@ -749,6 +750,74 @@ next_bh:
749} 750}
750 751
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 */
759int 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;
815out:
816
817 return bytes ? (unsigned int)bytes : ret;
818}
819
820/*
752 * This will copy user data from the iovec in the buffered write 821 * This will copy user data from the iovec in the buffered write
753 * context. 822 * context.
754 */ 823 */
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h
index 7d94071f0ab7..1b4ba5356a42 100644
--- a/fs/ocfs2/aops.h
+++ b/fs/ocfs2/aops.h
@@ -80,6 +80,20 @@ int ocfs2_map_and_write_user_data(struct inode *inode,
80 unsigned int *ret_from, 80 unsigned int *ret_from,
81 unsigned int *ret_to); 81 unsigned int *ret_to);
82 82
83struct 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};
91int 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/* all ocfs2_dio_end_io()'s fault */ 97/* all ocfs2_dio_end_io()'s fault */
84#define ocfs2_iocb_is_rw_locked(iocb) \ 98#define ocfs2_iocb_is_rw_locked(iocb) \
85 test_bit(0, (unsigned long *)&iocb->private) 99 test_bit(0, (unsigned long *)&iocb->private)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 5fd49ec169dc..f516619a3744 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1603,6 +1603,84 @@ out_sems:
1603 return written ? written : ret; 1603 return written ? written : ret;
1604} 1604}
1605 1605
1606static 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;
1653out:
1654
1655 return total ? total : ret;
1656}
1657
1658static 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
1606static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, 1684static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
1607 struct file *out, 1685 struct file *out,
1608 loff_t *ppos, 1686 loff_t *ppos,
@@ -1633,7 +1711,7 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
1633 } 1711 }
1634 1712
1635 /* ok, we're done with i_size and alloc work */ 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
1638out_unlock: 1716out_unlock:
1639 ocfs2_rw_unlock(inode, 1); 1717 ocfs2_rw_unlock(inode, 1);