mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 09:01:36 -04:00
bcachefs: Fix short buffered writes
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> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
committed by
Kent Overstreet
parent
0ba95acc44
commit
912bdf17a8
@@ -1454,23 +1454,23 @@ static int __bch2_buffered_write(struct bch_inode_info *inode,
|
||||
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);
|
||||
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);
|
||||
@@ -1567,6 +1567,7 @@ static ssize_t bch2_buffered_write(struct kiocb *iocb, struct iov_iter *iter)
|
||||
}
|
||||
pos += ret;
|
||||
written += ret;
|
||||
ret = 0;
|
||||
|
||||
balance_dirty_pages_ratelimited(mapping);
|
||||
} while (iov_iter_count(iter));
|
||||
|
||||
Reference in New Issue
Block a user