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>pull/1354/merge
parent
a1dce715c6
commit
0cd0d15d47
|
|
@ -88,9 +88,10 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
|
|||
const struct svc_fh *fhp, struct nfsd4_layoutget *args)
|
||||
{
|
||||
struct nfsd4_layout_seg *seg = &args->lg_seg;
|
||||
struct pnfs_block_layout *bl;
|
||||
struct pnfs_block_extent *bex;
|
||||
u64 length;
|
||||
u32 block_size = i_blocksize(inode);
|
||||
u32 nr_extents_max = 1, block_size = i_blocksize(inode);
|
||||
__be32 nfserr;
|
||||
|
||||
if (locks_in_grace(SVC_NET(rqstp)))
|
||||
|
|
@ -102,16 +103,33 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
|
|||
goto out_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 8881, section 3.3.17:
|
||||
* The layout4 data type defines a layout for a file.
|
||||
*
|
||||
* RFC 8881, section 18.43.3:
|
||||
* The loga_maxcount field specifies the maximum layout size
|
||||
* (in bytes) that the client can handle. If the size of the
|
||||
* layout structure exceeds the size specified by maxcount,
|
||||
* the metadata server will return the NFS4ERR_TOOSMALL error.
|
||||
*/
|
||||
nfserr = nfserr_toosmall;
|
||||
if (args->lg_maxcount < PNFS_BLOCK_LAYOUT4_SIZE +
|
||||
PNFS_BLOCK_EXTENT_SIZE)
|
||||
goto out_error;
|
||||
|
||||
/*
|
||||
* Some clients barf on non-zero block numbers for NONE or INVALID
|
||||
* layouts, so make sure to zero the whole structure.
|
||||
*/
|
||||
nfserr = nfserrno(-ENOMEM);
|
||||
bex = kzalloc(sizeof(*bex), GFP_KERNEL);
|
||||
if (!bex)
|
||||
bl = kzalloc(struct_size(bl, extents, nr_extents_max), GFP_KERNEL);
|
||||
if (!bl)
|
||||
goto out_error;
|
||||
args->lg_content = bex;
|
||||
bl->nr_extents = nr_extents_max;
|
||||
args->lg_content = bl;
|
||||
|
||||
bex = &bl->extents[0];
|
||||
nfserr = nfsd4_block_map_extent(inode, fhp, seg->offset, seg->length,
|
||||
seg->iomode, args->lg_minlength, bex);
|
||||
if (nfserr != nfs_ok)
|
||||
|
|
|
|||
|
|
@ -14,12 +14,25 @@
|
|||
#define NFSDDBG_FACILITY NFSDDBG_PNFS
|
||||
|
||||
|
||||
/**
|
||||
* nfsd4_block_encode_layoutget - encode block/scsi layout extent array
|
||||
* @xdr: stream for data encoding
|
||||
* @lgp: layoutget content, actually an array of extents to encode
|
||||
*
|
||||
* Encode the opaque loc_body field in the layoutget response. Since the
|
||||
* pnfs_block_layout4 and pnfs_scsi_layout4 structures on the wire are
|
||||
* the same, this function is used by both layout drivers.
|
||||
*
|
||||
* Return values:
|
||||
* %nfs_ok: Success, all extents encoded into @xdr
|
||||
* %nfserr_toosmall: Not enough space in @xdr to encode all the data
|
||||
*/
|
||||
__be32
|
||||
nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
|
||||
const struct nfsd4_layoutget *lgp)
|
||||
{
|
||||
const struct pnfs_block_extent *b = lgp->lg_content;
|
||||
int len = sizeof(__be32) + 5 * sizeof(__be64) + sizeof(__be32);
|
||||
const struct pnfs_block_layout *bl = lgp->lg_content;
|
||||
u32 i, len = sizeof(__be32) + bl->nr_extents * PNFS_BLOCK_EXTENT_SIZE;
|
||||
__be32 *p;
|
||||
|
||||
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
|
||||
|
|
@ -27,14 +40,19 @@ nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
|
|||
return nfserr_toosmall;
|
||||
|
||||
*p++ = cpu_to_be32(len);
|
||||
*p++ = cpu_to_be32(1); /* we always return a single extent */
|
||||
*p++ = cpu_to_be32(bl->nr_extents);
|
||||
|
||||
p = svcxdr_encode_deviceid4(p, &b->vol_id);
|
||||
p = xdr_encode_hyper(p, b->foff);
|
||||
p = xdr_encode_hyper(p, b->len);
|
||||
p = xdr_encode_hyper(p, b->soff);
|
||||
*p++ = cpu_to_be32(b->es);
|
||||
return 0;
|
||||
for (i = 0; i < bl->nr_extents; i++) {
|
||||
const struct pnfs_block_extent *bex = bl->extents + i;
|
||||
|
||||
p = svcxdr_encode_deviceid4(p, &bex->vol_id);
|
||||
p = xdr_encode_hyper(p, bex->foff);
|
||||
p = xdr_encode_hyper(p, bex->len);
|
||||
p = xdr_encode_hyper(p, bex->soff);
|
||||
*p++ = cpu_to_be32(bex->es);
|
||||
}
|
||||
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@
|
|||
struct iomap;
|
||||
struct xdr_stream;
|
||||
|
||||
/* On the wire size of the layout4 struct with zero number of extents */
|
||||
#define PNFS_BLOCK_LAYOUT4_SIZE \
|
||||
(sizeof(__be32) * 2 + /* offset4 */ \
|
||||
sizeof(__be32) * 2 + /* length4 */ \
|
||||
sizeof(__be32) + /* layoutiomode4 */ \
|
||||
sizeof(__be32) + /* layouttype4 */ \
|
||||
sizeof(__be32) + /* number of bytes */ \
|
||||
sizeof(__be32)) /* number of extents */
|
||||
|
||||
struct pnfs_block_extent {
|
||||
struct nfsd4_deviceid vol_id;
|
||||
u64 foff;
|
||||
|
|
@ -21,6 +30,11 @@ struct pnfs_block_range {
|
|||
u64 len;
|
||||
};
|
||||
|
||||
struct pnfs_block_layout {
|
||||
u32 nr_extents;
|
||||
struct pnfs_block_extent extents[] __counted_by(nr_extents);
|
||||
};
|
||||
|
||||
/*
|
||||
* Random upper cap for the uuid length to avoid unbounded allocation.
|
||||
* Not actually limited by the protocol.
|
||||
|
|
|
|||
Loading…
Reference in New Issue