diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-02-03 18:19:51 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-04-01 23:19:23 -0400 |
commit | 6130f5315ee80a591285a25957af71621bd0f17e (patch) | |
tree | 4130527b8904bc2e216fc69e9421c7f9ffc1bfbf /fs/splice.c | |
parent | 637b58c2887e5e57850865839cc75f59184b23d1 (diff) |
switch vmsplice_to_user() to copy_page_to_iter()
I've switched the sanity checks on iovec to rw_copy_check_uvector();
we might need to do a local analog, if any behaviour differences are
not actually bugfixes here...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 110 |
1 files changed, 21 insertions, 89 deletions
diff --git a/fs/splice.c b/fs/splice.c index ca3bfbd970f3..9bc07d2b53cf 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -1520,116 +1520,48 @@ static int get_iovec_page_array(const struct iovec __user *iov, | |||
1520 | 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, |
1521 | struct splice_desc *sd) | 1521 | struct splice_desc *sd) |
1522 | { | 1522 | { |
1523 | char *src; | 1523 | int n = copy_page_to_iter(buf->page, buf->offset, sd->len, sd->u.data); |
1524 | int ret; | 1524 | return n == sd->len ? n : -EFAULT; |
1525 | |||
1526 | /* | ||
1527 | * See if we can use the atomic maps, by prefaulting in the | ||
1528 | * pages and doing an atomic copy | ||
1529 | */ | ||
1530 | if (!fault_in_pages_writeable(sd->u.userptr, sd->len)) { | ||
1531 | src = kmap_atomic(buf->page); | ||
1532 | ret = __copy_to_user_inatomic(sd->u.userptr, src + buf->offset, | ||
1533 | sd->len); | ||
1534 | kunmap_atomic(src); | ||
1535 | if (!ret) { | ||
1536 | ret = sd->len; | ||
1537 | goto out; | ||
1538 | } | ||
1539 | } | ||
1540 | |||
1541 | /* | ||
1542 | * No dice, use slow non-atomic map and copy | ||
1543 | */ | ||
1544 | src = kmap(buf->page); | ||
1545 | |||
1546 | ret = sd->len; | ||
1547 | if (copy_to_user(sd->u.userptr, src + buf->offset, sd->len)) | ||
1548 | ret = -EFAULT; | ||
1549 | |||
1550 | kunmap(buf->page); | ||
1551 | out: | ||
1552 | if (ret > 0) | ||
1553 | sd->u.userptr += ret; | ||
1554 | return ret; | ||
1555 | } | 1525 | } |
1556 | 1526 | ||
1557 | /* | 1527 | /* |
1558 | * For lack of a better implementation, implement vmsplice() to userspace | 1528 | * For lack of a better implementation, implement vmsplice() to userspace |
1559 | * 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. |
1560 | */ | 1530 | */ |
1561 | 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, |
1562 | unsigned long nr_segs, unsigned int flags) | 1532 | unsigned long nr_segs, unsigned int flags) |
1563 | { | 1533 | { |
1564 | struct pipe_inode_info *pipe; | 1534 | struct pipe_inode_info *pipe; |
1565 | struct splice_desc sd; | 1535 | struct splice_desc sd; |
1566 | ssize_t size; | ||
1567 | int error; | ||
1568 | 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; | ||
1569 | 1541 | ||
1570 | pipe = get_pipe_info(file); | 1542 | pipe = get_pipe_info(file); |
1571 | if (!pipe) | 1543 | if (!pipe) |
1572 | return -EBADF; | 1544 | return -EBADF; |
1573 | 1545 | ||
1574 | pipe_lock(pipe); | 1546 | ret = rw_copy_check_uvector(READ, uiov, nr_segs, |
1575 | 1547 | ARRAY_SIZE(iovstack), iovstack, &iov); | |
1576 | error = ret = 0; | 1548 | if (ret <= 0) |
1577 | while (nr_segs) { | 1549 | return ret; |
1578 | void __user *base; | ||
1579 | size_t len; | ||
1580 | |||
1581 | /* | ||
1582 | * Get user address base and length for this iovec. | ||
1583 | */ | ||
1584 | error = get_user(base, &iov->iov_base); | ||
1585 | if (unlikely(error)) | ||
1586 | break; | ||
1587 | error = get_user(len, &iov->iov_len); | ||
1588 | if (unlikely(error)) | ||
1589 | break; | ||
1590 | |||
1591 | /* | ||
1592 | * Sanity check this iovec. 0 read succeeds. | ||
1593 | */ | ||
1594 | if (unlikely(!len)) | ||
1595 | break; | ||
1596 | if (unlikely(!base)) { | ||
1597 | error = -EFAULT; | ||
1598 | break; | ||
1599 | } | ||
1600 | |||
1601 | if (unlikely(!access_ok(VERIFY_WRITE, base, len))) { | ||
1602 | error = -EFAULT; | ||
1603 | break; | ||
1604 | } | ||
1605 | |||
1606 | sd.len = 0; | ||
1607 | sd.total_len = len; | ||
1608 | sd.flags = flags; | ||
1609 | sd.u.userptr = base; | ||
1610 | sd.pos = 0; | ||
1611 | |||
1612 | size = __splice_from_pipe(pipe, &sd, pipe_to_user); | ||
1613 | if (size < 0) { | ||
1614 | if (!ret) | ||
1615 | ret = size; | ||
1616 | |||
1617 | break; | ||
1618 | } | ||
1619 | |||
1620 | ret += size; | ||
1621 | 1550 | ||
1622 | if (size < len) | 1551 | iov_iter_init(&iter, iov, nr_segs, count, 0); |
1623 | break; | ||
1624 | 1552 | ||
1625 | nr_segs--; | 1553 | sd.len = 0; |
1626 | iov++; | 1554 | sd.total_len = count; |
1627 | } | 1555 | sd.flags = flags; |
1556 | sd.u.data = &iter; | ||
1557 | sd.pos = 0; | ||
1628 | 1558 | ||
1559 | pipe_lock(pipe); | ||
1560 | ret = __splice_from_pipe(pipe, &sd, pipe_to_user); | ||
1629 | pipe_unlock(pipe); | 1561 | pipe_unlock(pipe); |
1630 | 1562 | ||
1631 | if (!ret) | 1563 | if (iov != iovstack) |
1632 | ret = error; | 1564 | kfree(iov); |
1633 | 1565 | ||
1634 | return ret; | 1566 | return ret; |
1635 | } | 1567 | } |