Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ext4: move pagecache_isize_extended() out of active handle

In ext4_alloc_file_blocks(), pagecache_isize_extended() is called under
an active handle and may also hold folio lock if the block size is
smaller than the folio size. This also breaks the "folio lock ->
transaction start" lock ordering for the upcoming iomap buffered I/O
path.

Therefore, move pagecache_isize_extended() outside of an active handle.
Additionally, it is unnecessary to update the file length during each
iteration of the allocation loop. Instead, update the file length only
to the position where the allocation is successful. Postpone updating
the inode size until after the allocation loop completes or is
interrupted due to an error.

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260327102939.1095257-13-yi.zhang@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>

authored by

Zhang Yi and committed by
Theodore Ts'o
1ad0f428 116c0bda

+39 -23
+39 -23
fs/ext4/extents.c
··· 4582 4582 ext4_lblk_t len_lblk; 4583 4583 struct ext4_map_blocks map; 4584 4584 unsigned int credits; 4585 - loff_t epos, old_size = i_size_read(inode); 4585 + loff_t epos = 0, old_size = i_size_read(inode); 4586 4586 unsigned int blkbits = inode->i_blkbits; 4587 4587 bool alloc_zero = false; 4588 4588 ··· 4647 4647 ext4_journal_stop(handle); 4648 4648 break; 4649 4649 } 4650 + ext4_update_inode_fsync_trans(handle, inode, 1); 4651 + ret = ext4_journal_stop(handle); 4652 + if (unlikely(ret)) 4653 + break; 4654 + 4650 4655 /* 4651 4656 * allow a full retry cycle for any remaining allocations 4652 4657 */ 4653 4658 retries = 0; 4654 - epos = EXT4_LBLK_TO_B(inode, map.m_lblk + ret); 4655 - if (new_size) { 4656 - if (epos > new_size) 4657 - epos = new_size; 4658 - ext4_update_inode_size(inode, epos); 4659 - if (epos > old_size) 4660 - pagecache_isize_extended(inode, old_size, epos); 4661 - } 4662 - ret2 = ext4_mark_inode_dirty(handle, inode); 4663 - ext4_update_inode_fsync_trans(handle, inode, 1); 4664 - ret3 = ext4_journal_stop(handle); 4665 - ret2 = ret3 ? ret3 : ret2; 4666 - if (unlikely(ret2)) 4667 - break; 4668 4659 4669 4660 if (alloc_zero && 4670 4661 (map.m_flags & (EXT4_MAP_MAPPED | EXT4_MAP_UNWRITTEN))) { 4671 - ret2 = ext4_issue_zeroout(inode, map.m_lblk, map.m_pblk, 4672 - map.m_len); 4673 - if (likely(!ret2)) 4674 - ret2 = ext4_convert_unwritten_extents(NULL, 4662 + ret = ext4_issue_zeroout(inode, map.m_lblk, map.m_pblk, 4663 + map.m_len); 4664 + if (likely(!ret)) 4665 + ret = ext4_convert_unwritten_extents(NULL, 4675 4666 inode, (loff_t)map.m_lblk << blkbits, 4676 4667 (loff_t)map.m_len << blkbits); 4677 - if (ret2) 4668 + if (ret) 4678 4669 break; 4679 4670 } 4680 4671 4681 - map.m_lblk += ret; 4682 - map.m_len = len_lblk = len_lblk - ret; 4672 + map.m_lblk += map.m_len; 4673 + map.m_len = len_lblk = len_lblk - map.m_len; 4674 + epos = EXT4_LBLK_TO_B(inode, map.m_lblk); 4683 4675 } 4676 + 4684 4677 if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 4685 4678 goto retry; 4686 4679 4687 - return ret > 0 ? ret2 : ret; 4680 + if (!epos || !new_size) 4681 + return ret; 4682 + 4683 + /* 4684 + * Allocate blocks, update the file size to match the size of the 4685 + * already successfully allocated blocks. 4686 + */ 4687 + if (epos > new_size) 4688 + epos = new_size; 4689 + 4690 + handle = ext4_journal_start(inode, EXT4_HT_MISC, 1); 4691 + if (IS_ERR(handle)) 4692 + return ret ? ret : PTR_ERR(handle); 4693 + 4694 + ext4_update_inode_size(inode, epos); 4695 + ret2 = ext4_mark_inode_dirty(handle, inode); 4696 + ext4_update_inode_fsync_trans(handle, inode, 1); 4697 + ret3 = ext4_journal_stop(handle); 4698 + ret2 = ret3 ? ret3 : ret2; 4699 + 4700 + if (epos > old_size) 4701 + pagecache_isize_extended(inode, old_size, epos); 4702 + 4703 + return ret ? ret : ret2; 4688 4704 } 4689 4705 4690 4706 static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len);