diff options
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r-- | fs/fuse/file.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a9f5e137f1d3..ada0adeb3bb5 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -351,10 +351,9 @@ static void fuse_sync_writes(struct inode *inode) | |||
351 | fuse_release_nowrite(inode); | 351 | fuse_release_nowrite(inode); |
352 | } | 352 | } |
353 | 353 | ||
354 | int fuse_fsync_common(struct file *file, struct dentry *de, int datasync, | 354 | int fuse_fsync_common(struct file *file, int datasync, int isdir) |
355 | int isdir) | ||
356 | { | 355 | { |
357 | struct inode *inode = de->d_inode; | 356 | struct inode *inode = file->f_mapping->host; |
358 | struct fuse_conn *fc = get_fuse_conn(inode); | 357 | struct fuse_conn *fc = get_fuse_conn(inode); |
359 | struct fuse_file *ff = file->private_data; | 358 | struct fuse_file *ff = file->private_data; |
360 | struct fuse_req *req; | 359 | struct fuse_req *req; |
@@ -403,9 +402,9 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync, | |||
403 | return err; | 402 | return err; |
404 | } | 403 | } |
405 | 404 | ||
406 | static int fuse_fsync(struct file *file, struct dentry *de, int datasync) | 405 | static int fuse_fsync(struct file *file, int datasync) |
407 | { | 406 | { |
408 | return fuse_fsync_common(file, de, datasync, 0); | 407 | return fuse_fsync_common(file, datasync, 0); |
409 | } | 408 | } |
410 | 409 | ||
411 | void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos, | 410 | void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos, |
@@ -517,17 +516,26 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) | |||
517 | int i; | 516 | int i; |
518 | size_t count = req->misc.read.in.size; | 517 | size_t count = req->misc.read.in.size; |
519 | size_t num_read = req->out.args[0].size; | 518 | size_t num_read = req->out.args[0].size; |
520 | struct inode *inode = req->pages[0]->mapping->host; | 519 | struct address_space *mapping = NULL; |
521 | 520 | ||
522 | /* | 521 | for (i = 0; mapping == NULL && i < req->num_pages; i++) |
523 | * Short read means EOF. If file size is larger, truncate it | 522 | mapping = req->pages[i]->mapping; |
524 | */ | ||
525 | if (!req->out.h.error && num_read < count) { | ||
526 | loff_t pos = page_offset(req->pages[0]) + num_read; | ||
527 | fuse_read_update_size(inode, pos, req->misc.read.attr_ver); | ||
528 | } | ||
529 | 523 | ||
530 | 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 | } | ||
531 | 539 | ||
532 | for (i = 0; i < req->num_pages; i++) { | 540 | for (i = 0; i < req->num_pages; i++) { |
533 | struct page *page = req->pages[i]; | 541 | struct page *page = req->pages[i]; |
@@ -536,6 +544,7 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) | |||
536 | else | 544 | else |
537 | SetPageError(page); | 545 | SetPageError(page); |
538 | unlock_page(page); | 546 | unlock_page(page); |
547 | page_cache_release(page); | ||
539 | } | 548 | } |
540 | if (req->ff) | 549 | if (req->ff) |
541 | fuse_file_put(req->ff); | 550 | fuse_file_put(req->ff); |
@@ -550,6 +559,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file) | |||
550 | 559 | ||
551 | req->out.argpages = 1; | 560 | req->out.argpages = 1; |
552 | req->out.page_zeroing = 1; | 561 | req->out.page_zeroing = 1; |
562 | req->out.page_replace = 1; | ||
553 | fuse_read_fill(req, file, pos, count, FUSE_READ); | 563 | fuse_read_fill(req, file, pos, count, FUSE_READ); |
554 | req->misc.read.attr_ver = fuse_get_attr_version(fc); | 564 | req->misc.read.attr_ver = fuse_get_attr_version(fc); |
555 | if (fc->async_read) { | 565 | if (fc->async_read) { |
@@ -589,6 +599,7 @@ static int fuse_readpages_fill(void *_data, struct page *page) | |||
589 | return PTR_ERR(req); | 599 | return PTR_ERR(req); |
590 | } | 600 | } |
591 | } | 601 | } |
602 | page_cache_get(page); | ||
592 | req->pages[req->num_pages] = page; | 603 | req->pages[req->num_pages] = page; |
593 | req->num_pages++; | 604 | req->num_pages++; |
594 | return 0; | 605 | return 0; |
@@ -994,10 +1005,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | |||
994 | 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); |
995 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; | 1006 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; |
996 | npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); | 1007 | npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); |
997 | down_read(¤t->mm->mmap_sem); | 1008 | npages = get_user_pages_fast(user_addr, npages, !write, req->pages); |
998 | npages = get_user_pages(current, current->mm, user_addr, npages, !write, | ||
999 | 0, req->pages, NULL); | ||
1000 | up_read(¤t->mm->mmap_sem); | ||
1001 | if (npages < 0) | 1009 | if (npages < 0) |
1002 | return npages; | 1010 | return npages; |
1003 | 1011 | ||
@@ -1580,9 +1588,9 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov, | |||
1580 | while (iov_iter_count(&ii)) { | 1588 | while (iov_iter_count(&ii)) { |
1581 | struct page *page = pages[page_idx++]; | 1589 | struct page *page = pages[page_idx++]; |
1582 | 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)); |
1583 | void *kaddr, *map; | 1591 | void *kaddr; |
1584 | 1592 | ||
1585 | kaddr = map = kmap(page); | 1593 | kaddr = kmap(page); |
1586 | 1594 | ||
1587 | while (todo) { | 1595 | while (todo) { |
1588 | char __user *uaddr = ii.iov->iov_base + ii.iov_offset; | 1596 | char __user *uaddr = ii.iov->iov_base + ii.iov_offset; |