Commit c1aa96a52e9594fb16296c0d76c2066773d62933
Committed by
Linus Torvalds
1 parent
361b1eb55e
[PATCH] fuse: use asynchronous READ requests for readpages
This patch changes fuse_readpages() to send READ requests asynchronously. This makes it possible for userspace filesystems to utilize the kernel readahead logic instead of having to implement their own (resulting in double caching). Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 1 changed file with 27 additions and 17 deletions Side-by-side Diff
fs/fuse/file.c
... | ... | @@ -265,7 +265,7 @@ |
265 | 265 | req->file = file; |
266 | 266 | req->in.numargs = 1; |
267 | 267 | req->in.args[0].size = sizeof(struct fuse_read_in); |
268 | - req->in.args[0].value = &inarg; | |
268 | + req->in.args[0].value = inarg; | |
269 | 269 | req->out.argpages = 1; |
270 | 270 | req->out.argvar = 1; |
271 | 271 | req->out.numargs = 1; |
272 | 272 | |
273 | 273 | |
274 | 274 | |
275 | 275 | |
... | ... | @@ -311,23 +311,35 @@ |
311 | 311 | return err; |
312 | 312 | } |
313 | 313 | |
314 | -static int fuse_send_readpages(struct fuse_req *req, struct file *file, | |
315 | - struct inode *inode) | |
314 | +static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) | |
316 | 315 | { |
317 | - loff_t pos = page_offset(req->pages[0]); | |
318 | - size_t count = req->num_pages << PAGE_CACHE_SHIFT; | |
319 | - unsigned i; | |
320 | - req->out.page_zeroing = 1; | |
321 | - fuse_send_read(req, file, inode, pos, count); | |
316 | + int i; | |
317 | + | |
318 | + fuse_invalidate_attr(req->pages[0]->mapping->host); /* atime changed */ | |
319 | + | |
322 | 320 | for (i = 0; i < req->num_pages; i++) { |
323 | 321 | struct page *page = req->pages[i]; |
324 | 322 | if (!req->out.h.error) |
325 | 323 | SetPageUptodate(page); |
324 | + else | |
325 | + SetPageError(page); | |
326 | 326 | unlock_page(page); |
327 | 327 | } |
328 | - return req->out.h.error; | |
328 | + fuse_put_request(fc, req); | |
329 | 329 | } |
330 | 330 | |
331 | +static void fuse_send_readpages(struct fuse_req *req, struct file *file, | |
332 | + struct inode *inode) | |
333 | +{ | |
334 | + struct fuse_conn *fc = get_fuse_conn(inode); | |
335 | + loff_t pos = page_offset(req->pages[0]); | |
336 | + size_t count = req->num_pages << PAGE_CACHE_SHIFT; | |
337 | + req->out.page_zeroing = 1; | |
338 | + req->end = fuse_readpages_end; | |
339 | + fuse_read_fill(req, file, inode, pos, count, FUSE_READ); | |
340 | + request_send_background(fc, req); | |
341 | +} | |
342 | + | |
331 | 343 | struct fuse_readpages_data { |
332 | 344 | struct fuse_req *req; |
333 | 345 | struct file *file; |
334 | 346 | |
335 | 347 | |
... | ... | @@ -345,12 +357,12 @@ |
345 | 357 | (req->num_pages == FUSE_MAX_PAGES_PER_REQ || |
346 | 358 | (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || |
347 | 359 | req->pages[req->num_pages - 1]->index + 1 != page->index)) { |
348 | - int err = fuse_send_readpages(req, data->file, inode); | |
349 | - if (err) { | |
360 | + fuse_send_readpages(req, data->file, inode); | |
361 | + data->req = req = fuse_get_request(fc); | |
362 | + if (!req) { | |
350 | 363 | unlock_page(page); |
351 | - return err; | |
364 | + return -EINTR; | |
352 | 365 | } |
353 | - fuse_reset_request(req); | |
354 | 366 | } |
355 | 367 | req->pages[req->num_pages] = page; |
356 | 368 | req->num_pages ++; |
... | ... | @@ -375,10 +387,8 @@ |
375 | 387 | return -EINTR; |
376 | 388 | |
377 | 389 | err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); |
378 | - if (!err && data.req->num_pages) | |
379 | - err = fuse_send_readpages(data.req, file, inode); | |
380 | - fuse_put_request(fc, data.req); | |
381 | - fuse_invalidate_attr(inode); /* atime changed */ | |
390 | + if (!err) | |
391 | + fuse_send_readpages(data.req, file, inode); | |
382 | 392 | return err; |
383 | 393 | } |
384 | 394 |