1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2014-2016 Christoph Hellwig.
5 #include <linux/sunrpc/svc.h>
6 #include <linux/exportfs.h>
7 #include <linux/iomap.h>
8 #include <linux/nfs4.h>
11 #include "blocklayoutxdr.h"
13 #define NFSDDBG_FACILITY NFSDDBG_PNFS
17 nfsd4_block_encode_layoutget(struct xdr_stream
*xdr
,
18 struct nfsd4_layoutget
*lgp
)
20 struct pnfs_block_extent
*b
= lgp
->lg_content
;
21 int len
= sizeof(__be32
) + 5 * sizeof(__be64
) + sizeof(__be32
);
24 p
= xdr_reserve_space(xdr
, sizeof(__be32
) + len
);
26 return nfserr_toosmall
;
28 *p
++ = cpu_to_be32(len
);
29 *p
++ = cpu_to_be32(1); /* we always return a single extent */
31 p
= xdr_encode_opaque_fixed(p
, &b
->vol_id
,
32 sizeof(struct nfsd4_deviceid
));
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
);
41 nfsd4_block_encode_volume(struct xdr_stream
*xdr
, struct pnfs_block_volume
*b
)
47 case PNFS_BLOCK_VOLUME_SIMPLE
:
48 len
= 4 + 4 + 8 + 4 + (XDR_QUADLEN(b
->simple
.sig_len
) << 2);
49 p
= xdr_reserve_space(xdr
, len
);
53 *p
++ = cpu_to_be32(b
->type
);
54 *p
++ = cpu_to_be32(1); /* single signature */
55 p
= xdr_encode_hyper(p
, b
->simple
.offset
);
56 p
= xdr_encode_opaque(p
, b
->simple
.sig
, b
->simple
.sig_len
);
58 case PNFS_BLOCK_VOLUME_SCSI
:
59 len
= 4 + 4 + 4 + 4 + (XDR_QUADLEN(b
->scsi
.designator_len
) << 2) + 8;
60 p
= xdr_reserve_space(xdr
, len
);
64 *p
++ = cpu_to_be32(b
->type
);
65 *p
++ = cpu_to_be32(b
->scsi
.code_set
);
66 *p
++ = cpu_to_be32(b
->scsi
.designator_type
);
67 p
= xdr_encode_opaque(p
, b
->scsi
.designator
, b
->scsi
.designator_len
);
68 p
= xdr_encode_hyper(p
, b
->scsi
.pr_key
);
78 nfsd4_block_encode_getdeviceinfo(struct xdr_stream
*xdr
,
79 struct nfsd4_getdeviceinfo
*gdp
)
81 struct pnfs_block_deviceaddr
*dev
= gdp
->gd_device
;
82 int len
= sizeof(__be32
), ret
, i
;
85 p
= xdr_reserve_space(xdr
, len
+ sizeof(__be32
));
87 return nfserr_resource
;
89 for (i
= 0; i
< dev
->nr_volumes
; i
++) {
90 ret
= nfsd4_block_encode_volume(xdr
, &dev
->volumes
[i
]);
97 * Fill in the overall length and number of volumes at the beginning
100 *p
++ = cpu_to_be32(len
);
101 *p
++ = cpu_to_be32(dev
->nr_volumes
);
106 nfsd4_block_decode_layoutupdate(__be32
*p
, u32 len
, struct iomap
**iomapp
,
109 struct iomap
*iomaps
;
112 if (len
< sizeof(u32
)) {
113 dprintk("%s: extent array too small: %u\n", __func__
, len
);
117 if (len
% PNFS_BLOCK_EXTENT_SIZE
) {
118 dprintk("%s: extent array invalid: %u\n", __func__
, len
);
122 nr_iomaps
= be32_to_cpup(p
++);
123 if (nr_iomaps
!= len
/ PNFS_BLOCK_EXTENT_SIZE
) {
124 dprintk("%s: extent array size mismatch: %u/%u\n",
125 __func__
, len
, nr_iomaps
);
129 iomaps
= kcalloc(nr_iomaps
, sizeof(*iomaps
), GFP_KERNEL
);
131 dprintk("%s: failed to allocate extent array\n", __func__
);
135 for (i
= 0; i
< nr_iomaps
; i
++) {
136 struct pnfs_block_extent bex
;
138 memcpy(&bex
.vol_id
, p
, sizeof(struct nfsd4_deviceid
));
139 p
+= XDR_QUADLEN(sizeof(struct nfsd4_deviceid
));
141 p
= xdr_decode_hyper(p
, &bex
.foff
);
142 if (bex
.foff
& (block_size
- 1)) {
143 dprintk("%s: unaligned offset 0x%llx\n",
147 p
= xdr_decode_hyper(p
, &bex
.len
);
148 if (bex
.len
& (block_size
- 1)) {
149 dprintk("%s: unaligned length 0x%llx\n",
153 p
= xdr_decode_hyper(p
, &bex
.soff
);
154 if (bex
.soff
& (block_size
- 1)) {
155 dprintk("%s: unaligned disk offset 0x%llx\n",
159 bex
.es
= be32_to_cpup(p
++);
160 if (bex
.es
!= PNFS_BLOCK_READWRITE_DATA
) {
161 dprintk("%s: incorrect extent state %d\n",
166 iomaps
[i
].offset
= bex
.foff
;
167 iomaps
[i
].length
= bex
.len
;
178 nfsd4_scsi_decode_layoutupdate(__be32
*p
, u32 len
, struct iomap
**iomapp
,
181 struct iomap
*iomaps
;
182 u32 nr_iomaps
, expected
, i
;
184 if (len
< sizeof(u32
)) {
185 dprintk("%s: extent array too small: %u\n", __func__
, len
);
189 nr_iomaps
= be32_to_cpup(p
++);
190 expected
= sizeof(__be32
) + nr_iomaps
* PNFS_SCSI_RANGE_SIZE
;
191 if (len
!= expected
) {
192 dprintk("%s: extent array size mismatch: %u/%u\n",
193 __func__
, len
, expected
);
197 iomaps
= kcalloc(nr_iomaps
, sizeof(*iomaps
), GFP_KERNEL
);
199 dprintk("%s: failed to allocate extent array\n", __func__
);
203 for (i
= 0; i
< nr_iomaps
; i
++) {
206 p
= xdr_decode_hyper(p
, &val
);
207 if (val
& (block_size
- 1)) {
208 dprintk("%s: unaligned offset 0x%llx\n", __func__
, val
);
211 iomaps
[i
].offset
= val
;
213 p
= xdr_decode_hyper(p
, &val
);
214 if (val
& (block_size
- 1)) {
215 dprintk("%s: unaligned length 0x%llx\n", __func__
, val
);
218 iomaps
[i
].length
= val
;