diff options
author | Maxim Patlasov <mpatlasov@parallels.com> | 2012-10-26 11:49:24 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2013-01-24 10:21:27 -0500 |
commit | b2430d7567a376b3685627ca7e9d712f6f27d49b (patch) | |
tree | 2c59795b27e57f6a0a6c15d0f8aea3aac32f8317 /fs/fuse | |
parent | 54b966702dafe396b6f4e609f222b8e0fdb4d7a4 (diff) |
fuse: add per-page descriptor <offset, length> to fuse_req
The ability to save page pointers along with lengths and offsets in fuse_req
will be useful to cover several iovec-s with a single fuse_req.
Per-request page_offset is removed because anybody who need it can use
req->page_descs[0].offset instead.
Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dev.c | 28 | ||||
-rw-r--r-- | fs/fuse/file.c | 10 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 15 |
3 files changed, 37 insertions, 16 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 28d9792de4a2..db4af8f3886a 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -35,15 +35,18 @@ static struct fuse_conn *fuse_get_conn(struct file *file) | |||
35 | } | 35 | } |
36 | 36 | ||
37 | static void fuse_request_init(struct fuse_req *req, struct page **pages, | 37 | static void fuse_request_init(struct fuse_req *req, struct page **pages, |
38 | struct fuse_page_desc *page_descs, | ||
38 | unsigned npages) | 39 | unsigned npages) |
39 | { | 40 | { |
40 | memset(req, 0, sizeof(*req)); | 41 | memset(req, 0, sizeof(*req)); |
41 | memset(pages, 0, sizeof(*pages) * npages); | 42 | memset(pages, 0, sizeof(*pages) * npages); |
43 | memset(page_descs, 0, sizeof(*page_descs) * npages); | ||
42 | INIT_LIST_HEAD(&req->list); | 44 | INIT_LIST_HEAD(&req->list); |
43 | INIT_LIST_HEAD(&req->intr_entry); | 45 | INIT_LIST_HEAD(&req->intr_entry); |
44 | init_waitqueue_head(&req->waitq); | 46 | init_waitqueue_head(&req->waitq); |
45 | atomic_set(&req->count, 1); | 47 | atomic_set(&req->count, 1); |
46 | req->pages = pages; | 48 | req->pages = pages; |
49 | req->page_descs = page_descs; | ||
47 | req->max_pages = npages; | 50 | req->max_pages = npages; |
48 | } | 51 | } |
49 | 52 | ||
@@ -52,18 +55,25 @@ static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags) | |||
52 | struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags); | 55 | struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags); |
53 | if (req) { | 56 | if (req) { |
54 | struct page **pages; | 57 | struct page **pages; |
58 | struct fuse_page_desc *page_descs; | ||
55 | 59 | ||
56 | if (npages <= FUSE_REQ_INLINE_PAGES) | 60 | if (npages <= FUSE_REQ_INLINE_PAGES) { |
57 | pages = req->inline_pages; | 61 | pages = req->inline_pages; |
58 | else | 62 | page_descs = req->inline_page_descs; |
63 | } else { | ||
59 | pages = kmalloc(sizeof(struct page *) * npages, flags); | 64 | pages = kmalloc(sizeof(struct page *) * npages, flags); |
65 | page_descs = kmalloc(sizeof(struct fuse_page_desc) * | ||
66 | npages, flags); | ||
67 | } | ||
60 | 68 | ||
61 | if (!pages) { | 69 | if (!pages || !page_descs) { |
70 | kfree(pages); | ||
71 | kfree(page_descs); | ||
62 | kmem_cache_free(fuse_req_cachep, req); | 72 | kmem_cache_free(fuse_req_cachep, req); |
63 | return NULL; | 73 | return NULL; |
64 | } | 74 | } |
65 | 75 | ||
66 | fuse_request_init(req, pages, npages); | 76 | fuse_request_init(req, pages, page_descs, npages); |
67 | } | 77 | } |
68 | return req; | 78 | return req; |
69 | } | 79 | } |
@@ -81,8 +91,10 @@ struct fuse_req *fuse_request_alloc_nofs(unsigned npages) | |||
81 | 91 | ||
82 | void fuse_request_free(struct fuse_req *req) | 92 | void fuse_request_free(struct fuse_req *req) |
83 | { | 93 | { |
84 | if (req->pages != req->inline_pages) | 94 | if (req->pages != req->inline_pages) { |
85 | kfree(req->pages); | 95 | kfree(req->pages); |
96 | kfree(req->page_descs); | ||
97 | } | ||
86 | kmem_cache_free(fuse_req_cachep, req); | 98 | kmem_cache_free(fuse_req_cachep, req); |
87 | } | 99 | } |
88 | 100 | ||
@@ -186,7 +198,7 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req) | |||
186 | struct fuse_file *ff = file->private_data; | 198 | struct fuse_file *ff = file->private_data; |
187 | 199 | ||
188 | spin_lock(&fc->lock); | 200 | spin_lock(&fc->lock); |
189 | fuse_request_init(req, req->pages, req->max_pages); | 201 | fuse_request_init(req, req->pages, req->page_descs, req->max_pages); |
190 | BUG_ON(ff->reserved_req); | 202 | BUG_ON(ff->reserved_req); |
191 | ff->reserved_req = req; | 203 | ff->reserved_req = req; |
192 | wake_up_all(&fc->reserved_req_waitq); | 204 | wake_up_all(&fc->reserved_req_waitq); |
@@ -891,7 +903,7 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, | |||
891 | { | 903 | { |
892 | unsigned i; | 904 | unsigned i; |
893 | struct fuse_req *req = cs->req; | 905 | struct fuse_req *req = cs->req; |
894 | unsigned offset = req->page_offset; | 906 | unsigned offset = req->page_descs[0].offset; |
895 | unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset); | 907 | unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset); |
896 | 908 | ||
897 | for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) { | 909 | for (i = 0; i < req->num_pages && (nbytes || zeroing); i++) { |
@@ -1599,7 +1611,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, | |||
1599 | req->in.h.nodeid = outarg->nodeid; | 1611 | req->in.h.nodeid = outarg->nodeid; |
1600 | req->in.numargs = 2; | 1612 | req->in.numargs = 2; |
1601 | req->in.argpages = 1; | 1613 | req->in.argpages = 1; |
1602 | req->page_offset = offset; | 1614 | req->page_descs[0].offset = offset; |
1603 | req->end = fuse_retrieve_end; | 1615 | req->end = fuse_retrieve_end; |
1604 | 1616 | ||
1605 | index = outarg->offset >> PAGE_CACHE_SHIFT; | 1617 | index = outarg->offset >> PAGE_CACHE_SHIFT; |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index fdb5b33198aa..2b6f08ac62c3 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -798,7 +798,7 @@ static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file, | |||
798 | 798 | ||
799 | res = fuse_send_write(req, file, pos, count, NULL); | 799 | res = fuse_send_write(req, file, pos, count, NULL); |
800 | 800 | ||
801 | offset = req->page_offset; | 801 | offset = req->page_descs[0].offset; |
802 | count = res; | 802 | count = res; |
803 | for (i = 0; i < req->num_pages; i++) { | 803 | for (i = 0; i < req->num_pages; i++) { |
804 | struct page *page = req->pages[i]; | 804 | struct page *page = req->pages[i]; |
@@ -829,7 +829,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req, | |||
829 | int err; | 829 | int err; |
830 | 830 | ||
831 | req->in.argpages = 1; | 831 | req->in.argpages = 1; |
832 | req->page_offset = offset; | 832 | req->page_descs[0].offset = offset; |
833 | 833 | ||
834 | do { | 834 | do { |
835 | size_t tmp; | 835 | size_t tmp; |
@@ -1070,14 +1070,14 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | |||
1070 | return npages; | 1070 | return npages; |
1071 | 1071 | ||
1072 | req->num_pages = npages; | 1072 | req->num_pages = npages; |
1073 | req->page_offset = offset; | 1073 | req->page_descs[0].offset = offset; |
1074 | 1074 | ||
1075 | if (write) | 1075 | if (write) |
1076 | req->in.argpages = 1; | 1076 | req->in.argpages = 1; |
1077 | else | 1077 | else |
1078 | req->out.argpages = 1; | 1078 | req->out.argpages = 1; |
1079 | 1079 | ||
1080 | nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset; | 1080 | nbytes = (req->num_pages << PAGE_SHIFT) - req->page_descs[0].offset; |
1081 | *nbytesp = min(*nbytesp, nbytes); | 1081 | *nbytesp = min(*nbytesp, nbytes); |
1082 | 1082 | ||
1083 | return 0; | 1083 | return 0; |
@@ -1314,7 +1314,7 @@ static int fuse_writepage_locked(struct page *page) | |||
1314 | req->in.argpages = 1; | 1314 | req->in.argpages = 1; |
1315 | req->num_pages = 1; | 1315 | req->num_pages = 1; |
1316 | req->pages[0] = tmp_page; | 1316 | req->pages[0] = tmp_page; |
1317 | req->page_offset = 0; | 1317 | req->page_descs[0].offset = 0; |
1318 | req->end = fuse_writepage_end; | 1318 | req->end = fuse_writepage_end; |
1319 | req->inode = inode; | 1319 | req->inode = inode; |
1320 | 1320 | ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5b21e6ab9e75..70cef60afe0e 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -203,6 +203,12 @@ struct fuse_out { | |||
203 | struct fuse_arg args[3]; | 203 | struct fuse_arg args[3]; |
204 | }; | 204 | }; |
205 | 205 | ||
206 | /** FUSE page descriptor */ | ||
207 | struct fuse_page_desc { | ||
208 | unsigned int length; | ||
209 | unsigned int offset; | ||
210 | }; | ||
211 | |||
206 | /** The request state */ | 212 | /** The request state */ |
207 | enum fuse_req_state { | 213 | enum fuse_req_state { |
208 | FUSE_REQ_INIT = 0, | 214 | FUSE_REQ_INIT = 0, |
@@ -296,18 +302,21 @@ struct fuse_req { | |||
296 | /** page vector */ | 302 | /** page vector */ |
297 | struct page **pages; | 303 | struct page **pages; |
298 | 304 | ||
305 | /** page-descriptor vector */ | ||
306 | struct fuse_page_desc *page_descs; | ||
307 | |||
299 | /** size of the 'pages' array */ | 308 | /** size of the 'pages' array */ |
300 | unsigned max_pages; | 309 | unsigned max_pages; |
301 | 310 | ||
302 | /** inline page vector */ | 311 | /** inline page vector */ |
303 | struct page *inline_pages[FUSE_REQ_INLINE_PAGES]; | 312 | struct page *inline_pages[FUSE_REQ_INLINE_PAGES]; |
304 | 313 | ||
314 | /** inline page-descriptor vector */ | ||
315 | struct fuse_page_desc inline_page_descs[FUSE_REQ_INLINE_PAGES]; | ||
316 | |||
305 | /** number of pages in vector */ | 317 | /** number of pages in vector */ |
306 | unsigned num_pages; | 318 | unsigned num_pages; |
307 | 319 | ||
308 | /** offset of data on first page */ | ||
309 | unsigned page_offset; | ||
310 | |||
311 | /** File used in the request (or NULL) */ | 320 | /** File used in the request (or NULL) */ |
312 | struct fuse_file *ff; | 321 | struct fuse_file *ff; |
313 | 322 | ||