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)
|
const struct svc_fh *fhp, struct nfsd4_layoutget *args)
|
||||||
{
|
{
|
||||||
struct nfsd4_layout_seg *seg = &args->lg_seg;
|
struct nfsd4_layout_seg *seg = &args->lg_seg;
|
||||||
|
struct pnfs_block_layout *bl;
|
||||||
struct pnfs_block_extent *bex;
|
struct pnfs_block_extent *bex;
|
||||||
u64 length;
|
u64 length;
|
||||||
u32 block_size = i_blocksize(inode);
|
u32 nr_extents_max = 1, block_size = i_blocksize(inode);
|
||||||
__be32 nfserr;
|
__be32 nfserr;
|
||||||
|
|
||||||
if (locks_in_grace(SVC_NET(rqstp)))
|
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;
|
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
|
* Some clients barf on non-zero block numbers for NONE or INVALID
|
||||||
* layouts, so make sure to zero the whole structure.
|
* layouts, so make sure to zero the whole structure.
|
||||||
*/
|
*/
|
||||||
nfserr = nfserrno(-ENOMEM);
|
nfserr = nfserrno(-ENOMEM);
|
||||||
bex = kzalloc(sizeof(*bex), GFP_KERNEL);
|
bl = kzalloc(struct_size(bl, extents, nr_extents_max), GFP_KERNEL);
|
||||||
if (!bex)
|
if (!bl)
|
||||||
goto out_error;
|
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,
|
nfserr = nfsd4_block_map_extent(inode, fhp, seg->offset, seg->length,
|
||||||
seg->iomode, args->lg_minlength, bex);
|
seg->iomode, args->lg_minlength, bex);
|
||||||
if (nfserr != nfs_ok)
|
if (nfserr != nfs_ok)
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,25 @@
|
||||||
#define NFSDDBG_FACILITY NFSDDBG_PNFS
|
#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
|
__be32
|
||||||
nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
|
nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
|
||||||
const struct nfsd4_layoutget *lgp)
|
const struct nfsd4_layoutget *lgp)
|
||||||
{
|
{
|
||||||
const struct pnfs_block_extent *b = lgp->lg_content;
|
const struct pnfs_block_layout *bl = lgp->lg_content;
|
||||||
int len = sizeof(__be32) + 5 * sizeof(__be64) + sizeof(__be32);
|
u32 i, len = sizeof(__be32) + bl->nr_extents * PNFS_BLOCK_EXTENT_SIZE;
|
||||||
__be32 *p;
|
__be32 *p;
|
||||||
|
|
||||||
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
|
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
|
||||||
|
|
@ -27,14 +40,19 @@ nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
|
||||||
return nfserr_toosmall;
|
return nfserr_toosmall;
|
||||||
|
|
||||||
*p++ = cpu_to_be32(len);
|
*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);
|
for (i = 0; i < bl->nr_extents; i++) {
|
||||||
p = xdr_encode_hyper(p, b->foff);
|
const struct pnfs_block_extent *bex = bl->extents + i;
|
||||||
p = xdr_encode_hyper(p, b->len);
|
|
||||||
p = xdr_encode_hyper(p, b->soff);
|
p = svcxdr_encode_deviceid4(p, &bex->vol_id);
|
||||||
*p++ = cpu_to_be32(b->es);
|
p = xdr_encode_hyper(p, bex->foff);
|
||||||
return 0;
|
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
|
static int
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,15 @@
|
||||||
struct iomap;
|
struct iomap;
|
||||||
struct xdr_stream;
|
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 pnfs_block_extent {
|
||||||
struct nfsd4_deviceid vol_id;
|
struct nfsd4_deviceid vol_id;
|
||||||
u64 foff;
|
u64 foff;
|
||||||
|
|
@ -21,6 +30,11 @@ struct pnfs_block_range {
|
||||||
u64 len;
|
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.
|
* Random upper cap for the uuid length to avoid unbounded allocation.
|
||||||
* Not actually limited by the protocol.
|
* Not actually limited by the protocol.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue