Skip to content

Commit cc6c40e

Browse files
sbashirochucklever
authored andcommitted
NFSD/blocklayout: Support multiple extents per LAYOUTGET
Allow the pNFS server to respond with multiple extents to a LAYOUTGET request, thereby avoiding unnecessary load on the server and improving performance for the client. The number of LAYOUTGET requests is significantly reduced for various file access patterns, including random and parallel writes. Additionally, this change allows the client to request layouts with the loga_minlength value greater than the minimum possible length of a single extent in XFS. We use this functionality to fix a livelock in the client. Signed-off-by: Sergey Bashirov <sergeybashirov@gmail.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 0cd0d15 commit cc6c40e

1 file changed

Lines changed: 34 additions & 13 deletions

File tree

fs/nfsd/blocklayout.c

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
8989
{
9090
struct nfsd4_layout_seg *seg = &args->lg_seg;
9191
struct pnfs_block_layout *bl;
92-
struct pnfs_block_extent *bex;
93-
u64 length;
94-
u32 nr_extents_max = 1, block_size = i_blocksize(inode);
92+
struct pnfs_block_extent *first_bex, *last_bex;
93+
u64 offset = seg->offset, length = seg->length;
94+
u32 i, nr_extents_max, block_size = i_blocksize(inode);
9595
__be32 nfserr;
9696

9797
if (locks_in_grace(SVC_NET(rqstp)))
@@ -118,6 +118,13 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
118118
PNFS_BLOCK_EXTENT_SIZE)
119119
goto out_error;
120120

121+
/*
122+
* Limit the maximum layout size to avoid allocating
123+
* a large buffer on the server for each layout request.
124+
*/
125+
nr_extents_max = (min(args->lg_maxcount, PAGE_SIZE) -
126+
PNFS_BLOCK_LAYOUT4_SIZE) / PNFS_BLOCK_EXTENT_SIZE;
127+
121128
/*
122129
* Some clients barf on non-zero block numbers for NONE or INVALID
123130
* layouts, so make sure to zero the whole structure.
@@ -129,23 +136,37 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
129136
bl->nr_extents = nr_extents_max;
130137
args->lg_content = bl;
131138

132-
bex = &bl->extents[0];
133-
nfserr = nfsd4_block_map_extent(inode, fhp, seg->offset, seg->length,
134-
seg->iomode, args->lg_minlength, bex);
135-
if (nfserr != nfs_ok)
136-
goto out_error;
139+
for (i = 0; i < bl->nr_extents; i++) {
140+
struct pnfs_block_extent *bex = bl->extents + i;
141+
u64 bex_length;
142+
143+
nfserr = nfsd4_block_map_extent(inode, fhp, offset, length,
144+
seg->iomode, args->lg_minlength, bex);
145+
if (nfserr != nfs_ok)
146+
goto out_error;
147+
148+
bex_length = bex->len - (offset - bex->foff);
149+
if (bex_length >= length) {
150+
bl->nr_extents = i + 1;
151+
break;
152+
}
153+
154+
offset = bex->foff + bex->len;
155+
length -= bex_length;
156+
}
157+
158+
first_bex = bl->extents;
159+
last_bex = bl->extents + bl->nr_extents - 1;
137160

138161
nfserr = nfserr_layoutunavailable;
139-
length = bex->foff + bex->len - seg->offset;
162+
length = last_bex->foff + last_bex->len - seg->offset;
140163
if (length < args->lg_minlength) {
141164
dprintk("pnfsd: extent smaller than minlength\n");
142165
goto out_error;
143166
}
144167

145-
seg->offset = bex->foff;
146-
seg->length = bex->len;
147-
148-
dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es);
168+
seg->offset = first_bex->foff;
169+
seg->length = last_bex->foff - first_bex->foff + last_bex->len;
149170
return nfs_ok;
150171

151172
out_error:

0 commit comments

Comments
 (0)