2 * Copyright (c) 2014-2016 Christoph Hellwig.
4 #include <linux/sunrpc/svc.h>
5 #include <linux/exportfs.h>
6 #include <linux/iomap.h>
7 #include <linux/nfs4.h>
10 #include "blocklayoutxdr.h"
12 #define NFSDDBG_FACILITY NFSDDBG_PNFS
16 nfsd4_block_encode_layoutget(struct xdr_stream
*xdr
,
17 struct nfsd4_layoutget
*lgp
)
19 struct pnfs_block_extent
*b
= lgp
->lg_content
;
20 int len
= sizeof(__be32
) + 5 * sizeof(__be64
) + sizeof(__be32
);
23 p
= xdr_reserve_space(xdr
, sizeof(__be32
) + len
);
25 return nfserr_toosmall
;
27 *p
++ = cpu_to_be32(len
);
28 *p
++ = cpu_to_be32(1); /* we always return a single extent */
30 p
= xdr_encode_opaque_fixed(p
, &b
->vol_id
,
31 sizeof(struct nfsd4_deviceid
));
32 p
= xdr_encode_hyper(p
, b
->foff
);
33 p
= xdr_encode_hyper(p
, b
->len
);
34 p
= xdr_encode_hyper(p
, b
->soff
);
35 *p
++ = cpu_to_be32(b
->es
);
40 nfsd4_block_encode_volume(struct xdr_stream
*xdr
, struct pnfs_block_volume
*b
)
46 case PNFS_BLOCK_VOLUME_SIMPLE
:
47 len
= 4 + 4 + 8 + 4 + (XDR_QUADLEN(b
->simple
.sig_len
) << 2);
48 p
= xdr_reserve_space(xdr
, len
);
52 *p
++ = cpu_to_be32(b
->type
);
53 *p
++ = cpu_to_be32(1); /* single signature */
54 p
= xdr_encode_hyper(p
, b
->simple
.offset
);
55 p
= xdr_encode_opaque(p
, b
->simple
.sig
, b
->simple
.sig_len
);
57 case PNFS_BLOCK_VOLUME_SCSI
:
58 len
= 4 + 4 + 4 + 4 + (XDR_QUADLEN(b
->scsi
.designator_len
) << 2) + 8;
59 p
= xdr_reserve_space(xdr
, len
);
63 *p
++ = cpu_to_be32(b
->type
);
64 *p
++ = cpu_to_be32(b
->scsi
.code_set
);
65 *p
++ = cpu_to_be32(b
->scsi
.designator_type
);
66 p
= xdr_encode_opaque(p
, b
->scsi
.designator
, b
->scsi
.designator_len
);
67 p
= xdr_encode_hyper(p
, b
->scsi
.pr_key
);
77 nfsd4_block_encode_getdeviceinfo(struct xdr_stream
*xdr
,
78 struct nfsd4_getdeviceinfo
*gdp
)
80 struct pnfs_block_deviceaddr
*dev
= gdp
->gd_device
;
81 int len
= sizeof(__be32
), ret
, i
;
84 p
= xdr_reserve_space(xdr
, len
+ sizeof(__be32
));
86 return nfserr_resource
;
88 for (i
= 0; i
< dev
->nr_volumes
; i
++) {
89 ret
= nfsd4_block_encode_volume(xdr
, &dev
->volumes
[i
]);
96 * Fill in the overall length and number of volumes at the beginning
99 *p
++ = cpu_to_be32(len
);
100 *p
++ = cpu_to_be32(dev
->nr_volumes
);
105 nfsd4_block_decode_layoutupdate(__be32
*p
, u32 len
, struct iomap
**iomapp
,
108 struct iomap
*iomaps
;
111 if (len
< sizeof(u32
)) {
112 dprintk("%s: extent array too small: %u\n", __func__
, len
);
116 if (len
% PNFS_BLOCK_EXTENT_SIZE
) {
117 dprintk("%s: extent array invalid: %u\n", __func__
, len
);
121 nr_iomaps
= be32_to_cpup(p
++);
122 if (nr_iomaps
!= len
/ PNFS_BLOCK_EXTENT_SIZE
) {
123 dprintk("%s: extent array size mismatch: %u/%u\n",
124 __func__
, len
, nr_iomaps
);
128 iomaps
= kcalloc(nr_iomaps
, sizeof(*iomaps
), GFP_KERNEL
);
130 dprintk("%s: failed to allocate extent array\n", __func__
);
134 for (i
= 0; i
< nr_iomaps
; i
++) {
135 struct pnfs_block_extent bex
;
137 memcpy(&bex
.vol_id
, p
, sizeof(struct nfsd4_deviceid
));
138 p
+= XDR_QUADLEN(sizeof(struct nfsd4_deviceid
));
140 p
= xdr_decode_hyper(p
, &bex
.foff
);
141 if (bex
.foff
& (block_size
- 1)) {
142 dprintk("%s: unaligned offset 0x%llx\n",
146 p
= xdr_decode_hyper(p
, &bex
.len
);
147 if (bex
.len
& (block_size
- 1)) {
148 dprintk("%s: unaligned length 0x%llx\n",
152 p
= xdr_decode_hyper(p
, &bex
.soff
);
153 if (bex
.soff
& (block_size
- 1)) {
154 dprintk("%s: unaligned disk offset 0x%llx\n",
158 bex
.es
= be32_to_cpup(p
++);
159 if (bex
.es
!= PNFS_BLOCK_READWRITE_DATA
) {
160 dprintk("%s: incorrect extent state %d\n",
165 iomaps
[i
].offset
= bex
.foff
;
166 iomaps
[i
].length
= bex
.len
;
177 nfsd4_scsi_decode_layoutupdate(__be32
*p
, u32 len
, struct iomap
**iomapp
,
180 struct iomap
*iomaps
;
181 u32 nr_iomaps
, expected
, i
;
183 if (len
< sizeof(u32
)) {
184 dprintk("%s: extent array too small: %u\n", __func__
, len
);
188 nr_iomaps
= be32_to_cpup(p
++);
189 expected
= sizeof(__be32
) + nr_iomaps
* PNFS_SCSI_RANGE_SIZE
;
190 if (len
!= expected
) {
191 dprintk("%s: extent array size mismatch: %u/%u\n",
192 __func__
, len
, expected
);
196 iomaps
= kcalloc(nr_iomaps
, sizeof(*iomaps
), GFP_KERNEL
);
198 dprintk("%s: failed to allocate extent array\n", __func__
);
202 for (i
= 0; i
< nr_iomaps
; i
++) {
205 p
= xdr_decode_hyper(p
, &val
);
206 if (val
& (block_size
- 1)) {
207 dprintk("%s: unaligned offset 0x%llx\n", __func__
, val
);
210 iomaps
[i
].offset
= val
;
212 p
= xdr_decode_hyper(p
, &val
);
213 if (val
& (block_size
- 1)) {
214 dprintk("%s: unaligned length 0x%llx\n", __func__
, val
);
217 iomaps
[i
].length
= val
;