Skip to content

Commit 6c77676

Browse files
dhowellsAl Viro
authored andcommitted
iov_iter: Fix iter_xarray_get_pages{,_alloc}()
The maths at the end of iter_xarray_get_pages() to calculate the actual size doesn't work under some circumstances, such as when it's been asked to extract a partial single page. Various terms of the equation cancel out and you end up with actual == offset. The same issue exists in iter_xarray_get_pages_alloc(). Fix these to just use min() to select the lesser amount from between the amount of page content transcribed into the buffer, minus the offset, and the size limit specified. This doesn't appear to have caused a problem yet upstream because network filesystems aren't getting the pages from an xarray iterator, but rather passing it directly to the socket, which just iterates over it. Cachefiles *does* do DIO from one to/from ext4/xfs/btrfs/etc. but it always asks for whole pages to be written or read. Fixes: 7ff5062 ("iov_iter: Add ITER_XARRAY") Reported-by: Jeff Layton <[email protected]> Signed-off-by: David Howells <[email protected]> cc: Alexander Viro <[email protected]> cc: Dominique Martinet <[email protected]> cc: Mike Marshall <[email protected]> cc: Gao Xiang <[email protected]> cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] Signed-off-by: Al Viro <[email protected]>
1 parent f2906aa commit 6c77676

File tree

1 file changed

+4
-16
lines changed

1 file changed

+4
-16
lines changed

lib/iov_iter.c

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,7 +1434,7 @@ static ssize_t iter_xarray_get_pages(struct iov_iter *i,
14341434
{
14351435
unsigned nr, offset;
14361436
pgoff_t index, count;
1437-
size_t size = maxsize, actual;
1437+
size_t size = maxsize;
14381438
loff_t pos;
14391439

14401440
if (!size || !maxpages)
@@ -1461,13 +1461,7 @@ static ssize_t iter_xarray_get_pages(struct iov_iter *i,
14611461
if (nr == 0)
14621462
return 0;
14631463

1464-
actual = PAGE_SIZE * nr;
1465-
actual -= offset;
1466-
if (nr == count && size > 0) {
1467-
unsigned last_offset = (nr > 1) ? 0 : offset;
1468-
actual -= PAGE_SIZE - (last_offset + size);
1469-
}
1470-
return actual;
1464+
return min(nr * PAGE_SIZE - offset, maxsize);
14711465
}
14721466

14731467
/* must be done on non-empty ITER_IOVEC one */
@@ -1602,7 +1596,7 @@ static ssize_t iter_xarray_get_pages_alloc(struct iov_iter *i,
16021596
struct page **p;
16031597
unsigned nr, offset;
16041598
pgoff_t index, count;
1605-
size_t size = maxsize, actual;
1599+
size_t size = maxsize;
16061600
loff_t pos;
16071601

16081602
if (!size)
@@ -1631,13 +1625,7 @@ static ssize_t iter_xarray_get_pages_alloc(struct iov_iter *i,
16311625
if (nr == 0)
16321626
return 0;
16331627

1634-
actual = PAGE_SIZE * nr;
1635-
actual -= offset;
1636-
if (nr == count && size > 0) {
1637-
unsigned last_offset = (nr > 1) ? 0 : offset;
1638-
actual -= PAGE_SIZE - (last_offset + size);
1639-
}
1640-
return actual;
1628+
return min(nr * PAGE_SIZE - offset, maxsize);
16411629
}
16421630

16431631
ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,

0 commit comments

Comments
 (0)