]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
NFS: Support larger readdir buffers
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sun, 1 Nov 2020 19:26:47 +0000 (14:26 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 2 Dec 2020 19:05:52 +0000 (14:05 -0500)
Support readdir buffers of up to 1MB in size so that we can read
large directories using few RPC calls.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Tested-by: Benjamin Coddington <bcodding@redhat.com>
Tested-by: Dave Wysochanski <dwysocha@redhat.com>
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/internal.h

index 4b8cc93913f746b7734f994bd58f8b44c45895ab..f6454ba53d05d53c7a50b7979da6003a339d399c 100644 (file)
@@ -781,8 +781,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
        server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
 
        server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
-       if (server->dtsize > PAGE_SIZE * NFS_MAX_READDIR_PAGES)
-               server->dtsize = PAGE_SIZE * NFS_MAX_READDIR_PAGES;
+       if (server->dtsize > NFS_MAX_FILE_IO_SIZE)
+               server->dtsize = NFS_MAX_FILE_IO_SIZE;
        if (server->dtsize > server->rsize)
                server->dtsize = server->rsize;
 
index be0e2891fecc4bdf9a29ed7e2fb4e97e412deb8f..438906dae08331c9be8d54aff3f78e8171ed1cc9 100644 (file)
@@ -727,44 +727,47 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
        return status;
 }
 
-static
-void nfs_readdir_free_pages(struct page **pages, unsigned int npages)
+static void nfs_readdir_free_pages(struct page **pages, size_t npages)
 {
-       unsigned int i;
-       for (i = 0; i < npages; i++)
-               put_page(pages[i]);
+       while (npages--)
+               put_page(pages[npages]);
+       kfree(pages);
 }
 
 /*
  * nfs_readdir_alloc_pages() will allocate pages that must be freed with a call
  * to nfs_readdir_free_pages()
  */
-static
-int nfs_readdir_alloc_pages(struct page **pages, unsigned int npages)
+static struct page **nfs_readdir_alloc_pages(size_t npages)
 {
-       unsigned int i;
+       struct page **pages;
+       size_t i;
 
+       pages = kmalloc_array(npages, sizeof(*pages), GFP_KERNEL);
+       if (!pages)
+               return NULL;
        for (i = 0; i < npages; i++) {
                struct page *page = alloc_page(GFP_KERNEL);
                if (page == NULL)
                        goto out_freepages;
                pages[i] = page;
        }
-       return 0;
+       return pages;
 
 out_freepages:
        nfs_readdir_free_pages(pages, i);
-       return -ENOMEM;
+       return NULL;
 }
 
 static
 int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode)
 {
-       struct page *pages[NFS_MAX_READDIR_PAGES];
+       struct page **pages;
        struct nfs_entry entry;
        struct file     *file = desc->file;
+       size_t array_size;
+       size_t dtsize = NFS_SERVER(inode)->dtsize;
        int status = -ENOMEM;
-       unsigned int array_size = ARRAY_SIZE(pages);
 
        entry.prev_cookie = 0;
        entry.cookie = nfs_readdir_page_last_cookie(page);
@@ -781,9 +784,11 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
                goto out;
        }
 
-       status = nfs_readdir_alloc_pages(pages, array_size);
-       if (status < 0)
+       array_size = (dtsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       pages = nfs_readdir_alloc_pages(array_size);
+       if (!pages)
                goto out_release_label;
+
        do {
                unsigned int pglen;
                status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode);
index 6673a77884d9daeeee1f11f565ef541779e28fa7..b840d0a91c9d8f2d7f704eb2ab1b1eb311dc1539 100644 (file)
@@ -56,12 +56,6 @@ static inline bool nfs_lookup_is_soft_revalidate(const struct dentry *dentry)
 #define NFS_UNSPEC_RETRANS     (UINT_MAX)
 #define NFS_UNSPEC_TIMEO       (UINT_MAX)
 
-/*
- * Maximum number of pages that readdir can use for creating
- * a vmapped array of pages.
- */
-#define NFS_MAX_READDIR_PAGES 8
-
 struct nfs_client_initdata {
        unsigned long init_flags;
        const char *hostname;                   /* Hostname of the server */