Message ID | 20210706024210.746788-3-yi.zhang@huawei.com |
---|---|
State | Superseded |
Headers | show |
Series | ext4: improve delalloc buffer write performance | expand |
On Tue 06-07-21 10:42:08, Zhang Yi wrote: > 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> Looks good. Feel free to add: Reviewed-by: Jan Kara <jack@suse.cz> Honza > --- > fs/ext4/inline.c | 15 +++++---------- > fs/ext4/inode.c | 7 +++++-- > 2 files changed, 10 insertions(+), 12 deletions(-) > > diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c > index 70cb64db33f7..28b666f25ac2 100644 > --- a/fs/ext4/inline.c > +++ b/fs/ext4/inline.c > @@ -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; > } > > diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c > index 6f6a61f3ae5f..4efd50a844b9 100644 > --- a/fs/ext4/inode.c > +++ b/fs/ext4/inode.c > @@ -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; > -- > 2.31.1 >
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 70cb64db33f7..28b666f25ac2 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -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; } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 6f6a61f3ae5f..4efd50a844b9 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -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;
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> --- fs/ext4/inline.c | 15 +++++---------- fs/ext4/inode.c | 7 +++++-- 2 files changed, 10 insertions(+), 12 deletions(-)