Commit 0b8def9d authored by Al Viro's avatar Al Viro

__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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent e9d1593d
...@@ -2557,7 +2557,6 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -2557,7 +2557,6 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct file *file = iocb->ki_filp; struct file *file = iocb->ki_filp;
struct address_space * mapping = file->f_mapping; struct address_space * mapping = file->f_mapping;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
loff_t pos = iocb->ki_pos;
ssize_t written = 0; ssize_t written = 0;
ssize_t err; ssize_t err;
ssize_t status; ssize_t status;
...@@ -2565,7 +2564,7 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -2565,7 +2564,7 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
/* We can write back this queue in page reclaim */ /* We can write back this queue in page reclaim */
current->backing_dev_info = inode_to_bdi(inode); current->backing_dev_info = inode_to_bdi(inode);
err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); err = generic_write_checks(file, &iocb->ki_pos, &count, S_ISBLK(inode->i_mode));
if (err) if (err)
goto out; goto out;
...@@ -2583,9 +2582,9 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -2583,9 +2582,9 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
goto out; goto out;
if (io_is_direct(file)) { if (io_is_direct(file)) {
loff_t endbyte; loff_t pos, endbyte;
written = generic_file_direct_write(iocb, from, pos); written = generic_file_direct_write(iocb, from, iocb->ki_pos);
/* /*
* If the write stopped short of completing, fall back to * If the write stopped short of completing, fall back to
* buffered writes. Some filesystems do this for writes to * 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,13 +2592,10 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
* not succeed (even if it did, DAX does not handle dirty * not succeed (even if it did, DAX does not handle dirty
* page-cache pages correctly). * page-cache pages correctly).
*/ */
if (written < 0 || written == count || IS_DAX(inode)) if (written < 0 || !iov_iter_count(from) || IS_DAX(inode))
goto out; goto out;
pos += written; status = generic_perform_write(file, from, pos = iocb->ki_pos);
count -= written;
status = generic_perform_write(file, from, pos);
/* /*
* If generic_perform_write() returned a synchronous error * If generic_perform_write() returned a synchronous error
* then we want to return the number of bytes which were * 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,15 +2607,15 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
err = status; err = status;
goto out; goto out;
} }
iocb->ki_pos = pos + status;
/* /*
* We need to ensure that the page cache pages are written to * We need to ensure that the page cache pages are written to
* disk and invalidated to preserve the expected O_DIRECT * disk and invalidated to preserve the expected O_DIRECT
* semantics. * semantics.
*/ */
endbyte = pos + status - 1; endbyte = pos + status - 1;
err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte); err = filemap_write_and_wait_range(mapping, pos, endbyte);
if (err == 0) { if (err == 0) {
iocb->ki_pos = endbyte + 1;
written += status; written += status;
invalidate_mapping_pages(mapping, invalidate_mapping_pages(mapping,
pos >> PAGE_CACHE_SHIFT, pos >> PAGE_CACHE_SHIFT,
...@@ -2631,9 +2627,9 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -2631,9 +2627,9 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
*/ */
} }
} else { } else {
written = generic_perform_write(file, from, pos); written = generic_perform_write(file, from, iocb->ki_pos);
if (likely(written >= 0)) if (likely(written > 0))
iocb->ki_pos = pos + written; iocb->ki_pos += written;
} }
out: out:
current->backing_dev_info = NULL; current->backing_dev_info = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment