diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2020-07-09 13:54:58 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2020-07-09 14:54:00 -0400 |
commit | 6081343382c1e04c454aae6c2bc1b8131bd67493 (patch) | |
tree | 6432a91c31fcbde8ad7365bb27b806a51faa5667 /fs | |
parent | 65c16cd06892a925c60f198f07b2c2b95b3e7bef (diff) |
bcachefs: Fix short buffered writesbcachefs-buffered-write-fix
In the buffered write path, we have to check for short writes that write
to the full page, where the page wasn't UpToDate; when this happens, the
page is partly garbage, so we have to zero it out and revert that part
of the write.
This check was wrong - we reverted total from copied, but didn't revert
the iov_iter, probably also leading to corrupted writes.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/fs-io.c | 20 |
1 files changed, 10 insertions, 10 deletions
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c index ec78e7b52375..e9896be0e765 100644 --- a/fs/bcachefs/fs-io.c +++ b/fs/bcachefs/fs-io.c @@ -1516,24 +1516,24 @@ retry_reservation: if (!pg_copied) break; + if (!PageUptodate(page) && + pg_copied != PAGE_SIZE && + pos + copied + pg_copied < inode->v.i_size) { + zero_user(page, 0, PAGE_SIZE); + break; + } + flush_dcache_page(page); iov_iter_advance(iter, pg_copied); copied += pg_copied; + + if (pg_copied != pg_len) + break; } if (!copied) goto out; - if (copied < len && - ((offset + copied) & (PAGE_SIZE - 1))) { - struct page *page = pages[(offset + copied) >> PAGE_SHIFT]; - - if (!PageUptodate(page)) { - zero_user(page, 0, PAGE_SIZE); - copied -= (offset + copied) & (PAGE_SIZE - 1); - } - } - spin_lock(&inode->v.i_lock); if (pos + copied > inode->v.i_size) i_size_write(&inode->v, pos + copied); |