Skip to content

Commit

Permalink
ext4: correct the error path of ext4_write_inline_data_end()
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Zhang Yi authored and Theodore Ts'o committed Sep 5, 2021
1 parent 4df031f commit 55ce2f6
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 12 deletions.
15 changes: 5 additions & 10 deletions fs/ext4/inline.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -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;
}

Expand Down
7 changes: 5 additions & 2 deletions fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1439,14 +1442,14 @@ 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
* inode->i_size. So truncate them
*/
ext4_orphan_add(handle, inode);

errout:
ret2 = ext4_journal_stop(handle);
if (!ret)
ret = ret2;
Expand Down

0 comments on commit 55ce2f6

Please sign in to comment.