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 __be32 18 nfsd4_block_encode_layoutget(struct xdr_stream *xdr, 19 const struct nfsd4_layoutget *lgp) 20 { 21 const struct pnfs_block_extent *b = lgp->lg_content; 22 int len = sizeof(__be32) + 5 * sizeof(__be64) + sizeof(__be32); 23 __be32 *p; 24 25 p = xdr_reserve_space(xdr, sizeof(__be32) + len); 26 if (!p) 27 return nfserr_toosmall; 28 29 *p++ = cpu_to_be32(len); 30 *p++ = cpu_to_be32(1); /* we always return a single extent */ 31 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; 38 } 39 40 static int 41 nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b) 42 { 43 __be32 *p; 44 int len; 45 46 switch (b->type) { 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); 50 if (!p) 51 return -ETOOSMALL; 52 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); 57 break; 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); 61 if (!p) 62 return -ETOOSMALL; 63 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); 69 break; 70 default: 71 return -ENOTSUPP; 72 } 73 74 return len; 75 } 76 77 __be32 78 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, 79 const struct nfsd4_getdeviceinfo *gdp) 80 { 81 struct pnfs_block_deviceaddr *dev = gdp->gd_device; 82 int len = sizeof(__be32), ret, i; 83 __be32 *p; 84 85 /* 86 * See paragraph 5 of RFC 8881 S18.40.3. 87 */ 88 if (!gdp->gd_maxcount) { 89 if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) 90 return nfserr_resource; 91 return nfs_ok; 92 } 93 94 p = xdr_reserve_space(xdr, len + sizeof(__be32)); 95 if (!p) 96 return nfserr_resource; 97 98 for (i = 0; i < dev->nr_volumes; i++) { 99 ret = nfsd4_block_encode_volume(xdr, &dev->volumes[i]); 100 if (ret < 0) 101 return nfserrno(ret); 102 len += ret; 103 } 104 105 /* 106 * Fill in the overall length and number of volumes at the beginning 107 * of the layout. 108 */ 109 *p++ = cpu_to_be32(len); 110 *p++ = cpu_to_be32(dev->nr_volumes); 111 return 0; 112 } 113 114 /** 115 * nfsd4_block_decode_layoutupdate - decode the block layout extent array 116 * @xdr: subbuf set to the encoded array 117 * @iomapp: pointer to store the decoded extent array 118 * @nr_iomapsp: pointer to store the number of extents 119 * @block_size: alignment of extent offset and length 120 * 121 * This function decodes the opaque field of the layoutupdate4 structure 122 * in a layoutcommit request for the block layout driver. The field is 123 * actually an array of extents sent by the client. It also checks that 124 * the file offset, storage offset and length of each extent are aligned 125 * by @block_size. 126 * 127 * Return values: 128 * %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid 129 * %nfserr_bad_xdr: The encoded array in @xdr is invalid 130 * %nfserr_inval: An unaligned extent found 131 * %nfserr_delay: Failed to allocate memory for @iomapp 132 */ 133 __be32 134 nfsd4_block_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp, 135 int *nr_iomapsp, u32 block_size) 136 { 137 struct iomap *iomaps; 138 u32 nr_iomaps, expected, len, i; 139 __be32 nfserr; 140 141 if (xdr_stream_decode_u32(xdr, &nr_iomaps)) 142 return nfserr_bad_xdr; 143 144 len = sizeof(__be32) + xdr_stream_remaining(xdr); 145 expected = sizeof(__be32) + nr_iomaps * PNFS_BLOCK_EXTENT_SIZE; 146 if (len != expected) 147 return nfserr_bad_xdr; 148 149 iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL); 150 if (!iomaps) 151 return nfserr_delay; 152 153 for (i = 0; i < nr_iomaps; i++) { 154 struct pnfs_block_extent bex; 155 156 if (nfsd4_decode_deviceid4(xdr, &bex.vol_id)) { 157 nfserr = nfserr_bad_xdr; 158 goto fail; 159 } 160 161 if (xdr_stream_decode_u64(xdr, &bex.foff)) { 162 nfserr = nfserr_bad_xdr; 163 goto fail; 164 } 165 if (bex.foff & (block_size - 1)) { 166 nfserr = nfserr_inval; 167 goto fail; 168 } 169 170 if (xdr_stream_decode_u64(xdr, &bex.len)) { 171 nfserr = nfserr_bad_xdr; 172 goto fail; 173 } 174 if (bex.len & (block_size - 1)) { 175 nfserr = nfserr_inval; 176 goto fail; 177 } 178 179 if (xdr_stream_decode_u64(xdr, &bex.soff)) { 180 nfserr = nfserr_bad_xdr; 181 goto fail; 182 } 183 if (bex.soff & (block_size - 1)) { 184 nfserr = nfserr_inval; 185 goto fail; 186 } 187 188 if (xdr_stream_decode_u32(xdr, &bex.es)) { 189 nfserr = nfserr_bad_xdr; 190 goto fail; 191 } 192 if (bex.es != PNFS_BLOCK_READWRITE_DATA) { 193 nfserr = nfserr_inval; 194 goto fail; 195 } 196 197 iomaps[i].offset = bex.foff; 198 iomaps[i].length = bex.len; 199 } 200 201 *iomapp = iomaps; 202 *nr_iomapsp = nr_iomaps; 203 return nfs_ok; 204 fail: 205 kfree(iomaps); 206 return nfserr; 207 } 208 209 /** 210 * nfsd4_scsi_decode_layoutupdate - decode the scsi layout extent array 211 * @xdr: subbuf set to the encoded array 212 * @iomapp: pointer to store the decoded extent array 213 * @nr_iomapsp: pointer to store the number of extents 214 * @block_size: alignment of extent offset and length 215 * 216 * This function decodes the opaque field of the layoutupdate4 structure 217 * in a layoutcommit request for the scsi layout driver. The field is 218 * actually an array of extents sent by the client. It also checks that 219 * the offset and length of each extent are aligned by @block_size. 220 * 221 * Return values: 222 * %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid 223 * %nfserr_bad_xdr: The encoded array in @xdr is invalid 224 * %nfserr_inval: An unaligned extent found 225 * %nfserr_delay: Failed to allocate memory for @iomapp 226 */ 227 __be32 228 nfsd4_scsi_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp, 229 int *nr_iomapsp, u32 block_size) 230 { 231 struct iomap *iomaps; 232 u32 nr_iomaps, expected, len, i; 233 __be32 nfserr; 234 235 if (xdr_stream_decode_u32(xdr, &nr_iomaps)) 236 return nfserr_bad_xdr; 237 238 len = sizeof(__be32) + xdr_stream_remaining(xdr); 239 expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE; 240 if (len != expected) 241 return nfserr_bad_xdr; 242 243 iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL); 244 if (!iomaps) 245 return nfserr_delay; 246 247 for (i = 0; i < nr_iomaps; i++) { 248 u64 val; 249 250 if (xdr_stream_decode_u64(xdr, &val)) { 251 nfserr = nfserr_bad_xdr; 252 goto fail; 253 } 254 if (val & (block_size - 1)) { 255 nfserr = nfserr_inval; 256 goto fail; 257 } 258 iomaps[i].offset = val; 259 260 if (xdr_stream_decode_u64(xdr, &val)) { 261 nfserr = nfserr_bad_xdr; 262 goto fail; 263 } 264 if (val & (block_size - 1)) { 265 nfserr = nfserr_inval; 266 goto fail; 267 } 268 iomaps[i].length = val; 269 } 270 271 *iomapp = iomaps; 272 *nr_iomapsp = nr_iomaps; 273 return nfs_ok; 274 fail: 275 kfree(iomaps); 276 return nfserr; 277 } 278