blocklayoutxdr.c 7.4 KB

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