NFS: Support larger readdir buffers
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>
This commit is contained in:
parent
a52a8a6ada
commit
1a34c8c9a4
3 changed files with 21 additions and 22 deletions
|
@ -781,8 +781,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
|
||||||
server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
|
server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
|
||||||
|
|
||||||
server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
|
server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
|
||||||
if (server->dtsize > PAGE_SIZE * NFS_MAX_READDIR_PAGES)
|
if (server->dtsize > NFS_MAX_FILE_IO_SIZE)
|
||||||
server->dtsize = PAGE_SIZE * NFS_MAX_READDIR_PAGES;
|
server->dtsize = NFS_MAX_FILE_IO_SIZE;
|
||||||
if (server->dtsize > server->rsize)
|
if (server->dtsize > server->rsize)
|
||||||
server->dtsize = server->rsize;
|
server->dtsize = server->rsize;
|
||||||
|
|
||||||
|
|
33
fs/nfs/dir.c
33
fs/nfs/dir.c
|
@ -727,44 +727,47 @@ static int nfs_readdir_page_filler(struct nfs_readdir_descriptor *desc,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void nfs_readdir_free_pages(struct page **pages, size_t npages)
|
||||||
void nfs_readdir_free_pages(struct page **pages, unsigned int npages)
|
|
||||||
{
|
{
|
||||||
unsigned int i;
|
while (npages--)
|
||||||
for (i = 0; i < npages; i++)
|
put_page(pages[npages]);
|
||||||
put_page(pages[i]);
|
kfree(pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nfs_readdir_alloc_pages() will allocate pages that must be freed with a call
|
* nfs_readdir_alloc_pages() will allocate pages that must be freed with a call
|
||||||
* to nfs_readdir_free_pages()
|
* to nfs_readdir_free_pages()
|
||||||
*/
|
*/
|
||||||
static
|
static struct page **nfs_readdir_alloc_pages(size_t npages)
|
||||||
int nfs_readdir_alloc_pages(struct page **pages, unsigned int 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++) {
|
for (i = 0; i < npages; i++) {
|
||||||
struct page *page = alloc_page(GFP_KERNEL);
|
struct page *page = alloc_page(GFP_KERNEL);
|
||||||
if (page == NULL)
|
if (page == NULL)
|
||||||
goto out_freepages;
|
goto out_freepages;
|
||||||
pages[i] = page;
|
pages[i] = page;
|
||||||
}
|
}
|
||||||
return 0;
|
return pages;
|
||||||
|
|
||||||
out_freepages:
|
out_freepages:
|
||||||
nfs_readdir_free_pages(pages, i);
|
nfs_readdir_free_pages(pages, i);
|
||||||
return -ENOMEM;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode)
|
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 nfs_entry entry;
|
||||||
struct file *file = desc->file;
|
struct file *file = desc->file;
|
||||||
|
size_t array_size;
|
||||||
|
size_t dtsize = NFS_SERVER(inode)->dtsize;
|
||||||
int status = -ENOMEM;
|
int status = -ENOMEM;
|
||||||
unsigned int array_size = ARRAY_SIZE(pages);
|
|
||||||
|
|
||||||
entry.prev_cookie = 0;
|
entry.prev_cookie = 0;
|
||||||
entry.cookie = nfs_readdir_page_last_cookie(page);
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = nfs_readdir_alloc_pages(pages, array_size);
|
array_size = (dtsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||||
if (status < 0)
|
pages = nfs_readdir_alloc_pages(array_size);
|
||||||
|
if (!pages)
|
||||||
goto out_release_label;
|
goto out_release_label;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
unsigned int pglen;
|
unsigned int pglen;
|
||||||
status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode);
|
status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode);
|
||||||
|
|
|
@ -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_RETRANS (UINT_MAX)
|
||||||
#define NFS_UNSPEC_TIMEO (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 {
|
struct nfs_client_initdata {
|
||||||
unsigned long init_flags;
|
unsigned long init_flags;
|
||||||
const char *hostname; /* Hostname of the server */
|
const char *hostname; /* Hostname of the server */
|
||||||
|
|
Loading…
Add table
Reference in a new issue