diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 61ccb3c5390a..1fb020167323 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -266,6 +266,8 @@ void ext4_evict_inode(struct inode *inode) if (ext4_should_order_data(inode)) ext4_begin_ordered_truncate(inode, 0); + if (ext4_inode_buffered_iomap(inode)) + ext4_iomap_clear_disksize_pending(inode); truncate_inode_pages_final(&inode->i_data); /* @@ -4350,8 +4352,17 @@ static void ext4_iomap_discard_folio(struct folio *folio, loff_t pos) { struct inode *inode = folio->mapping->host; loff_t length = folio_pos(folio) + folio_size(folio) - pos; + loff_t pstart, plen; ext4_iomap_punch_delalloc(inode, pos, length, NULL); + + /* + * Clear the disksize-grow-pending state if the zeroed EOF block + * fails to write back and is discarded. + */ + plen = ext4_iomap_get_disksize_pending_range(inode, &pstart); + if (plen && pos <= pstart && folio_next_pos(folio) >= pstart + plen) + ext4_iomap_clear_disksize_pending(inode); } static ssize_t ext4_iomap_writeback_range(struct iomap_writepage_ctx *wpc, @@ -6761,7 +6772,18 @@ static int ext4_truncate_down(struct inode *inode, loff_t oldsize, start_lblk = newsize > 0 ? (newsize - 1) >> inode->i_blkbits : 0; ext4_fc_track_range(handle, inode, start_lblk, EXT_MAX_BLOCKS - 1); - ext4_set_inode_size(inode, newsize); + down_write(&EXT4_I(inode)->i_data_sem); + /* + * Truncate the zeroed EOF block invalidates the pending disksize + * update, so clear the disksize-grow-pending state. + */ + if (ext4_test_inode_state(inode, EXT4_STATE_DISKSIZE_GROW_PENDING) && + (newsize <= EXT4_I(inode)->i_disksize)) + ext4_iomap_clear_disksize_pending(inode); + + i_size_write(inode, newsize); + __ext4_set_i_disksize(inode, newsize); + up_write(&EXT4_I(inode)->i_data_sem); ret = ext4_mark_inode_dirty(handle, inode); ext4_journal_stop(handle); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 23dbdcd598fa..56bde3e439a5 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1497,6 +1497,14 @@ static void ext4_destroy_inode(struct inode *inode) "Inode %llu (%p): i_reserved_data_blocks (%u) not cleared!", inode->i_ino, EXT4_I(inode), EXT4_I(inode)->i_reserved_data_blocks); + + if (!(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ERROR_FS) && + !ext4_emergency_state(inode->i_sb) && + WARN_ON_ONCE(ext4_test_inode_state(inode, + EXT4_STATE_DISKSIZE_GROW_PENDING))) + ext4_msg(inode->i_sb, KERN_ERR, + "Inode %llu (%p): EXT4_STATE_DISKSIZE_GROW_PENDING not cleared!", + inode->i_ino, EXT4_I(inode)); } static void ext4_shutdown(struct super_block *sb)