[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>

authored by Miklos Szeredi and committed by Linus Torvalds c1aa96a5 361b1eb5

+27 -17
+27 -17
fs/fuse/file.c
··· 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; ··· 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 + } 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); 329 341 } 330 342 331 343 struct fuse_readpages_data { ··· 357 345 (req->num_pages == FUSE_MAX_PAGES_PER_REQ || 358 346 (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || 359 347 req->pages[req->num_pages - 1]->index + 1 != page->index)) { 360 - int err = fuse_send_readpages(req, data->file, inode); 361 - if (err) { 348 + fuse_send_readpages(req, data->file, inode); 349 + data->req = req = fuse_get_request(fc); 350 + if (!req) { 362 351 unlock_page(page); 363 - return err; 352 + return -EINTR; 364 353 } 365 - fuse_reset_request(req); 366 354 } 367 355 req->pages[req->num_pages] = page; 368 356 req->num_pages ++; ··· 387 375 return -EINTR; 388 376 389 377 err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); 390 - if (!err && data.req->num_pages) 391 - err = fuse_send_readpages(data.req, file, inode); 392 - fuse_put_request(fc, data.req); 393 - fuse_invalidate_attr(inode); /* atime changed */ 378 + if (!err) 379 + fuse_send_readpages(data.req, file, inode); 394 380 return err; 395 381 } 396 382