]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ext4: correct the error path of ext4_write_inline_data_end()
authorZhang Yi <yi.zhang@huawei.com>
Fri, 16 Jul 2021 12:20:22 +0000 (20:20 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 17 Oct 2021 08:42:33 +0000 (10:42 +0200)
[ Upstream commit 55ce2f649b9e88111270333a8127e23f4f8f42d7 ]

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>
fs/ext4/inline.c
fs/ext4/inode.c

index 46151bda6236803d897ce14696bb06bd5c1a5d94..cdb10e9fded6548e4a078e27e3fa48005eeaee10 100644 (file)
@@ -733,18 +733,13 @@ 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);
@@ -757,7 +752,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,
        (void) ext4_find_inline_data_nolock(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. */
@@ -766,7 +761,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;
 }
 
index 48b467353f6f11f9f277f5e78cb5414ae07291b8..dcbd8ac8d47113860f77e97f1b897e8458b18e5e 100644 (file)
@@ -1439,6 +1439,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);
@@ -1465,13 +1466,14 @@ static int ext4_write_end(struct file *file,
        if (i_size_changed || inline_data)
                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;
@@ -1554,6 +1556,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);
@@ -1583,6 +1586,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
@@ -1590,7 +1594,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;