diff options
Diffstat (limited to 'fs/ocfs2/file.c')
| -rw-r--r-- | fs/ocfs2/file.c | 80 |
1 files changed, 79 insertions, 1 deletions
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 | ||
| 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 | static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, | 1684 | static 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 | ||
| 1638 | out_unlock: | 1716 | out_unlock: |
| 1639 | ocfs2_rw_unlock(inode, 1); | 1717 | ocfs2_rw_unlock(inode, 1); |
