diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2005-09-09 16:10:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-09 17:03:46 -0400 |
commit | db50b96c0f28a21c5a4a19ecaba12d0972aab06a (patch) | |
tree | d7f2cb99de499c116ce08153a369044af0622c16 /fs | |
parent | 06663267b4b1e85ece73236ea720355668d4f736 (diff) |
[PATCH] FUSE - readpages operation
This patch adds readpages support to FUSE.
With the help of the readpages() operation multiple reads are bundled
together and sent as a single request to userspace. This can improve
reading performace.
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/file.c | 67 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
-rw-r--r-- | fs/fuse/inode.c | 15 |
3 files changed, 85 insertions, 0 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 96ea302db184..86ffb6db5fe7 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -227,6 +227,72 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
227 | return err; | 227 | return err; |
228 | } | 228 | } |
229 | 229 | ||
230 | static int fuse_send_readpages(struct fuse_req *req, struct file *file, | ||
231 | struct inode *inode) | ||
232 | { | ||
233 | loff_t pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT; | ||
234 | size_t count = req->num_pages << PAGE_CACHE_SHIFT; | ||
235 | unsigned i; | ||
236 | req->out.page_zeroing = 1; | ||
237 | fuse_send_read(req, file, inode, pos, count); | ||
238 | for (i = 0; i < req->num_pages; i++) { | ||
239 | struct page *page = req->pages[i]; | ||
240 | if (!req->out.h.error) | ||
241 | SetPageUptodate(page); | ||
242 | unlock_page(page); | ||
243 | } | ||
244 | return req->out.h.error; | ||
245 | } | ||
246 | |||
247 | struct fuse_readpages_data { | ||
248 | struct fuse_req *req; | ||
249 | struct file *file; | ||
250 | struct inode *inode; | ||
251 | }; | ||
252 | |||
253 | static int fuse_readpages_fill(void *_data, struct page *page) | ||
254 | { | ||
255 | struct fuse_readpages_data *data = _data; | ||
256 | struct fuse_req *req = data->req; | ||
257 | struct inode *inode = data->inode; | ||
258 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
259 | |||
260 | if (req->num_pages && | ||
261 | (req->num_pages == FUSE_MAX_PAGES_PER_REQ || | ||
262 | (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || | ||
263 | req->pages[req->num_pages - 1]->index + 1 != page->index)) { | ||
264 | int err = fuse_send_readpages(req, data->file, inode); | ||
265 | if (err) { | ||
266 | unlock_page(page); | ||
267 | return err; | ||
268 | } | ||
269 | fuse_reset_request(req); | ||
270 | } | ||
271 | req->pages[req->num_pages] = page; | ||
272 | req->num_pages ++; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int fuse_readpages(struct file *file, struct address_space *mapping, | ||
277 | struct list_head *pages, unsigned nr_pages) | ||
278 | { | ||
279 | struct inode *inode = mapping->host; | ||
280 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
281 | struct fuse_readpages_data data; | ||
282 | int err; | ||
283 | data.file = file; | ||
284 | data.inode = inode; | ||
285 | data.req = fuse_get_request_nonint(fc); | ||
286 | if (!data.req) | ||
287 | return -EINTR; | ||
288 | |||
289 | err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); | ||
290 | if (!err && data.req->num_pages) | ||
291 | err = fuse_send_readpages(data.req, file, inode); | ||
292 | fuse_put_request(fc, data.req); | ||
293 | return err; | ||
294 | } | ||
295 | |||
230 | static ssize_t fuse_send_write(struct fuse_req *req, struct file *file, | 296 | static ssize_t fuse_send_write(struct fuse_req *req, struct file *file, |
231 | struct inode *inode, loff_t pos, size_t count) | 297 | struct inode *inode, loff_t pos, size_t count) |
232 | { | 298 | { |
@@ -331,6 +397,7 @@ static struct address_space_operations fuse_file_aops = { | |||
331 | .readpage = fuse_readpage, | 397 | .readpage = fuse_readpage, |
332 | .prepare_write = fuse_prepare_write, | 398 | .prepare_write = fuse_prepare_write, |
333 | .commit_write = fuse_commit_write, | 399 | .commit_write = fuse_commit_write, |
400 | .readpages = fuse_readpages, | ||
334 | .set_page_dirty = fuse_set_page_dirty, | 401 | .set_page_dirty = fuse_set_page_dirty, |
335 | }; | 402 | }; |
336 | 403 | ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 86183c562104..aff3a01ea02b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -201,6 +201,9 @@ struct fuse_conn { | |||
201 | /** The fuse mount flags for this mount */ | 201 | /** The fuse mount flags for this mount */ |
202 | unsigned flags; | 202 | unsigned flags; |
203 | 203 | ||
204 | /** Maximum read size */ | ||
205 | unsigned max_read; | ||
206 | |||
204 | /** Readers of the connection are waiting on this */ | 207 | /** Readers of the connection are waiting on this */ |
205 | wait_queue_head_t waitq; | 208 | wait_queue_head_t waitq; |
206 | 209 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 458c62ca0fec..0b75c73386e9 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -32,6 +32,7 @@ struct fuse_mount_data { | |||
32 | unsigned rootmode; | 32 | unsigned rootmode; |
33 | unsigned user_id; | 33 | unsigned user_id; |
34 | unsigned flags; | 34 | unsigned flags; |
35 | unsigned max_read; | ||
35 | }; | 36 | }; |
36 | 37 | ||
37 | static struct inode *fuse_alloc_inode(struct super_block *sb) | 38 | static struct inode *fuse_alloc_inode(struct super_block *sb) |
@@ -250,6 +251,7 @@ enum { | |||
250 | OPT_DEFAULT_PERMISSIONS, | 251 | OPT_DEFAULT_PERMISSIONS, |
251 | OPT_ALLOW_OTHER, | 252 | OPT_ALLOW_OTHER, |
252 | OPT_KERNEL_CACHE, | 253 | OPT_KERNEL_CACHE, |
254 | OPT_MAX_READ, | ||
253 | OPT_ERR | 255 | OPT_ERR |
254 | }; | 256 | }; |
255 | 257 | ||
@@ -260,6 +262,7 @@ static match_table_t tokens = { | |||
260 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, | 262 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, |
261 | {OPT_ALLOW_OTHER, "allow_other"}, | 263 | {OPT_ALLOW_OTHER, "allow_other"}, |
262 | {OPT_KERNEL_CACHE, "kernel_cache"}, | 264 | {OPT_KERNEL_CACHE, "kernel_cache"}, |
265 | {OPT_MAX_READ, "max_read=%u"}, | ||
263 | {OPT_ERR, NULL} | 266 | {OPT_ERR, NULL} |
264 | }; | 267 | }; |
265 | 268 | ||
@@ -268,6 +271,7 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) | |||
268 | char *p; | 271 | char *p; |
269 | memset(d, 0, sizeof(struct fuse_mount_data)); | 272 | memset(d, 0, sizeof(struct fuse_mount_data)); |
270 | d->fd = -1; | 273 | d->fd = -1; |
274 | d->max_read = ~0; | ||
271 | 275 | ||
272 | while ((p = strsep(&opt, ",")) != NULL) { | 276 | while ((p = strsep(&opt, ",")) != NULL) { |
273 | int token; | 277 | int token; |
@@ -308,6 +312,12 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) | |||
308 | d->flags |= FUSE_KERNEL_CACHE; | 312 | d->flags |= FUSE_KERNEL_CACHE; |
309 | break; | 313 | break; |
310 | 314 | ||
315 | case OPT_MAX_READ: | ||
316 | if (match_int(&args[0], &value)) | ||
317 | return 0; | ||
318 | d->max_read = value; | ||
319 | break; | ||
320 | |||
311 | default: | 321 | default: |
312 | return 0; | 322 | return 0; |
313 | } | 323 | } |
@@ -329,6 +339,8 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
329 | seq_puts(m, ",allow_other"); | 339 | seq_puts(m, ",allow_other"); |
330 | if (fc->flags & FUSE_KERNEL_CACHE) | 340 | if (fc->flags & FUSE_KERNEL_CACHE) |
331 | seq_puts(m, ",kernel_cache"); | 341 | seq_puts(m, ",kernel_cache"); |
342 | if (fc->max_read != ~0) | ||
343 | seq_printf(m, ",max_read=%u", fc->max_read); | ||
332 | return 0; | 344 | return 0; |
333 | } | 345 | } |
334 | 346 | ||
@@ -453,6 +465,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
453 | 465 | ||
454 | fc->flags = d.flags; | 466 | fc->flags = d.flags; |
455 | fc->user_id = d.user_id; | 467 | fc->user_id = d.user_id; |
468 | fc->max_read = d.max_read; | ||
469 | if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) | ||
470 | fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; | ||
456 | 471 | ||
457 | err = -ENOMEM; | 472 | err = -ENOMEM; |
458 | root = get_root_inode(sb, d.rootmode); | 473 | root = get_root_inode(sb, d.rootmode); |