diff options
-rw-r--r-- | fs/nfs/pnfs.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index ce46a417e500..ee60c42b72b3 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -1433,33 +1433,37 @@ pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | |||
1433 | struct nfs_page *req) | 1433 | struct nfs_page *req) |
1434 | { | 1434 | { |
1435 | unsigned int size; | 1435 | unsigned int size; |
1436 | u64 end; | 1436 | u64 seg_end, req_start, seg_left; |
1437 | 1437 | ||
1438 | size = nfs_generic_pg_test(pgio, prev, req); | 1438 | size = nfs_generic_pg_test(pgio, prev, req); |
1439 | if (!size) | 1439 | if (!size) |
1440 | return 0; | 1440 | return 0; |
1441 | 1441 | ||
1442 | /* | 1442 | /* |
1443 | * Test if a nfs_page is fully contained in the pnfs_layout_range. | 1443 | * 'size' contains the number of bytes left in the current page (up |
1444 | * Note that this test makes several assumptions: | 1444 | * to the original size asked for in @req->wb_bytes). |
1445 | * - that the previous nfs_page in the struct nfs_pageio_descriptor | 1445 | * |
1446 | * is known to lie within the range. | 1446 | * Calculate how many bytes are left in the layout segment |
1447 | * - that the nfs_page being tested is known to be contiguous with the | 1447 | * and if there are less bytes than 'size', return that instead. |
1448 | * previous nfs_page. | ||
1449 | * - Layout ranges are page aligned, so we only have to test the | ||
1450 | * start offset of the request. | ||
1451 | * | 1448 | * |
1452 | * Please also note that 'end_offset' is actually the offset of the | 1449 | * Please also note that 'end_offset' is actually the offset of the |
1453 | * first byte that lies outside the pnfs_layout_range. FIXME? | 1450 | * first byte that lies outside the pnfs_layout_range. FIXME? |
1454 | * | 1451 | * |
1455 | */ | 1452 | */ |
1456 | if (pgio->pg_lseg) { | 1453 | if (pgio->pg_lseg) { |
1457 | end = end_offset(pgio->pg_lseg->pls_range.offset, | 1454 | seg_end = end_offset(pgio->pg_lseg->pls_range.offset, |
1458 | pgio->pg_lseg->pls_range.length); | 1455 | pgio->pg_lseg->pls_range.length); |
1459 | WARN_ON_ONCE(req_offset(req) > end); | 1456 | req_start = req_offset(req); |
1460 | if (req_offset(req) >= end) | 1457 | WARN_ON_ONCE(req_start > seg_end); |
1458 | /* start of request is past the last byte of this segment */ | ||
1459 | if (req_start >= seg_end) | ||
1461 | return 0; | 1460 | return 0; |
1462 | size = min((unsigned int)(end - req_offset(req)), size); | 1461 | |
1462 | /* adjust 'size' iff there are fewer bytes left in the | ||
1463 | * segment than what nfs_generic_pg_test returned */ | ||
1464 | seg_left = seg_end - req_start; | ||
1465 | if (seg_left < size) | ||
1466 | size = (unsigned int)seg_left; | ||
1463 | } | 1467 | } |
1464 | 1468 | ||
1465 | return size; | 1469 | return size; |