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 = xdr_encode_opaque_fixed(p, &b->vol_id, 33 sizeof(struct nfsd4_deviceid)); 34 p = xdr_encode_hyper(p, b->foff); 35 p = xdr_encode_hyper(p, b->len); 36 p = xdr_encode_hyper(p, b->soff); 37 *p++ = cpu_to_be32(b->es); 38 return 0; 39 } 40 41 static int 42 nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b) 43 { 44 __be32 *p; 45 int len; 46 47 switch (b->type) { 48 case PNFS_BLOCK_VOLUME_SIMPLE: 49 len = 4 + 4 + 8 + 4 + (XDR_QUADLEN(b->simple.sig_len) << 2); 50 p = xdr_reserve_space(xdr, len); 51 if (!p) 52 return -ETOOSMALL; 53 54 *p++ = cpu_to_be32(b->type); 55 *p++ = cpu_to_be32(1); /* single signature */ 56 p = xdr_encode_hyper(p, b->simple.offset); 57 p = xdr_encode_opaque(p, b->simple.sig, b->simple.sig_len); 58 break; 59 case PNFS_BLOCK_VOLUME_SCSI: 60 len = 4 + 4 + 4 + 4 + (XDR_QUADLEN(b->scsi.designator_len) << 2) + 8; 61 p = xdr_reserve_space(xdr, len); 62 if (!p) 63 return -ETOOSMALL; 64 65 *p++ = cpu_to_be32(b->type); 66 *p++ = cpu_to_be32(b->scsi.code_set); 67 *p++ = cpu_to_be32(b->scsi.designator_type); 68 p = xdr_encode_opaque(p, b->scsi.designator, b->scsi.designator_len); 69 p = xdr_encode_hyper(p, b->scsi.pr_key); 70 break; 71 default: 72 return -ENOTSUPP; 73 } 74 75 return len; 76 } 77 78 __be32 79 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr, 80 const struct nfsd4_getdeviceinfo *gdp) 81 { 82 struct pnfs_block_deviceaddr *dev = gdp->gd_device; 83 int len = sizeof(__be32), ret, i; 84 __be32 *p; 85 86 /* 87 * See paragraph 5 of RFC 8881 S18.40.3. 88 */ 89 if (!gdp->gd_maxcount) { 90 if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT) 91 return nfserr_resource; 92 return nfs_ok; 93 } 94 95 p = xdr_reserve_space(xdr, len + sizeof(__be32)); 96 if (!p) 97 return nfserr_resource; 98 99 for (i = 0; i < dev->nr_volumes; i++) { 100 ret = nfsd4_block_encode_volume(xdr, &dev->volumes[i]); 101 if (ret < 0) 102 return nfserrno(ret); 103 len += ret; 104 } 105 106 /* 107 * Fill in the overall length and number of volumes at the beginning 108 * of the layout. 109 */ 110 *p++ = cpu_to_be32(len); 111 *p++ = cpu_to_be32(dev->nr_volumes); 112 return 0; 113 } 114 115 /** 116 * nfsd4_block_decode_layoutupdate - decode the block layout extent array 117 * @p: pointer to the xdr data 118 * @len: number of bytes to decode 119 * @iomapp: pointer to store the decoded extent array 120 * @nr_iomapsp: pointer to store the number of extents 121 * @block_size: alignment of extent offset and length 122 * 123 * This function decodes the opaque field of the layoutupdate4 structure 124 * in a layoutcommit request for the block layout driver. The field is 125 * actually an array of extents sent by the client. It also checks that 126 * the file offset, storage offset and length of each extent are aligned 127 * by @block_size. 128 * 129 * Return values: 130 * %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid 131 * %nfserr_bad_xdr: The encoded array in @p is invalid 132 * %nfserr_inval: An unaligned extent found 133 * %nfserr_delay: Failed to allocate memory for @iomapp 134 */ 135 __be32 136 nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, 137 int *nr_iomapsp, u32 block_size) 138 { 139 struct iomap *iomaps; 140 u32 nr_iomaps, i; 141 142 if (len < sizeof(u32)) 143 return nfserr_bad_xdr; 144 len -= sizeof(u32); 145 if (len % PNFS_BLOCK_EXTENT_SIZE) 146 return nfserr_bad_xdr; 147 148 nr_iomaps = be32_to_cpup(p++); 149 if (nr_iomaps != len / PNFS_BLOCK_EXTENT_SIZE) 150 return nfserr_bad_xdr; 151 152 iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL); 153 if (!iomaps) 154 return nfserr_delay; 155 156 for (i = 0; i < nr_iomaps; i++) { 157 struct pnfs_block_extent bex; 158 159 memcpy(&bex.vol_id, p, sizeof(struct nfsd4_deviceid)); 160 p += XDR_QUADLEN(sizeof(struct nfsd4_deviceid)); 161 162 p = xdr_decode_hyper(p, &bex.foff); 163 if (bex.foff & (block_size - 1)) { 164 goto fail; 165 } 166 p = xdr_decode_hyper(p, &bex.len); 167 if (bex.len & (block_size - 1)) { 168 goto fail; 169 } 170 p = xdr_decode_hyper(p, &bex.soff); 171 if (bex.soff & (block_size - 1)) { 172 goto fail; 173 } 174 bex.es = be32_to_cpup(p++); 175 if (bex.es != PNFS_BLOCK_READWRITE_DATA) { 176 goto fail; 177 } 178 179 iomaps[i].offset = bex.foff; 180 iomaps[i].length = bex.len; 181 } 182 183 *iomapp = iomaps; 184 *nr_iomapsp = nr_iomaps; 185 return nfs_ok; 186 fail: 187 kfree(iomaps); 188 return nfserr_inval; 189 } 190 191 /** 192 * nfsd4_scsi_decode_layoutupdate - decode the scsi layout extent array 193 * @p: pointer to the xdr data 194 * @len: number of bytes to decode 195 * @iomapp: pointer to store the decoded extent array 196 * @nr_iomapsp: pointer to store the number of extents 197 * @block_size: alignment of extent offset and length 198 * 199 * This function decodes the opaque field of the layoutupdate4 structure 200 * in a layoutcommit request for the scsi layout driver. The field is 201 * actually an array of extents sent by the client. It also checks that 202 * the offset and length of each extent are aligned by @block_size. 203 * 204 * Return values: 205 * %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid 206 * %nfserr_bad_xdr: The encoded array in @p is invalid 207 * %nfserr_inval: An unaligned extent found 208 * %nfserr_delay: Failed to allocate memory for @iomapp 209 */ 210 __be32 211 nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp, 212 int *nr_iomapsp, u32 block_size) 213 { 214 struct iomap *iomaps; 215 u32 nr_iomaps, expected, i; 216 217 if (len < sizeof(u32)) 218 return nfserr_bad_xdr; 219 220 nr_iomaps = be32_to_cpup(p++); 221 expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE; 222 if (len != expected) 223 return nfserr_bad_xdr; 224 225 iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL); 226 if (!iomaps) 227 return nfserr_delay; 228 229 for (i = 0; i < nr_iomaps; i++) { 230 u64 val; 231 232 p = xdr_decode_hyper(p, &val); 233 if (val & (block_size - 1)) { 234 goto fail; 235 } 236 iomaps[i].offset = val; 237 238 p = xdr_decode_hyper(p, &val); 239 if (val & (block_size - 1)) { 240 goto fail; 241 } 242 iomaps[i].length = val; 243 } 244 245 *iomapp = iomaps; 246 *nr_iomapsp = nr_iomaps; 247 return nfs_ok; 248 fail: 249 kfree(iomaps); 250 return nfserr_inval; 251 } 252