mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
295 lines
7.4 KiB
C
295 lines
7.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2014-2016 Christoph Hellwig.
|
|
*/
|
|
#include <linux/sunrpc/svc.h>
|
|
#include <linux/exportfs.h>
|
|
#include <linux/iomap.h>
|
|
#include <linux/nfs4.h>
|
|
|
|
#include "nfsd.h"
|
|
#include "blocklayoutxdr.h"
|
|
#include "vfs.h"
|
|
|
|
#define NFSDDBG_FACILITY NFSDDBG_PNFS
|
|
|
|
|
|
/**
|
|
* nfsd4_block_encode_layoutget - encode block/scsi layout extent array
|
|
* @xdr: stream for data encoding
|
|
* @lgp: layoutget content, actually an array of extents to encode
|
|
*
|
|
* Encode the opaque loc_body field in the layoutget response. Since the
|
|
* pnfs_block_layout4 and pnfs_scsi_layout4 structures on the wire are
|
|
* the same, this function is used by both layout drivers.
|
|
*
|
|
* Return values:
|
|
* %nfs_ok: Success, all extents encoded into @xdr
|
|
* %nfserr_toosmall: Not enough space in @xdr to encode all the data
|
|
*/
|
|
__be32
|
|
nfsd4_block_encode_layoutget(struct xdr_stream *xdr,
|
|
const struct nfsd4_layoutget *lgp)
|
|
{
|
|
const struct pnfs_block_layout *bl = lgp->lg_content;
|
|
u32 i, len = sizeof(__be32) + bl->nr_extents * PNFS_BLOCK_EXTENT_SIZE;
|
|
__be32 *p;
|
|
|
|
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
|
|
if (!p)
|
|
return nfserr_toosmall;
|
|
|
|
*p++ = cpu_to_be32(len);
|
|
*p++ = cpu_to_be32(bl->nr_extents);
|
|
|
|
for (i = 0; i < bl->nr_extents; i++) {
|
|
const struct pnfs_block_extent *bex = bl->extents + i;
|
|
|
|
p = svcxdr_encode_deviceid4(p, &bex->vol_id);
|
|
p = xdr_encode_hyper(p, bex->foff);
|
|
p = xdr_encode_hyper(p, bex->len);
|
|
p = xdr_encode_hyper(p, bex->soff);
|
|
*p++ = cpu_to_be32(bex->es);
|
|
}
|
|
|
|
return nfs_ok;
|
|
}
|
|
|
|
static int
|
|
nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
|
|
{
|
|
__be32 *p;
|
|
int len;
|
|
|
|
switch (b->type) {
|
|
case PNFS_BLOCK_VOLUME_SIMPLE:
|
|
len = 4 + 4 + 8 + 4 + (XDR_QUADLEN(b->simple.sig_len) << 2);
|
|
p = xdr_reserve_space(xdr, len);
|
|
if (!p)
|
|
return -ETOOSMALL;
|
|
|
|
*p++ = cpu_to_be32(b->type);
|
|
*p++ = cpu_to_be32(1); /* single signature */
|
|
p = xdr_encode_hyper(p, b->simple.offset);
|
|
p = xdr_encode_opaque(p, b->simple.sig, b->simple.sig_len);
|
|
break;
|
|
case PNFS_BLOCK_VOLUME_SCSI:
|
|
len = 4 + 4 + 4 + 4 + (XDR_QUADLEN(b->scsi.designator_len) << 2) + 8;
|
|
p = xdr_reserve_space(xdr, len);
|
|
if (!p)
|
|
return -ETOOSMALL;
|
|
|
|
*p++ = cpu_to_be32(b->type);
|
|
*p++ = cpu_to_be32(b->scsi.code_set);
|
|
*p++ = cpu_to_be32(b->scsi.designator_type);
|
|
p = xdr_encode_opaque(p, b->scsi.designator, b->scsi.designator_len);
|
|
p = xdr_encode_hyper(p, b->scsi.pr_key);
|
|
break;
|
|
default:
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
__be32
|
|
nfsd4_block_encode_getdeviceinfo(struct xdr_stream *xdr,
|
|
const struct nfsd4_getdeviceinfo *gdp)
|
|
{
|
|
struct pnfs_block_deviceaddr *dev = gdp->gd_device;
|
|
int len = sizeof(__be32), ret, i;
|
|
__be32 *p;
|
|
|
|
/*
|
|
* See paragraph 5 of RFC 8881 S18.40.3.
|
|
*/
|
|
if (!gdp->gd_maxcount) {
|
|
if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT)
|
|
return nfserr_resource;
|
|
return nfs_ok;
|
|
}
|
|
|
|
p = xdr_reserve_space(xdr, len + sizeof(__be32));
|
|
if (!p)
|
|
return nfserr_resource;
|
|
|
|
for (i = 0; i < dev->nr_volumes; i++) {
|
|
ret = nfsd4_block_encode_volume(xdr, &dev->volumes[i]);
|
|
if (ret < 0)
|
|
return nfserrno(ret);
|
|
len += ret;
|
|
}
|
|
|
|
/*
|
|
* Fill in the overall length and number of volumes at the beginning
|
|
* of the layout.
|
|
*/
|
|
*p++ = cpu_to_be32(len);
|
|
*p++ = cpu_to_be32(dev->nr_volumes);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* nfsd4_block_decode_layoutupdate - decode the block layout extent array
|
|
* @xdr: subbuf set to the encoded array
|
|
* @iomapp: pointer to store the decoded extent array
|
|
* @nr_iomapsp: pointer to store the number of extents
|
|
* @block_size: alignment of extent offset and length
|
|
*
|
|
* This function decodes the opaque field of the layoutupdate4 structure
|
|
* in a layoutcommit request for the block layout driver. The field is
|
|
* actually an array of extents sent by the client. It also checks that
|
|
* the file offset, storage offset and length of each extent are aligned
|
|
* by @block_size.
|
|
*
|
|
* Return values:
|
|
* %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid
|
|
* %nfserr_bad_xdr: The encoded array in @xdr is invalid
|
|
* %nfserr_inval: An unaligned extent found
|
|
* %nfserr_delay: Failed to allocate memory for @iomapp
|
|
*/
|
|
__be32
|
|
nfsd4_block_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp,
|
|
int *nr_iomapsp, u32 block_size)
|
|
{
|
|
struct iomap *iomaps;
|
|
u32 nr_iomaps, expected, len, i;
|
|
__be32 nfserr;
|
|
|
|
if (xdr_stream_decode_u32(xdr, &nr_iomaps))
|
|
return nfserr_bad_xdr;
|
|
|
|
len = sizeof(__be32) + xdr_stream_remaining(xdr);
|
|
expected = sizeof(__be32) + nr_iomaps * PNFS_BLOCK_EXTENT_SIZE;
|
|
if (len != expected)
|
|
return nfserr_bad_xdr;
|
|
|
|
iomaps = kzalloc_objs(*iomaps, nr_iomaps);
|
|
if (!iomaps)
|
|
return nfserr_delay;
|
|
|
|
for (i = 0; i < nr_iomaps; i++) {
|
|
struct pnfs_block_extent bex;
|
|
|
|
if (nfsd4_decode_deviceid4(xdr, &bex.vol_id)) {
|
|
nfserr = nfserr_bad_xdr;
|
|
goto fail;
|
|
}
|
|
|
|
if (xdr_stream_decode_u64(xdr, &bex.foff)) {
|
|
nfserr = nfserr_bad_xdr;
|
|
goto fail;
|
|
}
|
|
if (bex.foff & (block_size - 1)) {
|
|
nfserr = nfserr_inval;
|
|
goto fail;
|
|
}
|
|
|
|
if (xdr_stream_decode_u64(xdr, &bex.len)) {
|
|
nfserr = nfserr_bad_xdr;
|
|
goto fail;
|
|
}
|
|
if (bex.len & (block_size - 1)) {
|
|
nfserr = nfserr_inval;
|
|
goto fail;
|
|
}
|
|
|
|
if (xdr_stream_decode_u64(xdr, &bex.soff)) {
|
|
nfserr = nfserr_bad_xdr;
|
|
goto fail;
|
|
}
|
|
if (bex.soff & (block_size - 1)) {
|
|
nfserr = nfserr_inval;
|
|
goto fail;
|
|
}
|
|
|
|
if (xdr_stream_decode_u32(xdr, &bex.es)) {
|
|
nfserr = nfserr_bad_xdr;
|
|
goto fail;
|
|
}
|
|
if (bex.es != PNFS_BLOCK_READWRITE_DATA) {
|
|
nfserr = nfserr_inval;
|
|
goto fail;
|
|
}
|
|
|
|
iomaps[i].offset = bex.foff;
|
|
iomaps[i].length = bex.len;
|
|
}
|
|
|
|
*iomapp = iomaps;
|
|
*nr_iomapsp = nr_iomaps;
|
|
return nfs_ok;
|
|
fail:
|
|
kfree(iomaps);
|
|
return nfserr;
|
|
}
|
|
|
|
/**
|
|
* nfsd4_scsi_decode_layoutupdate - decode the scsi layout extent array
|
|
* @xdr: subbuf set to the encoded array
|
|
* @iomapp: pointer to store the decoded extent array
|
|
* @nr_iomapsp: pointer to store the number of extents
|
|
* @block_size: alignment of extent offset and length
|
|
*
|
|
* This function decodes the opaque field of the layoutupdate4 structure
|
|
* in a layoutcommit request for the scsi layout driver. The field is
|
|
* actually an array of extents sent by the client. It also checks that
|
|
* the offset and length of each extent are aligned by @block_size.
|
|
*
|
|
* Return values:
|
|
* %nfs_ok: Successful decoding, @iomapp and @nr_iomapsp are valid
|
|
* %nfserr_bad_xdr: The encoded array in @xdr is invalid
|
|
* %nfserr_inval: An unaligned extent found
|
|
* %nfserr_delay: Failed to allocate memory for @iomapp
|
|
*/
|
|
__be32
|
|
nfsd4_scsi_decode_layoutupdate(struct xdr_stream *xdr, struct iomap **iomapp,
|
|
int *nr_iomapsp, u32 block_size)
|
|
{
|
|
struct iomap *iomaps;
|
|
u32 nr_iomaps, expected, len, i;
|
|
__be32 nfserr;
|
|
|
|
if (xdr_stream_decode_u32(xdr, &nr_iomaps))
|
|
return nfserr_bad_xdr;
|
|
|
|
len = sizeof(__be32) + xdr_stream_remaining(xdr);
|
|
expected = sizeof(__be32) + nr_iomaps * PNFS_SCSI_RANGE_SIZE;
|
|
if (len != expected)
|
|
return nfserr_bad_xdr;
|
|
|
|
iomaps = kzalloc_objs(*iomaps, nr_iomaps);
|
|
if (!iomaps)
|
|
return nfserr_delay;
|
|
|
|
for (i = 0; i < nr_iomaps; i++) {
|
|
u64 val;
|
|
|
|
if (xdr_stream_decode_u64(xdr, &val)) {
|
|
nfserr = nfserr_bad_xdr;
|
|
goto fail;
|
|
}
|
|
if (val & (block_size - 1)) {
|
|
nfserr = nfserr_inval;
|
|
goto fail;
|
|
}
|
|
iomaps[i].offset = val;
|
|
|
|
if (xdr_stream_decode_u64(xdr, &val)) {
|
|
nfserr = nfserr_bad_xdr;
|
|
goto fail;
|
|
}
|
|
if (val & (block_size - 1)) {
|
|
nfserr = nfserr_inval;
|
|
goto fail;
|
|
}
|
|
iomaps[i].length = val;
|
|
}
|
|
|
|
*iomapp = iomaps;
|
|
*nr_iomapsp = nr_iomaps;
|
|
return nfs_ok;
|
|
fail:
|
|
kfree(iomaps);
|
|
return nfserr;
|
|
}
|