Commit 1a34c8c9 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Reviewed-by: default avatarBenjamin Coddington <bcodding@redhat.com>
Tested-by: default avatarBenjamin Coddington <bcodding@redhat.com>
Tested-by: default avatarDave Wysochanski <dwysocha@redhat.com>
parent a52a8a6a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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;

+19 −14
Original line number Diff line number Diff line
@@ -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);
+0 −6
Original line number Diff line number Diff line
@@ -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 */