Linux Audio

Check our new training course

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