2 * Copyright (c) 2014 Christoph Hellwig.
4 #include <linux/sunrpc/svc.h>
5 #include <linux/exportfs.h>
6 #include <linux/nfs4.h>
9 #include "blocklayoutxdr.h"
11 #define NFSDDBG_FACILITY NFSDDBG_PNFS
15 nfsd4_block_encode_layoutget(struct xdr_stream
*xdr
,
16 struct nfsd4_layoutget
*lgp
)
18 struct pnfs_block_extent
*b
= lgp
->lg_content
;
19 int len
= sizeof(__be32
) + 5 * sizeof(__be64
) + sizeof(__be32
);
22 p
= xdr_reserve_space(xdr
, sizeof(__be32
) + len
);
24 return nfserr_toosmall
;
26 *p
++ = cpu_to_be32(len
);
27 *p
++ = cpu_to_be32(1); /* we always return a single extent */
29 p
= xdr_encode_opaque_fixed(p
, &b
->vol_id
,
30 sizeof(struct nfsd4_deviceid
));
31 p
= xdr_encode_hyper(p
, b
->foff
);
32 p
= xdr_encode_hyper(p
, b
->len
);
33 p
= xdr_encode_hyper(p
, b
->soff
);
34 *p
++ = cpu_to_be32(b
->es
);
39 nfsd4_block_encode_volume(struct xdr_stream
*xdr
, struct pnfs_block_volume
*b
)
45 case PNFS_BLOCK_VOLUME_SIMPLE
:
46 len
= 4 + 4 + 8 + 4 + b
->simple
.sig_len
;
47 p
= xdr_reserve_space(xdr
, len
);
51 *p
++ = cpu_to_be32(b
->type
);
52 *p
++ = cpu_to_be32(1); /* single signature */
53 p
= xdr_encode_hyper(p
, b
->simple
.offset
);
54 p
= xdr_encode_opaque(p
, b
->simple
.sig
, b
->simple
.sig_len
);
64 nfsd4_block_encode_getdeviceinfo(struct xdr_stream
*xdr
,
65 struct nfsd4_getdeviceinfo
*gdp
)
67 struct pnfs_block_deviceaddr
*dev
= gdp
->gd_device
;
68 int len
= sizeof(__be32
), ret
, i
;
71 p
= xdr_reserve_space(xdr
, len
+ sizeof(__be32
));
73 return nfserr_resource
;
75 for (i
= 0; i
< dev
->nr_volumes
; i
++) {
76 ret
= nfsd4_block_encode_volume(xdr
, &dev
->volumes
[i
]);
83 * Fill in the overall length and number of volumes at the beginning
86 *p
++ = cpu_to_be32(len
);
87 *p
++ = cpu_to_be32(dev
->nr_volumes
);
92 nfsd4_block_decode_layoutupdate(__be32
*p
, u32 len
, struct iomap
**iomapp
,
96 u32 nr_iomaps
, expected
, i
;
98 if (len
< sizeof(u32
)) {
99 dprintk("%s: extent array too small: %u\n", __func__
, len
);
103 nr_iomaps
= be32_to_cpup(p
++);
104 expected
= sizeof(__be32
) + nr_iomaps
* NFS4_BLOCK_EXTENT_SIZE
;
105 if (len
!= expected
) {
106 dprintk("%s: extent array size mismatch: %u/%u\n",
107 __func__
, len
, expected
);
111 iomaps
= kcalloc(nr_iomaps
, sizeof(*iomaps
), GFP_KERNEL
);
113 dprintk("%s: failed to allocate extent array\n", __func__
);
117 for (i
= 0; i
< nr_iomaps
; i
++) {
118 struct pnfs_block_extent bex
;
120 memcpy(&bex
.vol_id
, p
, sizeof(struct nfsd4_deviceid
));
121 p
+= XDR_QUADLEN(sizeof(struct nfsd4_deviceid
));
123 p
= xdr_decode_hyper(p
, &bex
.foff
);
124 if (bex
.foff
& (block_size
- 1)) {
125 dprintk("%s: unaligned offset %lld\n",
129 p
= xdr_decode_hyper(p
, &bex
.len
);
130 if (bex
.len
& (block_size
- 1)) {
131 dprintk("%s: unaligned length %lld\n",
135 p
= xdr_decode_hyper(p
, &bex
.soff
);
136 if (bex
.soff
& (block_size
- 1)) {
137 dprintk("%s: unaligned disk offset %lld\n",
141 bex
.es
= be32_to_cpup(p
++);
142 if (bex
.es
!= PNFS_BLOCK_READWRITE_DATA
) {
143 dprintk("%s: incorrect extent state %d\n",
148 iomaps
[i
].offset
= bex
.foff
;
149 iomaps
[i
].length
= bex
.len
;