Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iov_iter: saner helper for page array allocation

All call sites of get_pages_array() are essenitally identical now.
Replace with common helper...

Returns number of slots available in resulting array or 0 on OOM;
it's up to the caller to make sure it doesn't ask to zero-entry
array (i.e. neither maxpages nor size are allowed to be zero).

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 3cf42da3 85200084

+32 -45
+32 -45
lib/iov_iter.c
··· 1284 1284 } 1285 1285 EXPORT_SYMBOL(iov_iter_gap_alignment); 1286 1286 1287 - static struct page **get_pages_array(size_t n) 1287 + static int want_pages_array(struct page ***res, size_t size, 1288 + size_t start, unsigned int maxpages) 1288 1289 { 1289 - return kvmalloc_array(n, sizeof(struct page *), GFP_KERNEL); 1290 + unsigned int count = DIV_ROUND_UP(size + start, PAGE_SIZE); 1291 + 1292 + if (count > maxpages) 1293 + count = maxpages; 1294 + WARN_ON(!count); // caller should've prevented that 1295 + if (!*res) { 1296 + *res = kvmalloc_array(count, sizeof(struct page *), GFP_KERNEL); 1297 + if (!*res) 1298 + return 0; 1299 + } 1300 + return count; 1290 1301 } 1291 1302 1292 1303 static ssize_t pipe_get_pages(struct iov_iter *i, ··· 1305 1294 size_t *start) 1306 1295 { 1307 1296 struct pipe_inode_info *pipe = i->pipe; 1308 - unsigned int npages, off; 1297 + unsigned int npages, off, count; 1309 1298 struct page **p; 1310 1299 ssize_t left; 1311 - int count; 1312 1300 1313 1301 if (!sanity(i)) 1314 1302 return -EFAULT; 1315 1303 1316 1304 *start = off = pipe_npages(i, &npages); 1317 - count = DIV_ROUND_UP(maxsize + off, PAGE_SIZE); 1318 - if (count > npages) 1319 - count = npages; 1320 - if (count > maxpages) 1321 - count = maxpages; 1305 + if (!npages) 1306 + return -EFAULT; 1307 + count = want_pages_array(pages, maxsize, off, min(npages, maxpages)); 1308 + if (!count) 1309 + return -ENOMEM; 1322 1310 p = *pages; 1323 - if (!p) { 1324 - *pages = p = get_pages_array(count); 1325 - if (!p) 1326 - return -ENOMEM; 1327 - } 1328 - 1329 1311 left = maxsize; 1330 1312 npages = 0; 1331 1313 if (off) { ··· 1381 1377 struct page ***pages, size_t maxsize, 1382 1378 unsigned maxpages, size_t *_start_offset) 1383 1379 { 1384 - unsigned nr, offset; 1385 - pgoff_t index, count; 1386 - size_t size = maxsize; 1380 + unsigned nr, offset, count; 1381 + pgoff_t index; 1387 1382 loff_t pos; 1388 1383 1389 1384 pos = i->xarray_start + i->iov_offset; ··· 1390 1387 offset = pos & ~PAGE_MASK; 1391 1388 *_start_offset = offset; 1392 1389 1393 - count = DIV_ROUND_UP(size + offset, PAGE_SIZE); 1394 - if (count > maxpages) 1395 - count = maxpages; 1396 - 1397 - if (!*pages) { 1398 - *pages = get_pages_array(count); 1399 - if (!*pages) 1400 - return -ENOMEM; 1401 - } 1402 - 1390 + count = want_pages_array(pages, maxsize, offset, maxpages); 1391 + if (!count) 1392 + return -ENOMEM; 1403 1393 nr = iter_xarray_populate_pages(*pages, i->xarray, index, count); 1404 1394 if (nr == 0) 1405 1395 return 0; ··· 1441 1445 struct page ***pages, size_t maxsize, 1442 1446 unsigned int maxpages, size_t *start) 1443 1447 { 1444 - int n, res; 1448 + unsigned int n; 1445 1449 1446 1450 if (maxsize > i->count) 1447 1451 maxsize = i->count; ··· 1453 1457 if (likely(user_backed_iter(i))) { 1454 1458 unsigned int gup_flags = 0; 1455 1459 unsigned long addr; 1460 + int res; 1456 1461 1457 1462 if (iov_iter_rw(i) != WRITE) 1458 1463 gup_flags |= FOLL_WRITE; ··· 1463 1466 addr = first_iovec_segment(i, &maxsize); 1464 1467 *start = addr % PAGE_SIZE; 1465 1468 addr &= PAGE_MASK; 1466 - n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE); 1467 - if (n > maxpages) 1468 - n = maxpages; 1469 - if (!*pages) { 1470 - *pages = get_pages_array(n); 1471 - if (!*pages) 1472 - return -ENOMEM; 1473 - } 1469 + n = want_pages_array(pages, maxsize, *start, maxpages); 1470 + if (!n) 1471 + return -ENOMEM; 1474 1472 res = get_user_pages_fast(addr, n, gup_flags, *pages); 1475 1473 if (unlikely(res <= 0)) 1476 1474 return res; ··· 1476 1484 struct page *page; 1477 1485 1478 1486 page = first_bvec_segment(i, &maxsize, start); 1479 - n = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE); 1480 - if (n > maxpages) 1481 - n = maxpages; 1487 + n = want_pages_array(pages, maxsize, *start, maxpages); 1488 + if (!n) 1489 + return -ENOMEM; 1482 1490 p = *pages; 1483 - if (!p) { 1484 - *pages = p = get_pages_array(n); 1485 - if (!p) 1486 - return -ENOMEM; 1487 - } 1488 1491 for (int k = 0; k < n; k++) 1489 1492 get_page(*p++ = page++); 1490 1493 return min_t(size_t, maxsize, n * PAGE_SIZE - *start);