diff options
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 126 |
1 files changed, 25 insertions, 101 deletions
diff --git a/fs/splice.c b/fs/splice.c index 12028fa41def..9bc07d2b53cf 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -136,8 +136,6 @@ error: | |||
136 | 136 | ||
137 | const struct pipe_buf_operations page_cache_pipe_buf_ops = { | 137 | const struct pipe_buf_operations page_cache_pipe_buf_ops = { |
138 | .can_merge = 0, | 138 | .can_merge = 0, |
139 | .map = generic_pipe_buf_map, | ||
140 | .unmap = generic_pipe_buf_unmap, | ||
141 | .confirm = page_cache_pipe_buf_confirm, | 139 | .confirm = page_cache_pipe_buf_confirm, |
142 | .release = page_cache_pipe_buf_release, | 140 | .release = page_cache_pipe_buf_release, |
143 | .steal = page_cache_pipe_buf_steal, | 141 | .steal = page_cache_pipe_buf_steal, |
@@ -156,8 +154,6 @@ static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, | |||
156 | 154 | ||
157 | static const struct pipe_buf_operations user_page_pipe_buf_ops = { | 155 | static const struct pipe_buf_operations user_page_pipe_buf_ops = { |
158 | .can_merge = 0, | 156 | .can_merge = 0, |
159 | .map = generic_pipe_buf_map, | ||
160 | .unmap = generic_pipe_buf_unmap, | ||
161 | .confirm = generic_pipe_buf_confirm, | 157 | .confirm = generic_pipe_buf_confirm, |
162 | .release = page_cache_pipe_buf_release, | 158 | .release = page_cache_pipe_buf_release, |
163 | .steal = user_page_pipe_buf_steal, | 159 | .steal = user_page_pipe_buf_steal, |
@@ -547,8 +543,6 @@ EXPORT_SYMBOL(generic_file_splice_read); | |||
547 | 543 | ||
548 | static const struct pipe_buf_operations default_pipe_buf_ops = { | 544 | static const struct pipe_buf_operations default_pipe_buf_ops = { |
549 | .can_merge = 0, | 545 | .can_merge = 0, |
550 | .map = generic_pipe_buf_map, | ||
551 | .unmap = generic_pipe_buf_unmap, | ||
552 | .confirm = generic_pipe_buf_confirm, | 546 | .confirm = generic_pipe_buf_confirm, |
553 | .release = generic_pipe_buf_release, | 547 | .release = generic_pipe_buf_release, |
554 | .steal = generic_pipe_buf_steal, | 548 | .steal = generic_pipe_buf_steal, |
@@ -564,8 +558,6 @@ static int generic_pipe_buf_nosteal(struct pipe_inode_info *pipe, | |||
564 | /* Pipe buffer operations for a socket and similar. */ | 558 | /* Pipe buffer operations for a socket and similar. */ |
565 | const struct pipe_buf_operations nosteal_pipe_buf_ops = { | 559 | const struct pipe_buf_operations nosteal_pipe_buf_ops = { |
566 | .can_merge = 0, | 560 | .can_merge = 0, |
567 | .map = generic_pipe_buf_map, | ||
568 | .unmap = generic_pipe_buf_unmap, | ||
569 | .confirm = generic_pipe_buf_confirm, | 561 | .confirm = generic_pipe_buf_confirm, |
570 | .release = generic_pipe_buf_release, | 562 | .release = generic_pipe_buf_release, |
571 | .steal = generic_pipe_buf_nosteal, | 563 | .steal = generic_pipe_buf_nosteal, |
@@ -767,13 +759,13 @@ int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
767 | goto out; | 759 | goto out; |
768 | 760 | ||
769 | if (buf->page != page) { | 761 | if (buf->page != page) { |
770 | char *src = buf->ops->map(pipe, buf, 1); | 762 | char *src = kmap_atomic(buf->page); |
771 | char *dst = kmap_atomic(page); | 763 | char *dst = kmap_atomic(page); |
772 | 764 | ||
773 | memcpy(dst + offset, src + buf->offset, this_len); | 765 | memcpy(dst + offset, src + buf->offset, this_len); |
774 | flush_dcache_page(page); | 766 | flush_dcache_page(page); |
775 | kunmap_atomic(dst); | 767 | kunmap_atomic(dst); |
776 | buf->ops->unmap(pipe, buf, src); | 768 | kunmap_atomic(src); |
777 | } | 769 | } |
778 | ret = pagecache_write_end(file, mapping, sd->pos, this_len, this_len, | 770 | ret = pagecache_write_end(file, mapping, sd->pos, this_len, this_len, |
779 | page, fsdata); | 771 | page, fsdata); |
@@ -1067,9 +1059,9 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
1067 | void *data; | 1059 | void *data; |
1068 | loff_t tmp = sd->pos; | 1060 | loff_t tmp = sd->pos; |
1069 | 1061 | ||
1070 | data = buf->ops->map(pipe, buf, 0); | 1062 | data = kmap(buf->page); |
1071 | ret = __kernel_write(sd->u.file, data + buf->offset, sd->len, &tmp); | 1063 | ret = __kernel_write(sd->u.file, data + buf->offset, sd->len, &tmp); |
1072 | buf->ops->unmap(pipe, buf, data); | 1064 | kunmap(buf->page); |
1073 | 1065 | ||
1074 | return ret; | 1066 | return ret; |
1075 | } | 1067 | } |
@@ -1528,116 +1520,48 @@ static int get_iovec_page_array(const struct iovec __user *iov, | |||
1528 | static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | 1520 | static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, |
1529 | struct splice_desc *sd) | 1521 | struct splice_desc *sd) |
1530 | { | 1522 | { |
1531 | char *src; | 1523 | int n = copy_page_to_iter(buf->page, buf->offset, sd->len, sd->u.data); |
1532 | int ret; | 1524 | return n == sd->len ? n : -EFAULT; |
1533 | |||
1534 | /* | ||
1535 | * See if we can use the atomic maps, by prefaulting in the | ||
1536 | * pages and doing an atomic copy | ||
1537 | */ | ||
1538 | if (!fault_in_pages_writeable(sd->u.userptr, sd->len)) { | ||
1539 | src = buf->ops->map(pipe, buf, 1); | ||
1540 | ret = __copy_to_user_inatomic(sd->u.userptr, src + buf->offset, | ||
1541 | sd->len); | ||
1542 | buf->ops->unmap(pipe, buf, src); | ||
1543 | if (!ret) { | ||
1544 | ret = sd->len; | ||
1545 | goto out; | ||
1546 | } | ||
1547 | } | ||
1548 | |||
1549 | /* | ||
1550 | * No dice, use slow non-atomic map and copy | ||
1551 | */ | ||
1552 | src = buf->ops->map(pipe, buf, 0); | ||
1553 | |||
1554 | ret = sd->len; | ||
1555 | if (copy_to_user(sd->u.userptr, src + buf->offset, sd->len)) | ||
1556 | ret = -EFAULT; | ||
1557 | |||
1558 | buf->ops->unmap(pipe, buf, src); | ||
1559 | out: | ||
1560 | if (ret > 0) | ||
1561 | sd->u.userptr += ret; | ||
1562 | return ret; | ||
1563 | } | 1525 | } |
1564 | 1526 | ||
1565 | /* | 1527 | /* |
1566 | * For lack of a better implementation, implement vmsplice() to userspace | 1528 | * For lack of a better implementation, implement vmsplice() to userspace |
1567 | * as a simple copy of the pipes pages to the user iov. | 1529 | * as a simple copy of the pipes pages to the user iov. |
1568 | */ | 1530 | */ |
1569 | static long vmsplice_to_user(struct file *file, const struct iovec __user *iov, | 1531 | static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov, |
1570 | unsigned long nr_segs, unsigned int flags) | 1532 | unsigned long nr_segs, unsigned int flags) |
1571 | { | 1533 | { |
1572 | struct pipe_inode_info *pipe; | 1534 | struct pipe_inode_info *pipe; |
1573 | struct splice_desc sd; | 1535 | struct splice_desc sd; |
1574 | ssize_t size; | ||
1575 | int error; | ||
1576 | long ret; | 1536 | long ret; |
1537 | struct iovec iovstack[UIO_FASTIOV]; | ||
1538 | struct iovec *iov = iovstack; | ||
1539 | struct iov_iter iter; | ||
1540 | ssize_t count = 0; | ||
1577 | 1541 | ||
1578 | pipe = get_pipe_info(file); | 1542 | pipe = get_pipe_info(file); |
1579 | if (!pipe) | 1543 | if (!pipe) |
1580 | return -EBADF; | 1544 | return -EBADF; |
1581 | 1545 | ||
1582 | pipe_lock(pipe); | 1546 | ret = rw_copy_check_uvector(READ, uiov, nr_segs, |
1583 | 1547 | ARRAY_SIZE(iovstack), iovstack, &iov); | |
1584 | error = ret = 0; | 1548 | if (ret <= 0) |
1585 | while (nr_segs) { | 1549 | return ret; |
1586 | void __user *base; | ||
1587 | size_t len; | ||
1588 | |||
1589 | /* | ||
1590 | * Get user address base and length for this iovec. | ||
1591 | */ | ||
1592 | error = get_user(base, &iov->iov_base); | ||
1593 | if (unlikely(error)) | ||
1594 | break; | ||
1595 | error = get_user(len, &iov->iov_len); | ||
1596 | if (unlikely(error)) | ||
1597 | break; | ||
1598 | |||
1599 | /* | ||
1600 | * Sanity check this iovec. 0 read succeeds. | ||
1601 | */ | ||
1602 | if (unlikely(!len)) | ||
1603 | break; | ||
1604 | if (unlikely(!base)) { | ||
1605 | error = -EFAULT; | ||
1606 | break; | ||
1607 | } | ||
1608 | |||
1609 | if (unlikely(!access_ok(VERIFY_WRITE, base, len))) { | ||
1610 | error = -EFAULT; | ||
1611 | break; | ||
1612 | } | ||
1613 | |||
1614 | sd.len = 0; | ||
1615 | sd.total_len = len; | ||
1616 | sd.flags = flags; | ||
1617 | sd.u.userptr = base; | ||
1618 | sd.pos = 0; | ||
1619 | |||
1620 | size = __splice_from_pipe(pipe, &sd, pipe_to_user); | ||
1621 | if (size < 0) { | ||
1622 | if (!ret) | ||
1623 | ret = size; | ||
1624 | |||
1625 | break; | ||
1626 | } | ||
1627 | |||
1628 | ret += size; | ||
1629 | 1550 | ||
1630 | if (size < len) | 1551 | iov_iter_init(&iter, iov, nr_segs, count, 0); |
1631 | break; | ||
1632 | 1552 | ||
1633 | nr_segs--; | 1553 | sd.len = 0; |
1634 | iov++; | 1554 | sd.total_len = count; |
1635 | } | 1555 | sd.flags = flags; |
1556 | sd.u.data = &iter; | ||
1557 | sd.pos = 0; | ||
1636 | 1558 | ||
1559 | pipe_lock(pipe); | ||
1560 | ret = __splice_from_pipe(pipe, &sd, pipe_to_user); | ||
1637 | pipe_unlock(pipe); | 1561 | pipe_unlock(pipe); |
1638 | 1562 | ||
1639 | if (!ret) | 1563 | if (iov != iovstack) |
1640 | ret = error; | 1564 | kfree(iov); |
1641 | 1565 | ||
1642 | return ret; | 1566 | return ret; |
1643 | } | 1567 | } |