NFSD/blocklayout: Extract extent mapping from proc_layoutget

No changes in functionality. Split the proc_layoutget function to
create a helper function that maps single extent to the requested
range. This helper function is then used to implement support for
multiple extents per LAYOUTGET.

Signed-off-by: Sergey Bashirov <sergeybashirov@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
Sergey Bashirov
2025-10-03 12:11:04 +03:00
committed by Chuck Lever
parent 3524b021b0
commit a1dce715c6

View File

@@ -17,68 +17,44 @@
#define NFSDDBG_FACILITY NFSDDBG_PNFS #define NFSDDBG_FACILITY NFSDDBG_PNFS
/*
* Get an extent from the file system that starts at offset or below
* and may be shorter than the requested length.
*/
static __be32 static __be32
nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode, nfsd4_block_map_extent(struct inode *inode, const struct svc_fh *fhp,
const struct svc_fh *fhp, struct nfsd4_layoutget *args) u64 offset, u64 length, u32 iomode, u64 minlength,
struct pnfs_block_extent *bex)
{ {
struct nfsd4_layout_seg *seg = &args->lg_seg;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
u64 length;
u32 block_size = i_blocksize(inode);
struct pnfs_block_extent *bex;
struct iomap iomap; struct iomap iomap;
u32 device_generation = 0; u32 device_generation = 0;
int error; int error;
if (locks_in_grace(SVC_NET(rqstp))) error = sb->s_export_op->map_blocks(inode, offset, length, &iomap,
return nfserr_grace; iomode != IOMODE_READ, &device_generation);
if (seg->offset & (block_size - 1)) {
dprintk("pnfsd: I/O misaligned\n");
goto out_layoutunavailable;
}
/*
* Some clients barf on non-zero block numbers for NONE or INVALID
* layouts, so make sure to zero the whole structure.
*/
error = -ENOMEM;
bex = kzalloc(sizeof(*bex), GFP_KERNEL);
if (!bex)
goto out_error;
args->lg_content = bex;
error = sb->s_export_op->map_blocks(inode, seg->offset, seg->length,
&iomap, seg->iomode != IOMODE_READ,
&device_generation);
if (error) { if (error) {
if (error == -ENXIO) if (error == -ENXIO)
goto out_layoutunavailable; return nfserr_layoutunavailable;
goto out_error; return nfserrno(error);
}
length = iomap.offset + iomap.length - seg->offset;
if (length < args->lg_minlength) {
dprintk("pnfsd: extent smaller than minlength\n");
goto out_layoutunavailable;
} }
switch (iomap.type) { switch (iomap.type) {
case IOMAP_MAPPED: case IOMAP_MAPPED:
if (seg->iomode == IOMODE_READ) if (iomode == IOMODE_READ)
bex->es = PNFS_BLOCK_READ_DATA; bex->es = PNFS_BLOCK_READ_DATA;
else else
bex->es = PNFS_BLOCK_READWRITE_DATA; bex->es = PNFS_BLOCK_READWRITE_DATA;
bex->soff = iomap.addr; bex->soff = iomap.addr;
break; break;
case IOMAP_UNWRITTEN: case IOMAP_UNWRITTEN:
if (seg->iomode & IOMODE_RW) { if (iomode & IOMODE_RW) {
/* /*
* Crack monkey special case from section 2.3.1. * Crack monkey special case from section 2.3.1.
*/ */
if (args->lg_minlength == 0) { if (minlength == 0) {
dprintk("pnfsd: no soup for you!\n"); dprintk("pnfsd: no soup for you!\n");
goto out_layoutunavailable; return nfserr_layoutunavailable;
} }
bex->es = PNFS_BLOCK_INVALID_DATA; bex->es = PNFS_BLOCK_INVALID_DATA;
@@ -87,7 +63,7 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
} }
fallthrough; fallthrough;
case IOMAP_HOLE: case IOMAP_HOLE:
if (seg->iomode == IOMODE_READ) { if (iomode == IOMODE_READ) {
bex->es = PNFS_BLOCK_NONE_DATA; bex->es = PNFS_BLOCK_NONE_DATA;
break; break;
} }
@@ -95,27 +71,68 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
case IOMAP_DELALLOC: case IOMAP_DELALLOC:
default: default:
WARN(1, "pnfsd: filesystem returned %d extent\n", iomap.type); WARN(1, "pnfsd: filesystem returned %d extent\n", iomap.type);
goto out_layoutunavailable; return nfserr_layoutunavailable;
} }
error = nfsd4_set_deviceid(&bex->vol_id, fhp, device_generation); error = nfsd4_set_deviceid(&bex->vol_id, fhp, device_generation);
if (error) if (error)
goto out_error; return nfserrno(error);
bex->foff = iomap.offset; bex->foff = iomap.offset;
bex->len = iomap.length; bex->len = iomap.length;
return nfs_ok;
}
seg->offset = iomap.offset; static __be32
seg->length = iomap.length; nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
const struct svc_fh *fhp, struct nfsd4_layoutget *args)
{
struct nfsd4_layout_seg *seg = &args->lg_seg;
struct pnfs_block_extent *bex;
u64 length;
u32 block_size = i_blocksize(inode);
__be32 nfserr;
if (locks_in_grace(SVC_NET(rqstp)))
return nfserr_grace;
nfserr = nfserr_layoutunavailable;
if (seg->offset & (block_size - 1)) {
dprintk("pnfsd: I/O misaligned\n");
goto out_error;
}
/*
* Some clients barf on non-zero block numbers for NONE or INVALID
* layouts, so make sure to zero the whole structure.
*/
nfserr = nfserrno(-ENOMEM);
bex = kzalloc(sizeof(*bex), GFP_KERNEL);
if (!bex)
goto out_error;
args->lg_content = bex;
nfserr = nfsd4_block_map_extent(inode, fhp, seg->offset, seg->length,
seg->iomode, args->lg_minlength, bex);
if (nfserr != nfs_ok)
goto out_error;
nfserr = nfserr_layoutunavailable;
length = bex->foff + bex->len - seg->offset;
if (length < args->lg_minlength) {
dprintk("pnfsd: extent smaller than minlength\n");
goto out_error;
}
seg->offset = bex->foff;
seg->length = bex->len;
dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es); dprintk("GET: 0x%llx:0x%llx %d\n", bex->foff, bex->len, bex->es);
return 0; return nfs_ok;
out_error: out_error:
seg->length = 0; seg->length = 0;
return nfserrno(error); return nfserr;
out_layoutunavailable:
seg->length = 0;
return nfserr_layoutunavailable;
} }
static __be32 static __be32