Skip to content

Commit db85a9e

Browse files
author
Al Viro
committed
splice: switch get_iovec_page_array() to iov_iter
Signed-off-by: Al Viro <[email protected]>
1 parent e7c3c64 commit db85a9e

File tree

1 file changed

+36
-99
lines changed

1 file changed

+36
-99
lines changed

fs/splice.c

Lines changed: 36 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,106 +1434,32 @@ static long do_splice(struct file *in, loff_t __user *off_in,
14341434
return -EINVAL;
14351435
}
14361436

1437-
/*
1438-
* Map an iov into an array of pages and offset/length tupples. With the
1439-
* partial_page structure, we can map several non-contiguous ranges into
1440-
* our ones pages[] map instead of splitting that operation into pieces.
1441-
* Could easily be exported as a generic helper for other users, in which
1442-
* case one would probably want to add a 'max_nr_pages' parameter as well.
1443-
*/
1444-
static int get_iovec_page_array(const struct iovec __user *iov,
1445-
unsigned int nr_vecs, struct page **pages,
1446-
struct partial_page *partial, bool aligned,
1437+
static int get_iovec_page_array(struct iov_iter *from,
1438+
struct page **pages,
1439+
struct partial_page *partial,
14471440
unsigned int pipe_buffers)
14481441
{
1449-
int buffers = 0, error = 0;
1450-
1451-
while (nr_vecs) {
1452-
unsigned long off, npages;
1453-
struct iovec entry;
1454-
void __user *base;
1455-
size_t len;
1456-
int i;
1457-
1458-
error = -EFAULT;
1459-
if (copy_from_user(&entry, iov, sizeof(entry)))
1460-
break;
1461-
1462-
base = entry.iov_base;
1463-
len = entry.iov_len;
1464-
1465-
/*
1466-
* Sanity check this iovec. 0 read succeeds.
1467-
*/
1468-
error = 0;
1469-
if (unlikely(!len))
1470-
break;
1471-
error = -EFAULT;
1472-
if (!access_ok(VERIFY_READ, base, len))
1473-
break;
1474-
1475-
/*
1476-
* Get this base offset and number of pages, then map
1477-
* in the user pages.
1478-
*/
1479-
off = (unsigned long) base & ~PAGE_MASK;
1480-
1481-
/*
1482-
* If asked for alignment, the offset must be zero and the
1483-
* length a multiple of the PAGE_SIZE.
1484-
*/
1485-
error = -EINVAL;
1486-
if (aligned && (off || len & ~PAGE_MASK))
1487-
break;
1488-
1489-
npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
1490-
if (npages > pipe_buffers - buffers)
1491-
npages = pipe_buffers - buffers;
1492-
1493-
error = get_user_pages_fast((unsigned long)base, npages,
1494-
0, &pages[buffers]);
1495-
1496-
if (unlikely(error <= 0))
1497-
break;
1498-
1499-
/*
1500-
* Fill this contiguous range into the partial page map.
1501-
*/
1502-
for (i = 0; i < error; i++) {
1503-
const int plen = min_t(size_t, len, PAGE_SIZE - off);
1504-
1505-
partial[buffers].offset = off;
1506-
partial[buffers].len = plen;
1507-
1508-
off = 0;
1509-
len -= plen;
1442+
int buffers = 0;
1443+
while (iov_iter_count(from)) {
1444+
ssize_t copied;
1445+
size_t start;
1446+
1447+
copied = iov_iter_get_pages(from, pages + buffers, ~0UL,
1448+
pipe_buffers - buffers, &start);
1449+
if (copied <= 0)
1450+
return buffers ? buffers : copied;
1451+
1452+
iov_iter_advance(from, copied);
1453+
while (copied) {
1454+
int size = min_t(int, copied, PAGE_SIZE - start);
1455+
partial[buffers].offset = start;
1456+
partial[buffers].len = size;
1457+
copied -= size;
1458+
start = 0;
15101459
buffers++;
15111460
}
1512-
1513-
/*
1514-
* We didn't complete this iov, stop here since it probably
1515-
* means we have to move some of this into a pipe to
1516-
* be able to continue.
1517-
*/
1518-
if (len)
1519-
break;
1520-
1521-
/*
1522-
* Don't continue if we mapped fewer pages than we asked for,
1523-
* or if we mapped the max number of pages that we have
1524-
* room for.
1525-
*/
1526-
if (error < npages || buffers == pipe_buffers)
1527-
break;
1528-
1529-
nr_vecs--;
1530-
iov++;
15311461
}
1532-
1533-
if (buffers)
1534-
return buffers;
1535-
1536-
return error;
1462+
return buffers;
15371463
}
15381464

15391465
static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
@@ -1587,10 +1513,13 @@ static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov,
15871513
* as splice-from-memory, where the regular splice is splice-from-file (or
15881514
* to file). In both cases the output is a pipe, naturally.
15891515
*/
1590-
static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
1516+
static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov,
15911517
unsigned long nr_segs, unsigned int flags)
15921518
{
15931519
struct pipe_inode_info *pipe;
1520+
struct iovec iovstack[UIO_FASTIOV];
1521+
struct iovec *iov = iovstack;
1522+
struct iov_iter from;
15941523
struct page *pages[PIPE_DEF_BUFFERS];
15951524
struct partial_page partial[PIPE_DEF_BUFFERS];
15961525
struct splice_pipe_desc spd = {
@@ -1607,18 +1536,26 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
16071536
if (!pipe)
16081537
return -EBADF;
16091538

1610-
if (splice_grow_spd(pipe, &spd))
1539+
ret = import_iovec(WRITE, uiov, nr_segs,
1540+
ARRAY_SIZE(iovstack), &iov, &from);
1541+
if (ret < 0)
1542+
return ret;
1543+
1544+
if (splice_grow_spd(pipe, &spd)) {
1545+
kfree(iov);
16111546
return -ENOMEM;
1547+
}
16121548

1613-
spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages,
1614-
spd.partial, false,
1549+
spd.nr_pages = get_iovec_page_array(&from, spd.pages,
1550+
spd.partial,
16151551
spd.nr_pages_max);
16161552
if (spd.nr_pages <= 0)
16171553
ret = spd.nr_pages;
16181554
else
16191555
ret = splice_to_pipe(pipe, &spd);
16201556

16211557
splice_shrink_spd(&spd);
1558+
kfree(iov);
16221559
return ret;
16231560
}
16241561

0 commit comments

Comments
 (0)