ext4: correct the error path of ext4_write_inline_data_end()
Current error path of ext4_write_inline_data_end() is not correct. Firstly, it should pass out the error value if ext4_get_inode_loc() return fail, or else it could trigger infinite loop if we inject error here. And then it's better to add inode to orphan list if it return fail in ext4_journal_stop(), otherwise we could not restore inline xattr entry after power failure. Finally, we need to reset the 'ret' value if ext4_write_inline_data_end() return success in ext4_write_end() and ext4_journalled_write_end(), otherwise we could not get the error return value of ext4_journal_stop(). Signed-off-by: Zhang Yi <yi.zhang@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Link: https://lore.kernel.org/r/20210716122024.1105856-3-yi.zhang@huawei.com
This commit is contained in:
parent
4df031ff58
commit
55ce2f649b
|
@ -733,25 +733,20 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
|
|||
void *kaddr;
|
||||
struct ext4_iloc iloc;
|
||||
|
||||
if (unlikely(copied < len)) {
|
||||
if (!PageUptodate(page)) {
|
||||
copied = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (unlikely(copied < len) && !PageUptodate(page))
|
||||
return 0;
|
||||
|
||||
ret = ext4_get_inode_loc(inode, &iloc);
|
||||
if (ret) {
|
||||
ext4_std_error(inode->i_sb, ret);
|
||||
copied = 0;
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ext4_write_lock_xattr(inode, &no_expand);
|
||||
BUG_ON(!ext4_has_inline_data(inode));
|
||||
|
||||
kaddr = kmap_atomic(page);
|
||||
ext4_write_inline_data(inode, &iloc, kaddr, pos, len);
|
||||
ext4_write_inline_data(inode, &iloc, kaddr, pos, copied);
|
||||
kunmap_atomic(kaddr);
|
||||
SetPageUptodate(page);
|
||||
/* clear page dirty so that writepages wouldn't work for us. */
|
||||
|
@ -760,7 +755,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
|
|||
ext4_write_unlock_xattr(inode, &no_expand);
|
||||
brelse(iloc.bh);
|
||||
mark_inode_dirty(inode);
|
||||
out:
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
|
|
|
@ -1295,6 +1295,7 @@ static int ext4_write_end(struct file *file,
|
|||
goto errout;
|
||||
}
|
||||
copied = ret;
|
||||
ret = 0;
|
||||
} else
|
||||
copied = block_write_end(file, mapping, pos,
|
||||
len, copied, page, fsdata);
|
||||
|
@ -1321,13 +1322,14 @@ static int ext4_write_end(struct file *file,
|
|||
if (i_size_changed || inline_data)
|
||||
ret = ext4_mark_inode_dirty(handle, inode);
|
||||
|
||||
errout:
|
||||
if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))
|
||||
/* if we have allocated more blocks and copied
|
||||
* less. We will have blocks allocated outside
|
||||
* inode->i_size. So truncate them
|
||||
*/
|
||||
ext4_orphan_add(handle, inode);
|
||||
errout:
|
||||
|
||||
ret2 = ext4_journal_stop(handle);
|
||||
if (!ret)
|
||||
ret = ret2;
|
||||
|
@ -1410,6 +1412,7 @@ static int ext4_journalled_write_end(struct file *file,
|
|||
goto errout;
|
||||
}
|
||||
copied = ret;
|
||||
ret = 0;
|
||||
} else if (unlikely(copied < len) && !PageUptodate(page)) {
|
||||
copied = 0;
|
||||
ext4_journalled_zero_new_buffers(handle, page, from, to);
|
||||
|
@ -1439,6 +1442,7 @@ static int ext4_journalled_write_end(struct file *file,
|
|||
ret = ret2;
|
||||
}
|
||||
|
||||
errout:
|
||||
if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))
|
||||
/* if we have allocated more blocks and copied
|
||||
* less. We will have blocks allocated outside
|
||||
|
@ -1446,7 +1450,6 @@ static int ext4_journalled_write_end(struct file *file,
|
|||
*/
|
||||
ext4_orphan_add(handle, inode);
|
||||
|
||||
errout:
|
||||
ret2 = ext4_journal_stop(handle);
|
||||
if (!ret)
|
||||
ret = ret2;
|
||||
|
|
Loading…
Reference in New Issue