diff options
-rw-r--r-- | fs/fuse/dir.c | 2 | ||||
-rw-r--r-- | fs/fuse/file.c | 52 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 7 |
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 | ||
135 | static u64 fuse_get_attr_version(struct fuse_conn *fc) | 135 | u64 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) | |||
363 | void fuse_read_fill(struct fuse_req *req, struct file *file, | 363 | void 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 | ||
401 | static 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 | |||
401 | static int fuse_readpage(struct file *file, struct page *page) | 415 | static 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) | |||
439 | static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) | 467 | static 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 | ||
638 | void fuse_set_nowrite(struct inode *inode); | 641 | void fuse_set_nowrite(struct inode *inode); |
639 | void fuse_release_nowrite(struct inode *inode); | 642 | void fuse_release_nowrite(struct inode *inode); |
643 | |||
644 | u64 fuse_get_attr_version(struct fuse_conn *fc); | ||