Skip to content

Commit e52a825

Browse files
author
Miklos Szeredi
committed
fuse: realloc page array
Writeback caching currently allocates requests with the maximum number of possible pages, while the actual number of pages per request depends on a couple of factors that cannot be determined when the request is allocated (whether page is already under writeback, whether page is contiguous with previous pages already added to a request). This patch allows such requests to start with no page allocation (all pages inline) and grow the page array on demand. If the max_pages tunable remains the default value, then this will mean just one allocation that is the same size as before. If the tunable is larger, then this adds at most 3 additional memory allocations (which is generously compensated by the improved performance from the larger request). Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent 5da784c commit e52a825

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

fs/fuse/dev.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ static void fuse_request_init(struct fuse_req *req, struct page **pages,
5454
__set_bit(FR_PENDING, &req->flags);
5555
}
5656

57+
static struct page **fuse_req_pages_alloc(unsigned int npages, gfp_t flags,
58+
struct fuse_page_desc **desc)
59+
{
60+
struct page **pages;
61+
62+
pages = kzalloc(npages * (sizeof(struct page *) +
63+
sizeof(struct fuse_page_desc)), flags);
64+
*desc = (void *) pages + npages * sizeof(struct page *);
65+
66+
return pages;
67+
}
68+
5769
static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags)
5870
{
5971
struct fuse_req *req = kmem_cache_zalloc(fuse_req_cachep, flags);
@@ -63,13 +75,12 @@ static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags)
6375

6476
WARN_ON(npages > FUSE_MAX_MAX_PAGES);
6577
if (npages > FUSE_REQ_INLINE_PAGES) {
66-
pages = kzalloc(npages * (sizeof(*pages) +
67-
sizeof(*page_descs)), flags);
78+
pages = fuse_req_pages_alloc(npages, flags,
79+
&page_descs);
6880
if (!pages) {
6981
kmem_cache_free(fuse_req_cachep, req);
7082
return NULL;
7183
}
72-
page_descs = (void *) pages + npages * sizeof(*pages);
7384
} else if (npages) {
7485
pages = req->inline_pages;
7586
page_descs = req->inline_page_descs;
@@ -91,11 +102,41 @@ struct fuse_req *fuse_request_alloc_nofs(unsigned npages)
91102
return __fuse_request_alloc(npages, GFP_NOFS);
92103
}
93104

94-
void fuse_request_free(struct fuse_req *req)
105+
static void fuse_req_pages_free(struct fuse_req *req)
95106
{
96107
if (req->pages != req->inline_pages)
97108
kfree(req->pages);
109+
}
110+
111+
bool fuse_req_realloc_pages(struct fuse_conn *fc, struct fuse_req *req,
112+
gfp_t flags)
113+
{
114+
struct page **pages;
115+
struct fuse_page_desc *page_descs;
116+
unsigned int npages = min_t(unsigned int,
117+
max_t(unsigned int, req->max_pages * 2,
118+
FUSE_DEFAULT_MAX_PAGES_PER_REQ),
119+
fc->max_pages);
120+
WARN_ON(npages <= req->max_pages);
98121

122+
pages = fuse_req_pages_alloc(npages, flags, &page_descs);
123+
if (!pages)
124+
return false;
125+
126+
memcpy(pages, req->pages, sizeof(struct page *) * req->max_pages);
127+
memcpy(page_descs, req->page_descs,
128+
sizeof(struct fuse_page_desc) * req->max_pages);
129+
fuse_req_pages_free(req);
130+
req->pages = pages;
131+
req->page_descs = page_descs;
132+
req->max_pages = npages;
133+
134+
return true;
135+
}
136+
137+
void fuse_request_free(struct fuse_req *req)
138+
{
139+
fuse_req_pages_free(req);
99140
kmem_cache_free(fuse_req_cachep, req);
100141
}
101142

fs/fuse/file.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1827,7 +1827,13 @@ static int fuse_writepages_fill(struct page *page,
18271827
data->orig_pages[req->num_pages - 1]->index + 1 != page->index)) {
18281828
fuse_writepages_send(data);
18291829
data->req = NULL;
1830+
} else if (req && req->num_pages == req->max_pages) {
1831+
if (!fuse_req_realloc_pages(fc, req, GFP_NOFS)) {
1832+
fuse_writepages_send(data);
1833+
req = data->req = NULL;
1834+
}
18301835
}
1836+
18311837
err = -ENOMEM;
18321838
tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
18331839
if (!tmp_page)
@@ -1850,7 +1856,7 @@ static int fuse_writepages_fill(struct page *page,
18501856
struct fuse_inode *fi = get_fuse_inode(inode);
18511857

18521858
err = -ENOMEM;
1853-
req = fuse_request_alloc_nofs(fc->max_pages);
1859+
req = fuse_request_alloc_nofs(FUSE_REQ_INLINE_PAGES);
18541860
if (!req) {
18551861
__free_page(tmp_page);
18561862
goto out_unlock;

fs/fuse/fuse_i.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,10 @@ struct fuse_req *fuse_request_alloc(unsigned npages);
879879

880880
struct fuse_req *fuse_request_alloc_nofs(unsigned npages);
881881

882+
bool fuse_req_realloc_pages(struct fuse_conn *fc, struct fuse_req *req,
883+
gfp_t flags);
884+
885+
882886
/**
883887
* Free a request
884888
*/

0 commit comments

Comments
 (0)