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

NFSD/blocklayout: Introduce layout content structure

Add a layout content structure instead of a single extent. The ability
to store and encode an array of extents is then used to implement support
for multiple extents per LAYOUTGET.

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
0cd0d15d a1dce715

+63 -13
+22 -4
fs/nfsd/blocklayout.c
··· 88 88 const struct svc_fh *fhp, struct nfsd4_layoutget *args) 89 89 { 90 90 struct nfsd4_layout_seg *seg = &args->lg_seg; 91 + struct pnfs_block_layout *bl; 91 92 struct pnfs_block_extent *bex; 92 93 u64 length; 93 - u32 block_size = i_blocksize(inode); 94 + u32 nr_extents_max = 1, block_size = i_blocksize(inode); 94 95 __be32 nfserr; 95 96 96 97 if (locks_in_grace(SVC_NET(rqstp))) ··· 104 103 } 105 104 106 105 /* 106 + * RFC 8881, section 3.3.17: 107 + * The layout4 data type defines a layout for a file. 108 + * 109 + * RFC 8881, section 18.43.3: 110 + * The loga_maxcount field specifies the maximum layout size 111 + * (in bytes) that the client can handle. If the size of the 112 + * layout structure exceeds the size specified by maxcount, 113 + * the metadata server will return the NFS4ERR_TOOSMALL error. 114 + */ 115 + nfserr = nfserr_toosmall; 116 + if (args->lg_maxcount < PNFS_BLOCK_LAYOUT4_SIZE + 117 + PNFS_BLOCK_EXTENT_SIZE) 118 + goto out_error; 119 + 120 + /* 107 121 * Some clients barf on non-zero block numbers for NONE or INVALID 108 122 * layouts, so make sure to zero the whole structure. 109 123 */ 110 124 nfserr = nfserrno(-ENOMEM); 111 - bex = kzalloc(sizeof(*bex), GFP_KERNEL); 112 - if (!bex) 125 + bl = kzalloc(struct_size(bl, extents, nr_extents_max), GFP_KERNEL); 126 + if (!bl) 113 127 goto out_error; 114 - args->lg_content = bex; 128 + bl->nr_extents = nr_extents_max; 129 + args->lg_content = bl; 115 130 131 + bex = &bl->extents[0]; 116 132 nfserr = nfsd4_block_map_extent(inode, fhp, seg->offset, seg->length, 117 133 seg->iomode, args->lg_minlength, bex); 118 134 if (nfserr != nfs_ok)
+27 -9
fs/nfsd/blocklayoutxdr.c
··· 14 14 #define NFSDDBG_FACILITY NFSDDBG_PNFS 15 15 16 16 17 + /** 18 + * nfsd4_block_encode_layoutget - encode block/scsi layout extent array 19 + * @xdr: stream for data encoding 20 + * @lgp: layoutget content, actually an array of extents to encode 21 + * 22 + * Encode the opaque loc_body field in the layoutget response. Since the 23 + * pnfs_block_layout4 and pnfs_scsi_layout4 structures on the wire are 24 + * the same, this function is used by both layout drivers. 25 + * 26 + * Return values: 27 + * %nfs_ok: Success, all extents encoded into @xdr 28 + * %nfserr_toosmall: Not enough space in @xdr to encode all the data 29 + */ 17 30 __be32 18 31 nfsd4_block_encode_layoutget(struct xdr_stream *xdr, 19 32 const struct nfsd4_layoutget *lgp) 20 33 { 21 - const struct pnfs_block_extent *b = lgp->lg_content; 22 - int len = sizeof(__be32) + 5 * sizeof(__be64) + sizeof(__be32); 34 + const struct pnfs_block_layout *bl = lgp->lg_content; 35 + u32 i, len = sizeof(__be32) + bl->nr_extents * PNFS_BLOCK_EXTENT_SIZE; 23 36 __be32 *p; 24 37 25 38 p = xdr_reserve_space(xdr, sizeof(__be32) + len); ··· 40 27 return nfserr_toosmall; 41 28 42 29 *p++ = cpu_to_be32(len); 43 - *p++ = cpu_to_be32(1); /* we always return a single extent */ 30 + *p++ = cpu_to_be32(bl->nr_extents); 44 31 45 - p = svcxdr_encode_deviceid4(p, &b->vol_id); 46 - p = xdr_encode_hyper(p, b->foff); 47 - p = xdr_encode_hyper(p, b->len); 48 - p = xdr_encode_hyper(p, b->soff); 49 - *p++ = cpu_to_be32(b->es); 50 - return 0; 32 + for (i = 0; i < bl->nr_extents; i++) { 33 + const struct pnfs_block_extent *bex = bl->extents + i; 34 + 35 + p = svcxdr_encode_deviceid4(p, &bex->vol_id); 36 + p = xdr_encode_hyper(p, bex->foff); 37 + p = xdr_encode_hyper(p, bex->len); 38 + p = xdr_encode_hyper(p, bex->soff); 39 + *p++ = cpu_to_be32(bex->es); 40 + } 41 + 42 + return nfs_ok; 51 43 } 52 44 53 45 static int
+14
fs/nfsd/blocklayoutxdr.h
··· 8 8 struct iomap; 9 9 struct xdr_stream; 10 10 11 + /* On the wire size of the layout4 struct with zero number of extents */ 12 + #define PNFS_BLOCK_LAYOUT4_SIZE \ 13 + (sizeof(__be32) * 2 + /* offset4 */ \ 14 + sizeof(__be32) * 2 + /* length4 */ \ 15 + sizeof(__be32) + /* layoutiomode4 */ \ 16 + sizeof(__be32) + /* layouttype4 */ \ 17 + sizeof(__be32) + /* number of bytes */ \ 18 + sizeof(__be32)) /* number of extents */ 19 + 11 20 struct pnfs_block_extent { 12 21 struct nfsd4_deviceid vol_id; 13 22 u64 foff; ··· 28 19 struct pnfs_block_range { 29 20 u64 foff; 30 21 u64 len; 22 + }; 23 + 24 + struct pnfs_block_layout { 25 + u32 nr_extents; 26 + struct pnfs_block_extent extents[] __counted_by(nr_extents); 31 27 }; 32 28 33 29 /*