diff options
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r-- | fs/fuse/file.c | 39 |
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(¤t->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(¤t->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; |