1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2014-2016 Christoph Hellwig. 4 */ 5 #include <linux/sunrpc/svc.h> 6 #include <linux/exportfs.h> 7 #include <linux/iomap.h> 8 #include <linux/nfs4.h> 9 10 #include "nfsd.h" 11 #include "blocklayoutxdr.h" 12 #include "vfs.h" 13 14 #define NFSDDBG_FACILITY NFSDDBG_PNFS 15 16 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 */ 30 __be32 31 nfsd4_block_encode_layoutget(struct xdr_stream *xdr, 32 const struct nfsd4_layoutget *lgp) 33 { 34 const struct pnfs_block_layout *bl = lgp->lg_content; 35 u32 i, len = sizeof(__be32) + bl->nr_extents * PNFS_BLOCK_EXTENT_SIZE; 36 __be32 *p; 37 38 p = xdr_reserve_space(xdr, sizeof(__be32) + len); 39 if (!p) 40 return nfserr_toosmall; 41 42 *p++ = cpu_to_be32(len); 43 *p++ = cpu_to_be32(bl->nr_extents); 44 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; 56 } 57 58 static int 59 nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b) 60 { 61 __be32 *p; 62 int len; 63 64 switch (b->type) { 65 case PNFS_BLOCK_VOLUME_SIMPLE: 66 len = 4 + 4 + 8 + 4 + (XDR_QUADLEN(b->simple.sig_len) << 2); 67 p = xdr_reserve_space(xdr, len); 68 if (!p) 69 return -ETOOSMALL; 70 71 *p++ = cpu_to_be32(b->type); 72 *p++ = cpu_to_be32(1); /* single signature */ 73 p = xdr_encode_hyper(p, b->simple.offset); 74 p = xdr_encode_opaque(p, b->simple.sig, b->simple.sig_len); 75 break; 76 case PNFS_BLOCK_VOLUME_SCSI: 77 len = 4 + 4 + 4 + 4 + (XDR_QUADLEN(b->scsi.designator_len) << 2) + 8; 78 p = xdr_reserve_space(xdr, len); 79 if (!p) 80 return -ETOOSMALL; 81 82 *p++ = cpu_to_be32(b->type); 83 *p++ = cpu_to_be32(b->scsi.code_set); 84 *p++ = cpu_to_be32(b->scsi.designator_type); 85 p = xdr_encode_opaque(p, b->scsi.designator, b->scsi.designator_len); 86 p = xdr_encode_hyper(p, b->scsi.pr_key); 87 break; 88 default: 89 return -ENOTSUPP; 90 } 91 92 return len; 93 } 94 95 __be32 96 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, 97 const struct nfsd4_getdeviceinfo *gdp) 98 { 99 struct pnfs_block_deviceaddr *dev = gdp->gd_device; 100 int len = sizeof(__be32), ret, i; 101 __be32 *p; 102 103 /* 104 * See paragraph 5 of RFC 8881 S18.40.3. 105 */ 106 if (!gdp->gd_maxcount) { 107 if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) 108 return nfserr_resource; 109 return nfs_ok; 110 } 111 112 p = xdr_reserve_space(xdr, len + sizeof(__be32)); 113 if (!p) 114 return nfserr_resource; 115 116 for (i = 0; i < dev->nr_volumes; i++) { 117 ret = nfsd4_block_encode_volume(xdr, &dev->volumes[i]); 118 if (ret < 0) 119 return nfserrno(ret); 120 len += ret; 121 } 122 123 /* 124 * Fill in the overall length and number of volumes at the beginning 125 * of the layout. 126 */ 127 *p++ = cpu_to_be32(len); 128 *p++ = cpu_to_be32(dev->nr_volumes); 129 return 0; 130 } 131 132 /** 133 * nfsd4_block_decode_layoutupdate - decode the block layout extent array 134 * @xdr: subbuf set to the encoded array 135 * @iomapp: pointer to store the decoded extent array 136 * @nr_iomapsp: pointer to store the number of extents 137 * @block_size: alignment of extent offset and length 138 * 139 * This function decodes the opaque field of the layoutupdate4 structure 140 * in a layoutcommit request for the block layout driver. The field is 141 * actually an array of extents sent by the client. It also checks that 142 * the file offset, storage offset and length of each extent are aligned 143 * by @block_size. 144 * 145 * Return values: 146 * %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid 147 * %nfserr_bad_xdr: The encoded array in @xdr is invalid 148 * %nfserr_inval: An unaligned extent found 149 * %nfserr_delay: Failed to allocate memory for @iomapp 150 */ 151 __be32 152 nfsd4_block_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp, 153 int *nr_iomapsp, u32 block_size) 154 { 155 struct iomap *iomaps; 156 u32 nr_iomaps, expected, len, i; 157 __be32 nfserr; 158 159 if (xdr_stream_decode_u32(xdr, &nr_iomaps)) 160 return nfserr_bad_xdr; 161 162 len = sizeof(__be32) + xdr_stream_remaining(xdr); 163 expected = sizeof(__be32) + nr_iomaps * PNFS_BLOCK_EXTENT_SIZE; 164 if (len != expected) 165 return nfserr_bad_xdr; 166 167 iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL); 168 if (!iomaps) 169 return nfserr_delay; 170 171 for (i = 0; i < nr_iomaps; i++) { 172 struct pnfs_block_extent bex; 173 174 if (nfsd4_decode_deviceid4(xdr, &bex.vol_id)) { 175 nfserr = nfserr_bad_xdr; 176 goto fail; 177 } 178 179 if (xdr_stream_decode_u64(xdr, &bex.foff)) { 180 nfserr = nfserr_bad_xdr; 181 goto fail; 182 } 183 if (bex.foff & (block_size - 1)) { 184 nfserr = nfserr_inval; 185 goto fail; 186 } 187 188 if (xdr_stream_decode_u64(xdr, &bex.len)) { 189 nfserr = nfserr_bad_xdr; 190 goto fail; 191 } 192 if (bex.len & (block_size - 1)) { 193 nfserr = nfserr_inval; 194 goto fail; 195 } 196 197 if (xdr_stream_decode_u64(xdr, &bex.soff)) { 198 nfserr = nfserr_bad_xdr; 199 goto fail; 200 } 201 if (bex.soff & (block_size - 1)) { 202 nfserr = nfserr_inval; 203 goto fail; 204 } 205 206 if (xdr_stream_decode_u32(xdr, &bex.es)) { 207 nfserr = nfserr_bad_xdr; 208 goto fail; 209 } 210 if (bex.es != PNFS_BLOCK_READWRITE_DATA) { 211 nfserr = nfserr_inval; 212 goto fail; 213 } 214 215 iomaps[i].offset = bex.foff; 216 iomaps[i].length = bex.len; 217 } 218 219 *iomapp = iomaps; 220 *nr_iomapsp = nr_iomaps; 221 return nfs_ok; 222 fail: 223 kfree(iomaps); 224 return nfserr; 225 } 226 227 /** 228 * nfsd4_scsi_decode_layoutupdate - decode the scsi layout extent array 229 * @xdr: subbuf set to the encoded array 230 * @iomapp: pointer to store the decoded extent array 231 * @nr_iomapsp: pointer to store the number of extents 232 * @block_size: alignment of extent offset and length 233 * 234 * This function decodes the opaque field of the layoutupdate4 structure 235 * in a layoutcommit request for the scsi layout driver. The field is 236 * actually an array of extents sent by the client. It also checks that 237 * the offset and length of each extent are aligned by @block_size. 238 * 239 * Return values: 240 * %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid 241 * %nfserr_bad_xdr: The encoded array in @xdr is invalid 242 * %nfserr_inval: An unaligned extent found 243 * %nfserr_delay: Failed to allocate memory for @iomapp 244 */ 245 __be32 246 nfsd4_scsi_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp, 247 int *nr_iomapsp, u32 block_size) 248 { 249 struct iomap *iomaps; 250 u32 nr_iomaps, expected, len, i; 251 __be32 nfserr; 252 253 if (xdr_stream_decode_u32(xdr, &nr_iomaps)) 254 return nfserr_bad_xdr; 255 256 len = sizeof(__be32) + xdr_stream_remaining(xdr); 257 expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE; 258 if (len != expected) 259 return nfserr_bad_xdr; 260 261 iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL); 262 if (!iomaps) 263 return nfserr_delay; 264 265 for (i = 0; i < nr_iomaps; i++) { 266 u64 val; 267 268 if (xdr_stream_decode_u64(xdr, &val)) { 269 nfserr = nfserr_bad_xdr; 270 goto fail; 271 } 272 if (val & (block_size - 1)) { 273 nfserr = nfserr_inval; 274 goto fail; 275 } 276 iomaps[i].offset = val; 277 278 if (xdr_stream_decode_u64(xdr, &val)) { 279 nfserr = nfserr_bad_xdr; 280 goto fail; 281 } 282 if (val & (block_size - 1)) { 283 nfserr = nfserr_inval; 284 goto fail; 285 } 286 iomaps[i].length = val; 287 } 288 289 *iomapp = iomaps; 290 *nr_iomapsp = nr_iomaps; 291 return nfs_ok; 292 fail: 293 kfree(iomaps); 294 return nfserr; 295 } 296