ext4: move inode extension/truncate code out from ->iomap_end() callback
In preparation for implementing the iomap direct I/O modifications, the inode extension/truncate code needs to be moved out from the ext4_iomap_end() callback. For direct I/O, if the current code remained, it would behave incorrrectly. Updating the inode size prior to converting unwritten extents would potentially allow a racing direct I/O read to find unwritten extents before being converted correctly. The inode extension/truncate code now resides within a new helper ext4_handle_inode_extension(). This function has been designed so that it can accommodate for both DAX and direct I/O extension/truncate operations. Signed-off-by: Matthew Bobrowski <mbobrowski@mbobrowski.org> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Ritesh Harjani <riteshh@linux.ibm.com> Link: https://lore.kernel.org/r/d41ffa26e20b15b12895812c3cad7c91a6a59bc6.1572949325.git.mbobrowski@mbobrowski.org Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:

committed by
Theodore Ts'o

parent
b1b4705d54
commit
569342dc24
@@ -3583,53 +3583,7 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
||||
static int ext4_iomap_end(struct inode *inode, loff_t offset, loff_t length,
|
||||
ssize_t written, unsigned flags, struct iomap *iomap)
|
||||
{
|
||||
int ret = 0;
|
||||
handle_t *handle;
|
||||
int blkbits = inode->i_blkbits;
|
||||
bool truncate = false;
|
||||
|
||||
if (!(flags & IOMAP_WRITE) || (flags & IOMAP_FAULT))
|
||||
return 0;
|
||||
|
||||
handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
|
||||
if (IS_ERR(handle)) {
|
||||
ret = PTR_ERR(handle);
|
||||
goto orphan_del;
|
||||
}
|
||||
if (ext4_update_inode_size(inode, offset + written))
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
/*
|
||||
* We may need to truncate allocated but not written blocks beyond EOF.
|
||||
*/
|
||||
if (iomap->offset + iomap->length >
|
||||
ALIGN(inode->i_size, 1 << blkbits)) {
|
||||
ext4_lblk_t written_blk, end_blk;
|
||||
|
||||
written_blk = (offset + written) >> blkbits;
|
||||
end_blk = (offset + length) >> blkbits;
|
||||
if (written_blk < end_blk && ext4_can_truncate(inode))
|
||||
truncate = true;
|
||||
}
|
||||
/*
|
||||
* Remove inode from orphan list if we were extending a inode and
|
||||
* everything went fine.
|
||||
*/
|
||||
if (!truncate && inode->i_nlink &&
|
||||
!list_empty(&EXT4_I(inode)->i_orphan))
|
||||
ext4_orphan_del(handle, inode);
|
||||
ext4_journal_stop(handle);
|
||||
if (truncate) {
|
||||
ext4_truncate_failed_write(inode);
|
||||
orphan_del:
|
||||
/*
|
||||
* If truncate failed early the inode might still be on the
|
||||
* orphan list; we need to make sure the inode is removed from
|
||||
* the orphan list in that case.
|
||||
*/
|
||||
if (inode->i_nlink)
|
||||
ext4_orphan_del(NULL, inode);
|
||||
}
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct iomap_ops ext4_iomap_ops = {
|
||||
|
Reference in New Issue
Block a user