Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2014-2016 Christoph Hellwig.
0004  */
0005 #include <linux/sunrpc/svc.h>
0006 #include <linux/exportfs.h>
0007 #include <linux/iomap.h>
0008 #include <linux/nfs4.h>
0009 
0010 #include "nfsd.h"
0011 #include "blocklayoutxdr.h"
0012 
0013 #define NFSDDBG_FACILITY    NFSDDBG_PNFS
0014 
0015 
0016 __be32
0017 nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
0018         struct nfsd4_layoutget *lgp)
0019 {
0020     struct pnfs_block_extent *b = lgp->lg_content;
0021     int len = sizeof(__be32) + 5 * sizeof(__be64) + sizeof(__be32);
0022     __be32 *p;
0023 
0024     p = xdr_reserve_space(xdr, sizeof(__be32) + len);
0025     if (!p)
0026         return nfserr_toosmall;
0027 
0028     *p++ = cpu_to_be32(len);
0029     *p++ = cpu_to_be32(1);      /* we always return a single extent */
0030 
0031     p = xdr_encode_opaque_fixed(p, &b->vol_id,
0032             sizeof(struct nfsd4_deviceid));
0033     p = xdr_encode_hyper(p, b->foff);
0034     p = xdr_encode_hyper(p, b->len);
0035     p = xdr_encode_hyper(p, b->soff);
0036     *p++ = cpu_to_be32(b->es);
0037     return 0;
0038 }
0039 
0040 static int
0041 nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
0042 {
0043     __be32 *p;
0044     int len;
0045 
0046     switch (b->type) {
0047     case PNFS_BLOCK_VOLUME_SIMPLE:
0048         len = 4 + 4 + 8 + 4 + (XDR_QUADLEN(b->simple.sig_len) << 2);
0049         p = xdr_reserve_space(xdr, len);
0050         if (!p)
0051             return -ETOOSMALL;
0052 
0053         *p++ = cpu_to_be32(b->type);
0054         *p++ = cpu_to_be32(1);  /* single signature */
0055         p = xdr_encode_hyper(p, b->simple.offset);
0056         p = xdr_encode_opaque(p, b->simple.sig, b->simple.sig_len);
0057         break;
0058     case PNFS_BLOCK_VOLUME_SCSI:
0059         len = 4 + 4 + 4 + 4 + (XDR_QUADLEN(b->scsi.designator_len) << 2) + 8;
0060         p = xdr_reserve_space(xdr, len);
0061         if (!p)
0062             return -ETOOSMALL;
0063 
0064         *p++ = cpu_to_be32(b->type);
0065         *p++ = cpu_to_be32(b->scsi.code_set);
0066         *p++ = cpu_to_be32(b->scsi.designator_type);
0067         p = xdr_encode_opaque(p, b->scsi.designator, b->scsi.designator_len);
0068         p = xdr_encode_hyper(p, b->scsi.pr_key);
0069         break;
0070     default:
0071         return -ENOTSUPP;
0072     }
0073 
0074     return len;
0075 }
0076 
0077 __be32
0078 nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr,
0079         struct nfsd4_getdeviceinfo *gdp)
0080 {
0081     struct pnfs_block_deviceaddr *dev = gdp->gd_device;
0082     int len = sizeof(__be32), ret, i;
0083     __be32 *p;
0084 
0085     p = xdr_reserve_space(xdr, len + sizeof(__be32));
0086     if (!p)
0087         return nfserr_resource;
0088 
0089     for (i = 0; i < dev->nr_volumes; i++) {
0090         ret = nfsd4_block_encode_volume(xdr, &dev->volumes[i]);
0091         if (ret < 0)
0092             return nfserrno(ret);
0093         len += ret;
0094     }
0095 
0096     /*
0097      * Fill in the overall length and number of volumes at the beginning
0098      * of the layout.
0099      */
0100     *p++ = cpu_to_be32(len);
0101     *p++ = cpu_to_be32(dev->nr_volumes);
0102     return 0;
0103 }
0104 
0105 int
0106 nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
0107         u32 block_size)
0108 {
0109     struct iomap *iomaps;
0110     u32 nr_iomaps, i;
0111 
0112     if (len < sizeof(u32)) {
0113         dprintk("%s: extent array too small: %u\n", __func__, len);
0114         return -EINVAL;
0115     }
0116     len -= sizeof(u32);
0117     if (len % PNFS_BLOCK_EXTENT_SIZE) {
0118         dprintk("%s: extent array invalid: %u\n", __func__, len);
0119         return -EINVAL;
0120     }
0121 
0122     nr_iomaps = be32_to_cpup(p++);
0123     if (nr_iomaps != len / PNFS_BLOCK_EXTENT_SIZE) {
0124         dprintk("%s: extent array size mismatch: %u/%u\n",
0125             __func__, len, nr_iomaps);
0126         return -EINVAL;
0127     }
0128 
0129     iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
0130     if (!iomaps) {
0131         dprintk("%s: failed to allocate extent array\n", __func__);
0132         return -ENOMEM;
0133     }
0134 
0135     for (i = 0; i < nr_iomaps; i++) {
0136         struct pnfs_block_extent bex;
0137 
0138         memcpy(&bex.vol_id, p, sizeof(struct nfsd4_deviceid));
0139         p += XDR_QUADLEN(sizeof(struct nfsd4_deviceid));
0140 
0141         p = xdr_decode_hyper(p, &bex.foff);
0142         if (bex.foff & (block_size - 1)) {
0143             dprintk("%s: unaligned offset 0x%llx\n",
0144                 __func__, bex.foff);
0145             goto fail;
0146         }
0147         p = xdr_decode_hyper(p, &bex.len);
0148         if (bex.len & (block_size - 1)) {
0149             dprintk("%s: unaligned length 0x%llx\n",
0150                 __func__, bex.foff);
0151             goto fail;
0152         }
0153         p = xdr_decode_hyper(p, &bex.soff);
0154         if (bex.soff & (block_size - 1)) {
0155             dprintk("%s: unaligned disk offset 0x%llx\n",
0156                 __func__, bex.soff);
0157             goto fail;
0158         }
0159         bex.es = be32_to_cpup(p++);
0160         if (bex.es != PNFS_BLOCK_READWRITE_DATA) {
0161             dprintk("%s: incorrect extent state %d\n",
0162                 __func__, bex.es);
0163             goto fail;
0164         }
0165 
0166         iomaps[i].offset = bex.foff;
0167         iomaps[i].length = bex.len;
0168     }
0169 
0170     *iomapp = iomaps;
0171     return nr_iomaps;
0172 fail:
0173     kfree(iomaps);
0174     return -EINVAL;
0175 }
0176 
0177 int
0178 nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
0179         u32 block_size)
0180 {
0181     struct iomap *iomaps;
0182     u32 nr_iomaps, expected, i;
0183 
0184     if (len < sizeof(u32)) {
0185         dprintk("%s: extent array too small: %u\n", __func__, len);
0186         return -EINVAL;
0187     }
0188 
0189     nr_iomaps = be32_to_cpup(p++);
0190     expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE;
0191     if (len != expected) {
0192         dprintk("%s: extent array size mismatch: %u/%u\n",
0193             __func__, len, expected);
0194         return -EINVAL;
0195     }
0196 
0197     iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
0198     if (!iomaps) {
0199         dprintk("%s: failed to allocate extent array\n", __func__);
0200         return -ENOMEM;
0201     }
0202 
0203     for (i = 0; i < nr_iomaps; i++) {
0204         u64 val;
0205 
0206         p = xdr_decode_hyper(p, &val);
0207         if (val & (block_size - 1)) {
0208             dprintk("%s: unaligned offset 0x%llx\n", __func__, val);
0209             goto fail;
0210         }
0211         iomaps[i].offset = val;
0212 
0213         p = xdr_decode_hyper(p, &val);
0214         if (val & (block_size - 1)) {
0215             dprintk("%s: unaligned length 0x%llx\n", __func__, val);
0216             goto fail;
0217         }
0218         iomaps[i].length = val;
0219     }
0220 
0221     *iomapp = iomaps;
0222     return nr_iomaps;
0223 fail:
0224     kfree(iomaps);
0225     return -EINVAL;
0226 }