aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-30 12:16:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-30 12:16:14 -0400
commit003386fff3e02e51cea882e60f7d28290113964c (patch)
tree253001a9a0fc609b757362708edc2dcaab9e2a14 /fs/fuse/file.c
parent092405cdb66f060918160ae730640b449ed7b827 (diff)
parent51921cb746f56983db5a373ca68deb2b0d3ddf01 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: mm: export generic_pipe_buf_*() to modules fuse: support splice() reading from fuse device fuse: allow splice to move pages mm: export remove_from_page_cache() to modules mm: export lru_cache_add_*() to modules fuse: support splice() writing to fuse device fuse: get page reference for readpages fuse: use get_user_pages_fast() fuse: remove unneeded variable
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r--fs/fuse/file.c39
1 files changed, 24 insertions, 15 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b5fd6f9905e4..ada0adeb3bb5 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -516,17 +516,26 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
516 int i; 516 int i;
517 size_t count = req->misc.read.in.size; 517 size_t count = req->misc.read.in.size;
518 size_t num_read = req->out.args[0].size; 518 size_t num_read = req->out.args[0].size;
519 struct inode *inode = req->pages[0]->mapping->host; 519 struct address_space *mapping = NULL;
520 520
521 /* 521 for (i = 0; mapping == NULL && i < req->num_pages; i++)
522 * Short read means EOF. If file size is larger, truncate it 522 mapping = req->pages[i]->mapping;
523 */
524 if (!req->out.h.error && num_read < count) {
525 loff_t pos = page_offset(req->pages[0]) + num_read;
526 fuse_read_update_size(inode, pos, req->misc.read.attr_ver);
527 }
528 523
529 fuse_invalidate_attr(inode); /* atime changed */ 524 if (mapping) {
525 struct inode *inode = mapping->host;
526
527 /*
528 * Short read means EOF. If file size is larger, truncate it
529 */
530 if (!req->out.h.error && num_read < count) {
531 loff_t pos;
532
533 pos = page_offset(req->pages[0]) + num_read;
534 fuse_read_update_size(inode, pos,
535 req->misc.read.attr_ver);
536 }
537 fuse_invalidate_attr(inode); /* atime changed */
538 }
530 539
531 for (i = 0; i < req->num_pages; i++) { 540 for (i = 0; i < req->num_pages; i++) {
532 struct page *page = req->pages[i]; 541 struct page *page = req->pages[i];
@@ -535,6 +544,7 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
535 else 544 else
536 SetPageError(page); 545 SetPageError(page);
537 unlock_page(page); 546 unlock_page(page);
547 page_cache_release(page);
538 } 548 }
539 if (req->ff) 549 if (req->ff)
540 fuse_file_put(req->ff); 550 fuse_file_put(req->ff);
@@ -549,6 +559,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file)
549 559
550 req->out.argpages = 1; 560 req->out.argpages = 1;
551 req->out.page_zeroing = 1; 561 req->out.page_zeroing = 1;
562 req->out.page_replace = 1;
552 fuse_read_fill(req, file, pos, count, FUSE_READ); 563 fuse_read_fill(req, file, pos, count, FUSE_READ);
553 req->misc.read.attr_ver = fuse_get_attr_version(fc); 564 req->misc.read.attr_ver = fuse_get_attr_version(fc);
554 if (fc->async_read) { 565 if (fc->async_read) {
@@ -588,6 +599,7 @@ static int fuse_readpages_fill(void *_data, struct page *page)
588 return PTR_ERR(req); 599 return PTR_ERR(req);
589 } 600 }
590 } 601 }
602 page_cache_get(page);
591 req->pages[req->num_pages] = page; 603 req->pages[req->num_pages] = page;
592 req->num_pages++; 604 req->num_pages++;
593 return 0; 605 return 0;
@@ -993,10 +1005,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
993 nbytes = min_t(size_t, nbytes, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); 1005 nbytes = min_t(size_t, nbytes, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
994 npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; 1006 npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
995 npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); 1007 npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ);
996 down_read(&current->mm->mmap_sem); 1008 npages = get_user_pages_fast(user_addr, npages, !write, req->pages);
997 npages = get_user_pages(current, current->mm, user_addr, npages, !write,
998 0, req->pages, NULL);
999 up_read(&current->mm->mmap_sem);
1000 if (npages < 0) 1009 if (npages < 0)
1001 return npages; 1010 return npages;
1002 1011
@@ -1579,9 +1588,9 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
1579 while (iov_iter_count(&ii)) { 1588 while (iov_iter_count(&ii)) {
1580 struct page *page = pages[page_idx++]; 1589 struct page *page = pages[page_idx++];
1581 size_t todo = min_t(size_t, PAGE_SIZE, iov_iter_count(&ii)); 1590 size_t todo = min_t(size_t, PAGE_SIZE, iov_iter_count(&ii));
1582 void *kaddr, *map; 1591 void *kaddr;
1583 1592
1584 kaddr = map = kmap(page); 1593 kaddr = kmap(page);
1585 1594
1586 while (todo) { 1595 while (todo) {
1587 char __user *uaddr = ii.iov->iov_base + ii.iov_offset; 1596 char __user *uaddr = ii.iov->iov_base + ii.iov_offset;