Skip to content

Commit 0cd0d15

Browse files
sbashirochucklever
authored andcommitted
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>
1 parent a1dce71 commit 0cd0d15

3 files changed

Lines changed: 63 additions & 13 deletions

File tree

fs/nfsd/blocklayout.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
8888
const struct svc_fh *fhp, struct nfsd4_layoutget *args)
8989
{
9090
struct nfsd4_layout_seg *seg = &args->lg_seg;
91+
struct pnfs_block_layout *bl;
9192
struct pnfs_block_extent *bex;
9293
u64 length;
93-
u32 block_size = i_blocksize(inode);
94+
u32 nr_extents_max = 1, block_size = i_blocksize(inode);
9495
__be32 nfserr;
9596

9697
if (locks_in_grace(SVC_NET(rqstp)))
@@ -102,16 +103,33 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
102103
goto out_error;
103104
}
104105

106+
/*
107+
* RFC 8881, section 3.3.17:
108+
* The layout4 data type defines a layout for a file.
109+
*
110+
* RFC 8881, section 18.43.3:
111+
* The loga_maxcount field specifies the maximum layout size
112+
* (in bytes) that the client can handle. If the size of the
113+
* layout structure exceeds the size specified by maxcount,
114+
* the metadata server will return the NFS4ERR_TOOSMALL error.
115+
*/
116+
nfserr = nfserr_toosmall;
117+
if (args->lg_maxcount < PNFS_BLOCK_LAYOUT4_SIZE +
118+
PNFS_BLOCK_EXTENT_SIZE)
119+
goto out_error;
120+
105121
/*
106122
* Some clients barf on non-zero block numbers for NONE or INVALID
107123
* layouts, so make sure to zero the whole structure.
108124
*/
109125
nfserr = nfserrno(-ENOMEM);
110-
bex = kzalloc(sizeof(*bex), GFP_KERNEL);
111-
if (!bex)
126+
bl = kzalloc(struct_size(bl, extents, nr_extents_max), GFP_KERNEL);
127+
if (!bl)
112128
goto out_error;
113-
args->lg_content = bex;
129+
bl->nr_extents = nr_extents_max;
130+
args->lg_content = bl;
114131

132+
bex = &bl->extents[0];
115133
nfserr = nfsd4_block_map_extent(inode, fhp, seg->offset, seg->length,
116134
seg->iomode, args->lg_minlength, bex);
117135
if (nfserr != nfs_ok)

fs/nfsd/blocklayoutxdr.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,45 @@
1414
#define NFSDDBG_FACILITY NFSDDBG_PNFS
1515

1616

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+
*/
1730
__be32
1831
nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
1932
const struct nfsd4_layoutget *lgp)
2033
{
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;
2336
__be32 *p;
2437

2538
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
2639
if (!p)
2740
return nfserr_toosmall;
2841

2942
*p++ = cpu_to_be32(len);
30-
*p++ = cpu_to_be32(1); /* we always return a single extent */
43+
*p++ = cpu_to_be32(bl->nr_extents);
3144

32-
p = svcxdr_encode_deviceid4(p, &b->vol_id);
33-
p = xdr_encode_hyper(p, b->foff);
34-
p = xdr_encode_hyper(p, b->len);
35-
p = xdr_encode_hyper(p, b->soff);
36-
*p++ = cpu_to_be32(b->es);
37-
return 0;
45+
for (i = 0; i < bl->nr_extents; i++) {
46+
const struct pnfs_block_extent *bex = bl->extents + i;
47+
48+
p = svcxdr_encode_deviceid4(p, &bex->vol_id);
49+
p = xdr_encode_hyper(p, bex->foff);
50+
p = xdr_encode_hyper(p, bex->len);
51+
p = xdr_encode_hyper(p, bex->soff);
52+
*p++ = cpu_to_be32(bex->es);
53+
}
54+
55+
return nfs_ok;
3856
}
3957

4058
static int

fs/nfsd/blocklayoutxdr.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
struct iomap;
99
struct xdr_stream;
1010

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+
1120
struct pnfs_block_extent {
1221
struct nfsd4_deviceid vol_id;
1322
u64 foff;
@@ -21,6 +30,11 @@ struct pnfs_block_range {
2130
u64 len;
2231
};
2332

33+
struct pnfs_block_layout {
34+
u32 nr_extents;
35+
struct pnfs_block_extent extents[] __counted_by(nr_extents);
36+
};
37+
2438
/*
2539
* Random upper cap for the uuid length to avoid unbounded allocation.
2640
* Not actually limited by the protocol.

0 commit comments

Comments
 (0)