linux/fs/nfsd/blocklayoutxdr.c
<<
>>
Prefs
   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
  13#define NFSDDBG_FACILITY        NFSDDBG_PNFS
  14
  15
  16__be32
  17nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
  18                struct nfsd4_layoutget *lgp)
  19{
  20        struct pnfs_block_extent *b = lgp->lg_content;
  21        int len = sizeof(__be32) + 5 * sizeof(__be64) + sizeof(__be32);
  22        __be32 *p;
  23
  24        p = xdr_reserve_space(xdr, sizeof(__be32) + len);
  25        if (!p)
  26                return nfserr_toosmall;
  27
  28        *p++ = cpu_to_be32(len);
  29        *p++ = cpu_to_be32(1);          /* we always return a single extent */
  30
  31        p = xdr_encode_opaque_fixed(p, &b->vol_id,
  32                        sizeof(struct nfsd4_deviceid));
  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
  40static int
  41nfsd4_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
  78nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr,
  79                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        p = xdr_reserve_space(xdr, len + sizeof(__be32));
  86        if (!p)
  87                return nfserr_resource;
  88
  89        for (i = 0; i < dev->nr_volumes; i++) {
  90                ret = nfsd4_block_encode_volume(xdr, &dev->volumes[i]);
  91                if (ret < 0)
  92                        return nfserrno(ret);
  93                len += ret;
  94        }
  95
  96        /*
  97         * Fill in the overall length and number of volumes at the beginning
  98         * of the layout.
  99         */
 100        *p++ = cpu_to_be32(len);
 101        *p++ = cpu_to_be32(dev->nr_volumes);
 102        return 0;
 103}
 104
 105int
 106nfsd4_block_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
 107                u32 block_size)
 108{
 109        struct iomap *iomaps;
 110        u32 nr_iomaps, i;
 111
 112        if (len < sizeof(u32)) {
 113                dprintk("%s: extent array too small: %u\n", __func__, len);
 114                return -EINVAL;
 115        }
 116        len -= sizeof(u32);
 117        if (len % PNFS_BLOCK_EXTENT_SIZE) {
 118                dprintk("%s: extent array invalid: %u\n", __func__, len);
 119                return -EINVAL;
 120        }
 121
 122        nr_iomaps = be32_to_cpup(p++);
 123        if (nr_iomaps != len / PNFS_BLOCK_EXTENT_SIZE) {
 124                dprintk("%s: extent array size mismatch: %u/%u\n",
 125                        __func__, len, nr_iomaps);
 126                return -EINVAL;
 127        }
 128
 129        iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
 130        if (!iomaps) {
 131                dprintk("%s: failed to allocate extent array\n", __func__);
 132                return -ENOMEM;
 133        }
 134
 135        for (i = 0; i < nr_iomaps; i++) {
 136                struct pnfs_block_extent bex;
 137
 138                memcpy(&bex.vol_id, p, sizeof(struct nfsd4_deviceid));
 139                p += XDR_QUADLEN(sizeof(struct nfsd4_deviceid));
 140
 141                p = xdr_decode_hyper(p, &bex.foff);
 142                if (bex.foff & (block_size - 1)) {
 143                        dprintk("%s: unaligned offset 0x%llx\n",
 144                                __func__, bex.foff);
 145                        goto fail;
 146                }
 147                p = xdr_decode_hyper(p, &bex.len);
 148                if (bex.len & (block_size - 1)) {
 149                        dprintk("%s: unaligned length 0x%llx\n",
 150                                __func__, bex.foff);
 151                        goto fail;
 152                }
 153                p = xdr_decode_hyper(p, &bex.soff);
 154                if (bex.soff & (block_size - 1)) {
 155                        dprintk("%s: unaligned disk offset 0x%llx\n",
 156                                __func__, bex.soff);
 157                        goto fail;
 158                }
 159                bex.es = be32_to_cpup(p++);
 160                if (bex.es != PNFS_BLOCK_READWRITE_DATA) {
 161                        dprintk("%s: incorrect extent state %d\n",
 162                                __func__, bex.es);
 163                        goto fail;
 164                }
 165
 166                iomaps[i].offset = bex.foff;
 167                iomaps[i].length = bex.len;
 168        }
 169
 170        *iomapp = iomaps;
 171        return nr_iomaps;
 172fail:
 173        kfree(iomaps);
 174        return -EINVAL;
 175}
 176
 177int
 178nfsd4_scsi_decode_layoutupdate(__be32 *p, u32 len, struct iomap **iomapp,
 179                u32 block_size)
 180{
 181        struct iomap *iomaps;
 182        u32 nr_iomaps, expected, i;
 183
 184        if (len < sizeof(u32)) {
 185                dprintk("%s: extent array too small: %u\n", __func__, len);
 186                return -EINVAL;
 187        }
 188
 189        nr_iomaps = be32_to_cpup(p++);
 190        expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE;
 191        if (len != expected) {
 192                dprintk("%s: extent array size mismatch: %u/%u\n",
 193                        __func__, len, expected);
 194                return -EINVAL;
 195        }
 196
 197        iomaps = kcalloc(nr_iomaps, sizeof(*iomaps), GFP_KERNEL);
 198        if (!iomaps) {
 199                dprintk("%s: failed to allocate extent array\n", __func__);
 200                return -ENOMEM;
 201        }
 202
 203        for (i = 0; i < nr_iomaps; i++) {
 204                u64 val;
 205
 206                p = xdr_decode_hyper(p, &val);
 207                if (val & (block_size - 1)) {
 208                        dprintk("%s: unaligned offset 0x%llx\n", __func__, val);
 209                        goto fail;
 210                }
 211                iomaps[i].offset = val;
 212
 213                p = xdr_decode_hyper(p, &val);
 214                if (val & (block_size - 1)) {
 215                        dprintk("%s: unaligned length 0x%llx\n", __func__, val);
 216                        goto fail;
 217                }
 218                iomaps[i].length = val;
 219        }
 220
 221        *iomapp = iomaps;
 222        return nr_iomaps;
 223fail:
 224        kfree(iomaps);
 225        return -EINVAL;
 226}
 227