]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFSD/blocklayout: Extract extent mapping from proc_layoutget
authorSergey Bashirov <sergeybashirov@gmail.com>
Fri, 3 Oct 2025 09:11:04 +0000 (12:11 +0300)
committerChuck Lever <chuck.lever@oracle.com>
Sun, 16 Nov 2025 23:20:11 +0000 (18:20 -0500)
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>
fs/nfsd/blocklayout.c

index 425648565ab2d419a42face83da79d23e51dfd7c..35a95501db633fcc0a98fe1f34e1c2185f84a8be 100644 (file)
 #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
-nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
-               const struct svc_fh *fhp, struct nfsd4_layoutget *args)
+nfsd4_block_map_extent(struct inode *inode, const struct svc_fh *fhp,
+               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;
-       u64 length;
-       u32 block_size = i_blocksize(inode);
-       struct pnfs_block_extent *bex;
        struct iomap iomap;
        u32 device_generation = 0;
        int error;
 
-       if (locks_in_grace(SVC_NET(rqstp)))
-               return nfserr_grace;
-
-       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);
+       error = sb->s_export_op->map_blocks(inode, offset, length, &iomap,
+                       iomode != IOMODE_READ, &device_generation);
        if (error) {
                if (error == -ENXIO)
-                       goto out_layoutunavailable;
-               goto out_error;
-       }
-
-       length = iomap.offset + iomap.length - seg->offset;
-       if (length < args->lg_minlength) {
-               dprintk("pnfsd: extent smaller than minlength\n");
-               goto out_layoutunavailable;
+                       return nfserr_layoutunavailable;
+               return nfserrno(error);
        }
 
        switch (iomap.type) {
        case IOMAP_MAPPED:
-               if (seg->iomode == IOMODE_READ)
+               if (iomode == IOMODE_READ)
                        bex->es = PNFS_BLOCK_READ_DATA;
                else
                        bex->es = PNFS_BLOCK_READWRITE_DATA;
                bex->soff = iomap.addr;
                break;
        case IOMAP_UNWRITTEN:
-               if (seg->iomode & IOMODE_RW) {
+               if (iomode & IOMODE_RW) {
                        /*
                         * Crack monkey special case from section 2.3.1.
                         */
-                       if (args->lg_minlength == 0) {
+                       if (minlength == 0) {
                                dprintk("pnfsd: no soup for you!\n");
-                               goto out_layoutunavailable;
+                               return nfserr_layoutunavailable;
                        }
 
                        bex->es = PNFS_BLOCK_INVALID_DATA;
@@ -87,7 +63,7 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
                }
                fallthrough;
        case IOMAP_HOLE:
-               if (seg->iomode == IOMODE_READ) {
+               if (iomode == IOMODE_READ) {
                        bex->es = PNFS_BLOCK_NONE_DATA;
                        break;
                }
@@ -95,27 +71,68 @@ nfsd4_block_proc_layoutget(struct svc_rqst *rqstp, struct inode *inode,
        case IOMAP_DELALLOC:
        default:
                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);
        if (error)
-               goto out_error;
+               return nfserrno(error);
+
        bex->foff = iomap.offset;
        bex->len = iomap.length;
+       return nfs_ok;
+}
+
+static __be32
+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;
 
-       seg->offset = iomap.offset;
-       seg->length = iomap.length;
+       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);
-       return 0;
+       return nfs_ok;
 
 out_error:
        seg->length = 0;
-       return nfserrno(error);
-out_layoutunavailable:
-       seg->length = 0;
-       return nfserr_layoutunavailable;
+       return nfserr;
 }
 
 static __be32