root/fs/nfsd/blocklayoutxdr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfsd4_block_encode_layoutget
  2. nfsd4_block_encode_volume
  3. nfsd4_block_encode_getdeviceinfo
  4. nfsd4_block_decode_layoutupdate
  5. nfsd4_scsi_decode_layoutupdate

   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
  17 nfsd4_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 
  40 static int
  41 nfsd4_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
  78 nfsd4_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 
 105 int
 106 nfsd4_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;
 172 fail:
 173         kfree(iomaps);
 174         return -EINVAL;
 175 }
 176 
 177 int
 178 nfsd4_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;
 223 fail:
 224         kfree(iomaps);
 225         return -EINVAL;
 226 }

/* [<][>][^][v][top][bottom][index][help] */