aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dir.c2
-rw-r--r--fs/fuse/file.c52
-rw-r--r--fs/fuse/fuse_i.h7
3 files changed, 53 insertions, 8 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 48b9971ecd97..2060bf06b906 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -132,7 +132,7 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
132 req->out.args[0].value = outarg; 132 req->out.args[0].value = outarg;
133} 133}
134 134
135static u64 fuse_get_attr_version(struct fuse_conn *fc) 135u64 fuse_get_attr_version(struct fuse_conn *fc)
136{ 136{
137 u64 curr_version; 137 u64 curr_version;
138 138
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index c5b5982bf386..a02418c89d4b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -363,7 +363,7 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
363void fuse_read_fill(struct fuse_req *req, struct file *file, 363void fuse_read_fill(struct fuse_req *req, struct file *file,
364 struct inode *inode, loff_t pos, size_t count, int opcode) 364 struct inode *inode, loff_t pos, size_t count, int opcode)
365{ 365{
366 struct fuse_read_in *inarg = &req->misc.read_in; 366 struct fuse_read_in *inarg = &req->misc.read.in;
367 struct fuse_file *ff = file->private_data; 367 struct fuse_file *ff = file->private_data;
368 368
369 inarg->fh = ff->fh; 369 inarg->fh = ff->fh;
@@ -389,7 +389,7 @@ static size_t fuse_send_read(struct fuse_req *req, struct file *file,
389 389
390 fuse_read_fill(req, file, inode, pos, count, FUSE_READ); 390 fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
391 if (owner != NULL) { 391 if (owner != NULL) {
392 struct fuse_read_in *inarg = &req->misc.read_in; 392 struct fuse_read_in *inarg = &req->misc.read.in;
393 393
394 inarg->read_flags |= FUSE_READ_LOCKOWNER; 394 inarg->read_flags |= FUSE_READ_LOCKOWNER;
395 inarg->lock_owner = fuse_lock_owner_id(fc, owner); 395 inarg->lock_owner = fuse_lock_owner_id(fc, owner);
@@ -398,11 +398,29 @@ static size_t fuse_send_read(struct fuse_req *req, struct file *file,
398 return req->out.args[0].size; 398 return req->out.args[0].size;
399} 399}
400 400
401static void fuse_read_update_size(struct inode *inode, loff_t size,
402 u64 attr_ver)
403{
404 struct fuse_conn *fc = get_fuse_conn(inode);
405 struct fuse_inode *fi = get_fuse_inode(inode);
406
407 spin_lock(&fc->lock);
408 if (attr_ver == fi->attr_version && size < inode->i_size) {
409 fi->attr_version = ++fc->attr_version;
410 i_size_write(inode, size);
411 }
412 spin_unlock(&fc->lock);
413}
414
401static int fuse_readpage(struct file *file, struct page *page) 415static int fuse_readpage(struct file *file, struct page *page)
402{ 416{
403 struct inode *inode = page->mapping->host; 417 struct inode *inode = page->mapping->host;
404 struct fuse_conn *fc = get_fuse_conn(inode); 418 struct fuse_conn *fc = get_fuse_conn(inode);
405 struct fuse_req *req; 419 struct fuse_req *req;
420 size_t num_read;
421 loff_t pos = page_offset(page);
422 size_t count = PAGE_CACHE_SIZE;
423 u64 attr_ver;
406 int err; 424 int err;
407 425
408 err = -EIO; 426 err = -EIO;
@@ -421,15 +439,25 @@ static int fuse_readpage(struct file *file, struct page *page)
421 if (IS_ERR(req)) 439 if (IS_ERR(req))
422 goto out; 440 goto out;
423 441
442 attr_ver = fuse_get_attr_version(fc);
443
424 req->out.page_zeroing = 1; 444 req->out.page_zeroing = 1;
425 req->num_pages = 1; 445 req->num_pages = 1;
426 req->pages[0] = page; 446 req->pages[0] = page;
427 fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE, 447 num_read = fuse_send_read(req, file, inode, pos, count, NULL);
428 NULL);
429 err = req->out.h.error; 448 err = req->out.h.error;
430 fuse_put_request(fc, req); 449 fuse_put_request(fc, req);
431 if (!err) 450
451 if (!err) {
452 /*
453 * Short read means EOF. If file size is larger, truncate it
454 */
455 if (num_read < count)
456 fuse_read_update_size(inode, pos + num_read, attr_ver);
457
432 SetPageUptodate(page); 458 SetPageUptodate(page);
459 }
460
433 fuse_invalidate_attr(inode); /* atime changed */ 461 fuse_invalidate_attr(inode); /* atime changed */
434 out: 462 out:
435 unlock_page(page); 463 unlock_page(page);
@@ -439,8 +467,19 @@ static int fuse_readpage(struct file *file, struct page *page)
439static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) 467static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
440{ 468{
441 int i; 469 int i;
470 size_t count = req->misc.read.in.size;
471 size_t num_read = req->out.args[0].size;
472 struct inode *inode = req->pages[0]->mapping->host;
442 473
443 fuse_invalidate_attr(req->pages[0]->mapping->host); /* atime changed */ 474 /*
475 * Short read means EOF. If file size is larger, truncate it
476 */
477 if (!req->out.h.error && num_read < count) {
478 loff_t pos = page_offset(req->pages[0]) + num_read;
479 fuse_read_update_size(inode, pos, req->misc.read.attr_ver);
480 }
481
482 fuse_invalidate_attr(inode); /* atime changed */
444 483
445 for (i = 0; i < req->num_pages; i++) { 484 for (i = 0; i < req->num_pages; i++) {
446 struct page *page = req->pages[i]; 485 struct page *page = req->pages[i];
@@ -463,6 +502,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
463 size_t count = req->num_pages << PAGE_CACHE_SHIFT; 502 size_t count = req->num_pages << PAGE_CACHE_SHIFT;
464 req->out.page_zeroing = 1; 503 req->out.page_zeroing = 1;
465 fuse_read_fill(req, file, inode, pos, count, FUSE_READ); 504 fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
505 req->misc.read.attr_ver = fuse_get_attr_version(fc);
466 if (fc->async_read) { 506 if (fc->async_read) {
467 struct fuse_file *ff = file->private_data; 507 struct fuse_file *ff = file->private_data;
468 req->ff = fuse_file_get(ff); 508 req->ff = fuse_file_get(ff);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 4b094fbc9c7f..934dd819a4ef 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -239,7 +239,10 @@ struct fuse_req {
239 } release; 239 } release;
240 struct fuse_init_in init_in; 240 struct fuse_init_in init_in;
241 struct fuse_init_out init_out; 241 struct fuse_init_out init_out;
242 struct fuse_read_in read_in; 242 struct {
243 struct fuse_read_in in;
244 u64 attr_ver;
245 } read;
243 struct { 246 struct {
244 struct fuse_write_in in; 247 struct fuse_write_in in;
245 struct fuse_write_out out; 248 struct fuse_write_out out;
@@ -637,3 +640,5 @@ void fuse_flush_writepages(struct inode *inode);
637 640
638void fuse_set_nowrite(struct inode *inode); 641void fuse_set_nowrite(struct inode *inode);
639void fuse_release_nowrite(struct inode *inode); 642void fuse_release_nowrite(struct inode *inode);
643
644u64 fuse_get_attr_version(struct fuse_conn *fc);