Skip to content

Commit 14cbfee

Browse files
zhangyi089gregkh
authored andcommitted
ext4: correct the error path of ext4_write_inline_data_end()
[ Upstream commit 55ce2f6 ] 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 Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent d7a15e1 commit 14cbfee

2 files changed

Lines changed: 10 additions & 12 deletions

File tree

fs/ext4/inline.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -733,18 +733,13 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
733733
void *kaddr;
734734
struct ext4_iloc iloc;
735735

736-
if (unlikely(copied < len)) {
737-
if (!PageUptodate(page)) {
738-
copied = 0;
739-
goto out;
740-
}
741-
}
736+
if (unlikely(copied < len) && !PageUptodate(page))
737+
return 0;
742738

743739
ret = ext4_get_inode_loc(inode, &iloc);
744740
if (ret) {
745741
ext4_std_error(inode->i_sb, ret);
746-
copied = 0;
747-
goto out;
742+
return ret;
748743
}
749744

750745
ext4_write_lock_xattr(inode, &no_expand);
@@ -757,7 +752,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
757752
(void) ext4_find_inline_data_nolock(inode);
758753

759754
kaddr = kmap_atomic(page);
760-
ext4_write_inline_data(inode, &iloc, kaddr, pos, len);
755+
ext4_write_inline_data(inode, &iloc, kaddr, pos, copied);
761756
kunmap_atomic(kaddr);
762757
SetPageUptodate(page);
763758
/* clear page dirty so that writepages wouldn't work for us. */
@@ -766,7 +761,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
766761
ext4_write_unlock_xattr(inode, &no_expand);
767762
brelse(iloc.bh);
768763
mark_inode_dirty(inode);
769-
out:
764+
770765
return copied;
771766
}
772767

fs/ext4/inode.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,7 @@ static int ext4_write_end(struct file *file,
12961296
goto errout;
12971297
}
12981298
copied = ret;
1299+
ret = 0;
12991300
} else
13001301
copied = block_write_end(file, mapping, pos,
13011302
len, copied, page, fsdata);
@@ -1322,13 +1323,14 @@ static int ext4_write_end(struct file *file,
13221323
if (i_size_changed || inline_data)
13231324
ret = ext4_mark_inode_dirty(handle, inode);
13241325

1326+
errout:
13251327
if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))
13261328
/* if we have allocated more blocks and copied
13271329
* less. We will have blocks allocated outside
13281330
* inode->i_size. So truncate them
13291331
*/
13301332
ext4_orphan_add(handle, inode);
1331-
errout:
1333+
13321334
ret2 = ext4_journal_stop(handle);
13331335
if (!ret)
13341336
ret = ret2;
@@ -1411,6 +1413,7 @@ static int ext4_journalled_write_end(struct file *file,
14111413
goto errout;
14121414
}
14131415
copied = ret;
1416+
ret = 0;
14141417
} else if (unlikely(copied < len) && !PageUptodate(page)) {
14151418
copied = 0;
14161419
ext4_journalled_zero_new_buffers(handle, page, from, to);
@@ -1440,14 +1443,14 @@ static int ext4_journalled_write_end(struct file *file,
14401443
ret = ret2;
14411444
}
14421445

1446+
errout:
14431447
if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))
14441448
/* if we have allocated more blocks and copied
14451449
* less. We will have blocks allocated outside
14461450
* inode->i_size. So truncate them
14471451
*/
14481452
ext4_orphan_add(handle, inode);
14491453

1450-
errout:
14511454
ret2 = ext4_journal_stop(handle);
14521455
if (!ret)
14531456
ret = ret2;

0 commit comments

Comments
 (0)