Message ID | 20240619173929.177818-10-cel@kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Snapshot of fixes for SCSI PR key registration | expand |
On Wed, Jun 19, 2024 at 01:39:34PM -0400, cel@kernel.org wrote: > From: Chuck Lever <chuck.lever@oracle.com> > > nfs4_get_device_info() frequently requests more than a few pages > when provisioning a nfs4_deviceid_node object. Hmm. Looks like nfs4_get_device_info uses max_resp_sz to size the buffer. In theory the max_deviceinfo_size field in struct pnfs_layoutdriver_type caps it, but that isn't actually set anywhere at all. I guess we can't really do anything to size this better, but at least for blocklayout where we usually get a single device or a handful of stripes this is quite an overallocation. And all that is just to pass it to xdr_init_decode_pages, which is using it basically as a scratchpad.
diff --git a/fs/nfs/pnfs_dev.c b/fs/nfs/pnfs_dev.c index 178001c90156..26a78d69acab 100644 --- a/fs/nfs/pnfs_dev.c +++ b/fs/nfs/pnfs_dev.c @@ -101,9 +101,8 @@ nfs4_get_device_info(struct nfs_server *server, struct nfs4_deviceid_node *d = NULL; struct pnfs_device *pdev = NULL; struct page **pages = NULL; + int rc, i, max_pages; u32 max_resp_sz; - int max_pages; - int rc, i; /* * Use the session max response size as the basis for setting @@ -125,11 +124,9 @@ nfs4_get_device_info(struct nfs_server *server, if (!pages) goto out_free_pdev; - for (i = 0; i < max_pages; i++) { - pages[i] = alloc_page(gfp_flags); - if (!pages[i]) - goto out_free_pages; - } + i = alloc_pages_bulk_array(GFP_KERNEL, max_pages, pages); + if (i != max_pages) + goto out_free_pages; memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id)); pdev->layout_type = server->pnfs_curr_ld->id; @@ -154,8 +151,8 @@ nfs4_get_device_info(struct nfs_server *server, set_bit(NFS_DEVICEID_NOCACHE, &d->flags); out_free_pages: - while (--i >= 0) - __free_page(pages[i]); + if (i) + release_pages(pages, i); kfree(pages); out_free_pdev: kfree(pdev);