pNFS: Handle RPC size limit for layoutcommits
authorSergey Bashirov <sergeybashirov@gmail.com>
Mon, 30 Jun 2025 18:35:29 +0000 (21:35 +0300)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 14 Jul 2025 22:20:28 +0000 (15:20 -0700)
When there are too many block extents for a layoutcommit, they may not
all fit into the maximum-sized RPC. This patch allows the generic pnfs
code to properly handle -ENOSPC returned by the block/scsi layout driver
and trigger additional layoutcommits if necessary.

Co-developed-by: Konstantin Evtushenko <koevtushenko@yandex.com>
Signed-off-by: Konstantin Evtushenko <koevtushenko@yandex.com>
Signed-off-by: Sergey Bashirov <sergeybashirov@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20250630183537.196479-5-sergeybashirov@gmail.com
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/pnfs.c

index 1a7ec68bde15328b3a4d02489eaeb2faffc8ec02..3fd0971bf16fcfdaba390674666d3fca4a07f328 100644 (file)
@@ -3340,6 +3340,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
        struct nfs_inode *nfsi = NFS_I(inode);
        loff_t end_pos;
        int status;
+       bool mark_as_dirty = false;
 
        if (!pnfs_layoutcommit_outstanding(inode))
                return 0;
@@ -3391,19 +3392,23 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
        if (ld->prepare_layoutcommit) {
                status = ld->prepare_layoutcommit(&data->args);
                if (status) {
-                       put_cred(data->cred);
+                       if (status != -ENOSPC)
+                               put_cred(data->cred);
                        spin_lock(&inode->i_lock);
                        set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags);
                        if (end_pos > nfsi->layout->plh_lwb)
                                nfsi->layout->plh_lwb = end_pos;
-                       goto out_unlock;
+                       if (status != -ENOSPC)
+                               goto out_unlock;
+                       spin_unlock(&inode->i_lock);
+                       mark_as_dirty = true;
                }
        }
 
 
        status = nfs4_proc_layoutcommit(data, sync);
 out:
-       if (status)
+       if (status || mark_as_dirty)
                mark_inode_dirty_sync(inode);
        dprintk("<-- %s status %d\n", __func__, status);
        return status;