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

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Sergey Bashirov and committed by
Chuck Lever
cc6c40e0 0cd0d15d

+34 -13
+34 -13
fs/nfsd/blocklayout.c
··· 89 89 { 90 90 struct nfsd4_layout_seg *seg = &args->lg_seg; 91 91 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); 95 95 __be32 nfserr; 96 96 97 97 if (locks_in_grace(SVC_NET(rqstp))) ··· 119 119 goto out_error; 120 120 121 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 + 128 + /* 122 129 * Some clients barf on non-zero block numbers for NONE or INVALID 123 130 * layouts, so make sure to zero the whole structure. 124 131 */ ··· 136 129 bl->nr_extents = nr_extents_max; 137 130 args->lg_content = bl; 138 131 139 - bex = &bl->extents[0]; 140 - nfserr = nfsd4_block_map_extent(inode, fhp, seg->offset, seg->length, 141 - seg->iomode, args->lg_minlength, bex); 142 - if (nfserr != nfs_ok) 143 - goto out_error; 132 + for (i = 0; i < bl->nr_extents; i++) { 133 + struct pnfs_block_extent *bex = bl->extents + i; 134 + u64 bex_length; 135 + 136 + nfserr = nfsd4_block_map_extent(inode, fhp, offset, length, 137 + seg->iomode, args->lg_minlength, bex); 138 + if (nfserr != nfs_ok) 139 + goto out_error; 140 + 141 + bex_length = bex->len - (offset - bex->foff); 142 + if (bex_length >= length) { 143 + bl->nr_extents = i + 1; 144 + break; 145 + } 146 + 147 + offset = bex->foff + bex->len; 148 + length -= bex_length; 149 + } 150 + 151 + first_bex = bl->extents; 152 + last_bex = bl->extents + bl->nr_extents - 1; 144 153 145 154 nfserr = nfserr_layoutunavailable; 146 - length = bex->foff + bex->len - seg->offset; 155 + length = last_bex->foff + last_bex->len - seg->offset; 147 156 if (length < args->lg_minlength) { 148 157 dprintk("pnfsd: extent smaller than minlength\n"); 149 158 goto out_error; 150 159 } 151 160 152 - seg->offset = bex->foff; 153 - seg->length = bex->len; 154 - 155 - dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es); 161 + seg->offset = first_bex->foff; 162 + seg->length = last_bex->foff - first_bex->foff + last_bex->len; 156 163 return nfs_ok; 157 164 158 165 out_error: