Skip to content

Commit 08cb5b0

Browse files
bcodding-rhtrondmypd
authored andcommitted
pnfs: Fix the check for requests in range of layout segment
It's possible and acceptable for NFS to attempt to add requests beyond the range of the current pgio->pg_lseg, a case which should be caught and limited by the pg_test operation. However, the current handling of this case replaces pgio->pg_lseg with a new layout segment (after a WARN) within that pg_test operation. That will cause all the previously added requests to be submitted with this new layout segment, which may not be valid for those requests. Fix this problem by only returning zero for the number of bytes to coalesce from pg_test for this case which allows any previously added requests to complete on the current layout segment. The check for requests starting out of range of the layout segment moves to pg_init, so that the replacement of pgio->pg_lseg will be done when the next request is added. Signed-off-by: Benjamin Coddington <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent d2c23c0 commit 08cb5b0

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

fs/nfs/pnfs.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,12 +2094,26 @@ pnfs_generic_pg_check_layout(struct nfs_pageio_descriptor *pgio)
20942094
}
20952095
EXPORT_SYMBOL_GPL(pnfs_generic_pg_check_layout);
20962096

2097+
/*
2098+
* Check for any intersection between the request and the pgio->pg_lseg,
2099+
* and if none, put this pgio->pg_lseg away.
2100+
*/
2101+
static void
2102+
pnfs_generic_pg_check_range(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
2103+
{
2104+
if (pgio->pg_lseg && !pnfs_lseg_request_intersecting(pgio->pg_lseg, req)) {
2105+
pnfs_put_lseg(pgio->pg_lseg);
2106+
pgio->pg_lseg = NULL;
2107+
}
2108+
}
2109+
20972110
void
20982111
pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
20992112
{
21002113
u64 rd_size = req->wb_bytes;
21012114

21022115
pnfs_generic_pg_check_layout(pgio);
2116+
pnfs_generic_pg_check_range(pgio, req);
21032117
if (pgio->pg_lseg == NULL) {
21042118
if (pgio->pg_dreq == NULL)
21052119
rd_size = i_size_read(pgio->pg_inode) - req_offset(req);
@@ -2131,6 +2145,7 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
21312145
struct nfs_page *req, u64 wb_size)
21322146
{
21332147
pnfs_generic_pg_check_layout(pgio);
2148+
pnfs_generic_pg_check_range(pgio, req);
21342149
if (pgio->pg_lseg == NULL) {
21352150
pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
21362151
req->wb_context,
@@ -2191,16 +2206,10 @@ pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio,
21912206
seg_end = pnfs_end_offset(pgio->pg_lseg->pls_range.offset,
21922207
pgio->pg_lseg->pls_range.length);
21932208
req_start = req_offset(req);
2194-
WARN_ON_ONCE(req_start >= seg_end);
2209+
21952210
/* start of request is past the last byte of this segment */
2196-
if (req_start >= seg_end) {
2197-
/* reference the new lseg */
2198-
if (pgio->pg_ops->pg_cleanup)
2199-
pgio->pg_ops->pg_cleanup(pgio);
2200-
if (pgio->pg_ops->pg_init)
2201-
pgio->pg_ops->pg_init(pgio, req);
2211+
if (req_start >= seg_end)
22022212
return 0;
2203-
}
22042213

22052214
/* adjust 'size' iff there are fewer bytes left in the
22062215
* segment than what nfs_generic_pg_test returned */

fs/nfs/pnfs.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,16 @@ pnfs_lseg_range_intersecting(const struct pnfs_layout_range *l1,
593593
return pnfs_is_range_intersecting(l1->offset, end1, l2->offset, end2);
594594
}
595595

596+
static inline bool
597+
pnfs_lseg_request_intersecting(struct pnfs_layout_segment *lseg, struct nfs_page *req)
598+
{
599+
u64 seg_last = pnfs_end_offset(lseg->pls_range.offset, lseg->pls_range.length);
600+
u64 req_last = req_offset(req) + req->wb_bytes;
601+
602+
return pnfs_is_range_intersecting(lseg->pls_range.offset, seg_last,
603+
req_offset(req), req_last);
604+
}
605+
596606
extern unsigned int layoutstats_timer;
597607

598608
#ifdef NFS_DEBUG

0 commit comments

Comments
 (0)