static ssize_t ext4_write_checks(struct kiocb *iocb, struct iov_iter *from)
{
+ struct inode *inode = file_inode(iocb->ki_filp);
+ loff_t old_size = i_size_read(inode);
ssize_t ret, count;
count = ext4_generic_write_checks(iocb, from);
ret = file_modified(iocb->ki_filp);
if (ret)
return ret;
+
+ /*
+ * If the position is beyond the EOF, it is necessary to zero out the
+ * partial block that beyond the existing EOF, as it may contains
+ * stale data written through mmap.
+ */
+ if (iocb->ki_pos > old_size && !ext4_verity_in_progress(inode)) {
+ if (iocb->ki_flags & IOCB_NOWAIT)
+ return -EAGAIN;
+
+ ret = ext4_block_zero_eof(inode, old_size, iocb->ki_pos);
+ if (ret)
+ return ret;
+ }
+
return count;
}
folio_unlock(folio);
folio_put(folio);
- if (old_size < pos && !verity) {
+ if (old_size < pos && !verity)
pagecache_isize_extended(inode, old_size, pos);
- ext4_block_zero_eof(inode, old_size, pos);
- }
+
/*
* Don't mark the inode dirty under folio lock. First, it unnecessarily
* makes the holding time of folio lock longer. Second, it forces lock
folio_unlock(folio);
folio_put(folio);
- if (old_size < pos && !verity) {
+ if (old_size < pos && !verity)
pagecache_isize_extended(inode, old_size, pos);
- ext4_block_zero_eof(inode, old_size, pos);
- }
if (size_changed) {
ret2 = ext4_mark_inode_dirty(handle, inode);
struct inode *inode = mapping->host;
loff_t old_size = inode->i_size;
bool disksize_changed = false;
- loff_t new_i_size, zero_len = 0;
+ loff_t new_i_size;
handle_t *handle;
if (unlikely(!folio_buffers(folio))) {
folio_unlock(folio);
folio_put(folio);
- if (pos > old_size) {
+ if (pos > old_size)
pagecache_isize_extended(inode, old_size, pos);
- zero_len = pos - old_size;
- }
- if (!disksize_changed && !zero_len)
+ if (!disksize_changed)
return copied;
- handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
+ handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
if (IS_ERR(handle))
return PTR_ERR(handle);
- if (zero_len)
- ext4_block_zero_eof(inode, old_size, pos);
ext4_mark_inode_dirty(handle, inode);
ext4_journal_stop(handle);