aboutsummaryrefslogtreecommitdiffstats
path: root/fs/splice.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-02-03 18:19:51 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-04-01 23:19:23 -0400
commit6130f5315ee80a591285a25957af71621bd0f17e (patch)
tree4130527b8904bc2e216fc69e9421c7f9ffc1bfbf /fs/splice.c
parent637b58c2887e5e57850865839cc75f59184b23d1 (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.c110
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,
1520static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, 1520static 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);
1551out:
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 */
1561static long vmsplice_to_user(struct file *file, const struct iovec __user *iov, 1531static 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}