diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-07 10:22:53 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-11 22:29:47 -0400 |
commit | 0b8def9d6dfa6b2a9a2740cf81d8d2c134688d39 (patch) | |
tree | b9f8769682257d9a8ec4ccb0a3253d021fd68ce8 /mm | |
parent | e9d1593d4e9311bca040ecf6ec7599e6f235140c (diff) |
__generic_file_write_iter: keep ->ki_pos and return value consistent
A side effect worth noting: in O_APPEND case we set ->ki_pos early,
so if it turns out to be an error or a zero-length write, we'll
end up with ->ki_pos modified. Safe, since all callers never
look at the ->ki_pos after the call of __generic_file_write_iter()
returning non-positive, all the way to caller of ->write_iter() and
those discard ->ki_pos when getting that.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 24 |
1 files changed, 10 insertions, 14 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 9920db455f05..353f82e09e63 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2557,7 +2557,6 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2557 | struct file *file = iocb->ki_filp; | 2557 | struct file *file = iocb->ki_filp; |
2558 | struct address_space * mapping = file->f_mapping; | 2558 | struct address_space * mapping = file->f_mapping; |
2559 | struct inode *inode = mapping->host; | 2559 | struct inode *inode = mapping->host; |
2560 | loff_t pos = iocb->ki_pos; | ||
2561 | ssize_t written = 0; | 2560 | ssize_t written = 0; |
2562 | ssize_t err; | 2561 | ssize_t err; |
2563 | ssize_t status; | 2562 | ssize_t status; |
@@ -2565,7 +2564,7 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2565 | 2564 | ||
2566 | /* We can write back this queue in page reclaim */ | 2565 | /* We can write back this queue in page reclaim */ |
2567 | current->backing_dev_info = inode_to_bdi(inode); | 2566 | current->backing_dev_info = inode_to_bdi(inode); |
2568 | err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); | 2567 | err = generic_write_checks(file, &iocb->ki_pos, &count, S_ISBLK(inode->i_mode)); |
2569 | if (err) | 2568 | if (err) |
2570 | goto out; | 2569 | goto out; |
2571 | 2570 | ||
@@ -2583,9 +2582,9 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2583 | goto out; | 2582 | goto out; |
2584 | 2583 | ||
2585 | if (io_is_direct(file)) { | 2584 | if (io_is_direct(file)) { |
2586 | loff_t endbyte; | 2585 | loff_t pos, endbyte; |
2587 | 2586 | ||
2588 | written = generic_file_direct_write(iocb, from, pos); | 2587 | written = generic_file_direct_write(iocb, from, iocb->ki_pos); |
2589 | /* | 2588 | /* |
2590 | * If the write stopped short of completing, fall back to | 2589 | * If the write stopped short of completing, fall back to |
2591 | * buffered writes. Some filesystems do this for writes to | 2590 | * buffered writes. Some filesystems do this for writes to |
@@ -2593,13 +2592,10 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2593 | * not succeed (even if it did, DAX does not handle dirty | 2592 | * not succeed (even if it did, DAX does not handle dirty |
2594 | * page-cache pages correctly). | 2593 | * page-cache pages correctly). |
2595 | */ | 2594 | */ |
2596 | if (written < 0 || written == count || IS_DAX(inode)) | 2595 | if (written < 0 || !iov_iter_count(from) || IS_DAX(inode)) |
2597 | goto out; | 2596 | goto out; |
2598 | 2597 | ||
2599 | pos += written; | 2598 | status = generic_perform_write(file, from, pos = iocb->ki_pos); |
2600 | count -= written; | ||
2601 | |||
2602 | status = generic_perform_write(file, from, pos); | ||
2603 | /* | 2599 | /* |
2604 | * If generic_perform_write() returned a synchronous error | 2600 | * If generic_perform_write() returned a synchronous error |
2605 | * then we want to return the number of bytes which were | 2601 | * then we want to return the number of bytes which were |
@@ -2611,15 +2607,15 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2611 | err = status; | 2607 | err = status; |
2612 | goto out; | 2608 | goto out; |
2613 | } | 2609 | } |
2614 | iocb->ki_pos = pos + status; | ||
2615 | /* | 2610 | /* |
2616 | * We need to ensure that the page cache pages are written to | 2611 | * We need to ensure that the page cache pages are written to |
2617 | * disk and invalidated to preserve the expected O_DIRECT | 2612 | * disk and invalidated to preserve the expected O_DIRECT |
2618 | * semantics. | 2613 | * semantics. |
2619 | */ | 2614 | */ |
2620 | endbyte = pos + status - 1; | 2615 | endbyte = pos + status - 1; |
2621 | err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte); | 2616 | err = filemap_write_and_wait_range(mapping, pos, endbyte); |
2622 | if (err == 0) { | 2617 | if (err == 0) { |
2618 | iocb->ki_pos = endbyte + 1; | ||
2623 | written += status; | 2619 | written += status; |
2624 | invalidate_mapping_pages(mapping, | 2620 | invalidate_mapping_pages(mapping, |
2625 | pos >> PAGE_CACHE_SHIFT, | 2621 | pos >> PAGE_CACHE_SHIFT, |
@@ -2631,9 +2627,9 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
2631 | */ | 2627 | */ |
2632 | } | 2628 | } |
2633 | } else { | 2629 | } else { |
2634 | written = generic_perform_write(file, from, pos); | 2630 | written = generic_perform_write(file, from, iocb->ki_pos); |
2635 | if (likely(written >= 0)) | 2631 | if (likely(written > 0)) |
2636 | iocb->ki_pos = pos + written; | 2632 | iocb->ki_pos += written; |
2637 | } | 2633 | } |
2638 | out: | 2634 | out: |
2639 | current->backing_dev_info = NULL; | 2635 | current->backing_dev_info = NULL; |