^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2014-2016 Christoph Hellwig.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/sunrpc/svc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/exportfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/iomap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/nfs4.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "nfsd.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "blocklayoutxdr.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define NFSDDBG_FACILITY NFSDDBG_PNFS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) __be32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct nfsd4_layoutget *lgp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct pnfs_block_extent *b = lgp->lg_content;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) int len = sizeof(__be32) + 5 * sizeof(__be64) + sizeof(__be32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) __be32 *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) p = xdr_reserve_space(xdr, sizeof(__be32) + len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) if (!p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) return nfserr_toosmall;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) *p++ = cpu_to_be32(len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *p++ = cpu_to_be32(1); /* we always return a single extent */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) p = xdr_encode_opaque_fixed(p, &b->vol_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) sizeof(struct nfsd4_deviceid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) p = xdr_encode_hyper(p, b->foff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) p = xdr_encode_hyper(p, b->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) p = xdr_encode_hyper(p, b->soff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) *p++ = cpu_to_be32(b->es);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) __be32 *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) switch (b->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) case PNFS_BLOCK_VOLUME_SIMPLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) len = 4 + 4 + 8 + 4 + (XDR_QUADLEN(b->simple.sig_len) << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) p = xdr_reserve_space(xdr, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (!p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return -ETOOSMALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *p++ = cpu_to_be32(b->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *p++ = cpu_to_be32(1); /* single signature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) p = xdr_encode_hyper(p, b->simple.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) p = xdr_encode_opaque(p, b->simple.sig, b->simple.sig_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) case PNFS_BLOCK_VOLUME_SCSI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) len = 4 + 4 + 4 + 4 + (XDR_QUADLEN(b->scsi.designator_len) << 2) + 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) p = xdr_reserve_space(xdr, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (!p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return -ETOOSMALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) *p++ = cpu_to_be32(b->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *p++ = cpu_to_be32(b->scsi.code_set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *p++ = cpu_to_be32(b->scsi.designator_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) p = xdr_encode_opaque(p, b->scsi.designator, b->scsi.designator_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) p = xdr_encode_hyper(p, b->scsi.pr_key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) __be32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct nfsd4_getdeviceinfo *gdp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct pnfs_block_deviceaddr *dev = gdp->gd_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int len = sizeof(__be32), ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) __be32 *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) p = xdr_reserve_space(xdr, len + sizeof(__be32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (!p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return nfserr_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) for (i = 0; i < dev->nr_volumes; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ret = nfsd4_block_encode_volume(xdr, &dev->volumes[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return nfserrno(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) len += ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * Fill in the overall length and number of volumes at the beginning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * of the layout.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) *p++ = cpu_to_be32(len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) *p++ = cpu_to_be32(dev->nr_volumes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) u32 block_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct iomap *iomaps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) u32 nr_iomaps, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (len < sizeof(u32)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) dprintk("%s: extent array too small: %u\n", __func__, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) len -= sizeof(u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (len % PNFS_BLOCK_EXTENT_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) dprintk("%s: extent array invalid: %u\n", __func__, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) nr_iomaps = be32_to_cpup(p++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (nr_iomaps != len / PNFS_BLOCK_EXTENT_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) dprintk("%s: extent array size mismatch: %u/%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) __func__, len, nr_iomaps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (!iomaps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) dprintk("%s: failed to allocate extent array\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) for (i = 0; i < nr_iomaps; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct pnfs_block_extent bex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) memcpy(&bex.vol_id, p, sizeof(struct nfsd4_deviceid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) p += XDR_QUADLEN(sizeof(struct nfsd4_deviceid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) p = xdr_decode_hyper(p, &bex.foff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (bex.foff & (block_size - 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) dprintk("%s: unaligned offset 0x%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) __func__, bex.foff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) p = xdr_decode_hyper(p, &bex.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (bex.len & (block_size - 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) dprintk("%s: unaligned length 0x%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) __func__, bex.foff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) p = xdr_decode_hyper(p, &bex.soff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (bex.soff & (block_size - 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) dprintk("%s: unaligned disk offset 0x%llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) __func__, bex.soff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) bex.es = be32_to_cpup(p++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (bex.es != PNFS_BLOCK_READWRITE_DATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) dprintk("%s: incorrect extent state %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) __func__, bex.es);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) iomaps[i].offset = bex.foff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) iomaps[i].length = bex.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) *iomapp = iomaps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return nr_iomaps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) kfree(iomaps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) u32 block_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct iomap *iomaps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) u32 nr_iomaps, expected, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (len < sizeof(u32)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) dprintk("%s: extent array too small: %u\n", __func__, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) nr_iomaps = be32_to_cpup(p++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (len != expected) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) dprintk("%s: extent array size mismatch: %u/%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) __func__, len, expected);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (!iomaps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) dprintk("%s: failed to allocate extent array\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) for (i = 0; i < nr_iomaps; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) u64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) p = xdr_decode_hyper(p, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (val & (block_size - 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) dprintk("%s: unaligned offset 0x%llx\n", __func__, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) iomaps[i].offset = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) p = xdr_decode_hyper(p, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (val & (block_size - 1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) dprintk("%s: unaligned length 0x%llx\n", __func__, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) iomaps[i].length = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) *iomapp = iomaps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return nr_iomaps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) kfree(iomaps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }