summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/file.c17
-rw-r--r--fs/ext4/inode.c21
2 files changed, 24 insertions, 14 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index f1dc5ce791a7..ec0d81bea07a 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -271,6 +271,8 @@ static ssize_t ext4_generic_write_checks(struct kiocb *iocb,
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);
@@ -280,6 +282,21 @@ static ssize_t ext4_write_checks(struct kiocb *iocb, struct iov_iter *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;
}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 9c1b95c439d5..7eb4daea3faa 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1466,10 +1466,9 @@ static int ext4_write_end(const struct kiocb *iocb,
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
@@ -1584,10 +1583,8 @@ static int ext4_journalled_write_end(const struct kiocb *iocb,
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);
@@ -3226,7 +3223,7 @@ static int ext4_da_do_write_end(struct address_space *mapping,
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))) {
@@ -3270,19 +3267,15 @@ static int ext4_da_do_write_end(struct address_space *mapping,
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);