[Devel] [PATCH rh8 1/2] ms/ext4: handle ext4_mark_inode_dirty errors
Konstantin Khorenko
khorenko at virtuozzo.com
Wed Mar 3 19:41:02 MSK 2021
Both these patches will be applied in 4.18.0-240.1.1.vz8.5.6 kernel.
--
Best regards,
Konstantin Khorenko,
Virtuozzo Linux Kernel Team
On 02/03/2021 07:25 PM, Konstantin Khorenko wrote:
> From: Harshad Shirwadkar <harshadshirwadkar at gmail.com>
>
> ext4_mark_inode_dirty() can fail for real reasons. Ignoring its return
> value may lead ext4 to ignore real failures that would result in
> corruption / crashes. Harden ext4_mark_inode_dirty error paths to fail
> as soon as possible and return errors to the caller whenever
> appropriate.
>
> One of the possible scnearios when this bug could affected is that
> while creating a new inode, its directory entry gets added
> successfully but while writing the inode itself mark_inode_dirty
> returns error which is ignored. This would result in inconsistency
> that the directory entry points to a non-existent inode.
>
> Ran gce-xfstests smoke tests and verified that there were no
> regressions.
>
> Signed-off-by: Harshad Shirwadkar <harshadshirwadkar at gmail.com>
> Link: https://lore.kernel.org/r/20200427013438.219117-1-harshadshirwadkar@gmail.com
> Signed-off-by: Theodore Ts'o <tytso at mit.edu>
>
> (cherry picked from commit 4209ae12b12265d475bba28634184423149bd14f)
> Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
>
> Backport note: dropped hunk in ext4_handle_inode_extension() as vz8
> kernel does not have this function yet.
> ---
> fs/ext4/acl.c | 2 +-
> fs/ext4/ext4.h | 3 +-
> fs/ext4/ext4_jbd2.h | 5 ++-
> fs/ext4/extents.c | 34 ++++++++++++--------
> fs/ext4/indirect.c | 4 ++-
> fs/ext4/inline.c | 6 ++--
> fs/ext4/inode.c | 38 +++++++++++++++-------
> fs/ext4/migrate.c | 12 ++++---
> fs/ext4/namei.c | 78 +++++++++++++++++++++++++++++----------------
> fs/ext4/super.c | 16 ++++++----
> fs/ext4/xattr.c | 6 ++--
> 11 files changed, 131 insertions(+), 73 deletions(-)
>
> diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
> index b3eba92f38f5..76f634d185f1 100644
> --- a/fs/ext4/acl.c
> +++ b/fs/ext4/acl.c
> @@ -255,7 +255,7 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
> if (!error && update_mode) {
> inode->i_mode = mode;
> inode->i_ctime = current_time(inode);
> - ext4_mark_inode_dirty(handle, inode);
> + error = ext4_mark_inode_dirty(handle, inode);
> }
> out_stop:
> ext4_journal_stop(handle);
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 0249169b9c14..053b512397f2 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -3223,8 +3223,7 @@ enum ext4_event_type {
> */
> #define EXT_MAX_BLOCKS 0xffffffff
>
> -extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
> -extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
> +extern void ext4_ext_tree_init(handle_t *handle, struct inode *inode);
> extern int ext4_ext_index_trans_blocks(struct inode *inode, int extents);
> extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
> struct ext4_map_blocks *map, int flags);
> diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
> index a6b9b66dbfad..eb81e139ce56 100644
> --- a/fs/ext4/ext4_jbd2.h
> +++ b/fs/ext4/ext4_jbd2.h
> @@ -222,7 +222,10 @@ ext4_mark_iloc_dirty(handle_t *handle,
> int ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
> struct ext4_iloc *iloc);
>
> -int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
> +#define ext4_mark_inode_dirty(__h, __i) \
> + __ext4_mark_inode_dirty((__h), (__i), __func__, __LINE__)
> +int __ext4_mark_inode_dirty(handle_t *handle, struct inode *inode,
> + const char *func, unsigned int line);
>
> int ext4_expand_extra_isize(struct inode *inode,
> unsigned int new_extra_isize,
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 6cabc158a59a..afa98403d602 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -871,7 +871,7 @@ ext4_ext_binsearch(struct inode *inode,
>
> }
>
> -int ext4_ext_tree_init(handle_t *handle, struct inode *inode)
> +void ext4_ext_tree_init(handle_t *handle, struct inode *inode)
> {
> struct ext4_extent_header *eh;
>
> @@ -881,7 +881,6 @@ int ext4_ext_tree_init(handle_t *handle, struct inode *inode)
> eh->eh_magic = EXT4_EXT_MAGIC;
> eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
> ext4_mark_inode_dirty(handle, inode);
> - return 0;
> }
>
> struct ext4_ext_path *
> @@ -1382,7 +1381,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
> ext4_idx_pblock(EXT_FIRST_INDEX(neh)));
>
> le16_add_cpu(&neh->eh_depth, 1);
> - ext4_mark_inode_dirty(handle, inode);
> + err = ext4_mark_inode_dirty(handle, inode);
> out:
> brelse(bh);
>
> @@ -4644,7 +4643,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
> struct inode *inode = file_inode(file);
> handle_t *handle;
> int ret = 0;
> - int ret2 = 0;
> + int ret2 = 0, ret3 = 0;
> int retries = 0;
> int depth = 0;
> struct ext4_map_blocks map;
> @@ -4708,10 +4707,11 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
> ext4_set_inode_flag(inode,
> EXT4_INODE_EOFBLOCKS);
> }
> - ext4_mark_inode_dirty(handle, inode);
> + ret2 = ext4_mark_inode_dirty(handle, inode);
> ext4_update_inode_fsync_trans(handle, inode, 1);
> - ret2 = ext4_journal_stop(handle);
> - if (ret2)
> + ret3 = ext4_journal_stop(handle);
> + ret2 = ret3 ? ret3 : ret2;
> + if (unlikely(ret2))
> break;
> }
> if (ret == -ENOSPC &&
> @@ -4869,7 +4869,9 @@ static long ext4_zero_range(struct file *file, loff_t offset,
> if ((offset + len) > i_size_read(inode))
> ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
> }
> - ext4_mark_inode_dirty(handle, inode);
> + ret = ext4_mark_inode_dirty(handle, inode);
> + if (unlikely(ret))
> + goto out_handle;
>
> /* Zero out partial block at the edges of the range */
> ret = ext4_zero_partial_blocks(handle, inode, offset, len);
> @@ -4879,6 +4881,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
> if (file->f_flags & O_SYNC)
> ext4_handle_sync(handle);
>
> +out_handle:
> ext4_journal_stop(handle);
> out_mutex:
> inode_unlock(inode);
> @@ -4997,8 +5000,7 @@ int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode,
> loff_t offset, ssize_t len)
> {
> unsigned int max_blocks;
> - int ret = 0;
> - int ret2 = 0;
> + int ret = 0, ret2 = 0, ret3 = 0;
> struct ext4_map_blocks map;
> unsigned int credits, blkbits = inode->i_blkbits;
>
> @@ -5041,9 +5043,13 @@ int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode,
> "ext4_ext_map_blocks returned %d",
> inode->i_ino, map.m_lblk,
> map.m_len, ret);
> - ext4_mark_inode_dirty(handle, inode);
> - if (credits)
> - ret2 = ext4_journal_stop(handle);
> + ret2 = ext4_mark_inode_dirty(handle, inode);
> + if (credits) {
> + ret3 = ext4_journal_stop(handle);
> + if (unlikely(ret3))
> + ret2 = ret3;
> + }
> +
> if (ret <= 0 || ret2)
> break;
> }
> @@ -5567,7 +5573,7 @@ int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
> if (IS_SYNC(inode))
> ext4_handle_sync(handle);
> inode->i_mtime = inode->i_ctime = current_time(inode);
> - ext4_mark_inode_dirty(handle, inode);
> + ret = ext4_mark_inode_dirty(handle, inode);
> ext4_update_inode_fsync_trans(handle, inode, 1);
>
> out_stop:
> diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
> index 3d4227c34df0..e6978c663f20 100644
> --- a/fs/ext4/indirect.c
> +++ b/fs/ext4/indirect.c
> @@ -473,7 +473,9 @@ static int ext4_splice_branch(handle_t *handle,
> /*
> * OK, we spliced it into the inode itself on a direct block.
> */
> - ext4_mark_inode_dirty(handle, ar->inode);
> + err = ext4_mark_inode_dirty(handle, ar->inode);
> + if (unlikely(err))
> + goto err_out;
> jbd_debug(5, "splicing direct\n");
> }
> return err;
> diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
> index 7eb295ae38f9..0b08b06c6484 100644
> --- a/fs/ext4/inline.c
> +++ b/fs/ext4/inline.c
> @@ -1263,7 +1263,7 @@ static int ext4_convert_inline_data_nolock(handle_t *handle,
> int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
> struct inode *dir, struct inode *inode)
> {
> - int ret, inline_size, no_expand;
> + int ret, ret2, inline_size, no_expand;
> void *inline_start;
> struct ext4_iloc iloc;
>
> @@ -1317,7 +1317,9 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
>
> out:
> ext4_write_unlock_xattr(dir, &no_expand);
> - ext4_mark_inode_dirty(handle, dir);
> + ret2 = ext4_mark_inode_dirty(handle, dir);
> + if (unlikely(ret2 && !ret))
> + ret = ret2;
> brelse(iloc.bh);
> return ret;
> }
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 8e7de233296c..95db85e44ce6 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -1420,7 +1420,7 @@ static int ext4_write_end(struct file *file,
> * filesystems.
> */
> if (i_size_changed || inline_data)
> - ext4_mark_inode_dirty(handle, inode);
> + ret = ext4_mark_inode_dirty(handle, inode);
>
> if (pos + len > inode->i_size && ext4_can_truncate(inode))
> /* if we have allocated more blocks and copied
> @@ -3188,7 +3188,7 @@ static int ext4_da_write_end(struct file *file,
> * new_i_size is less that inode->i_size
> * bu greater than i_disksize.(hint delalloc)
> */
> - ext4_mark_inode_dirty(handle, inode);
> + ret = ext4_mark_inode_dirty(handle, inode);
> }
> }
>
> @@ -3205,7 +3205,7 @@ static int ext4_da_write_end(struct file *file,
> if (ret2 < 0)
> ret = ret2;
> ret2 = ext4_journal_stop(handle);
> - if (!ret)
> + if (unlikely(ret2 && !ret))
> ret = ret2;
>
> return ret ? ret : copied;
> @@ -4213,6 +4213,8 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
> loff_t len)
> {
> handle_t *handle;
> + int ret;
> +
> loff_t size = i_size_read(inode);
>
> WARN_ON(!inode_is_locked(inode));
> @@ -4226,10 +4228,10 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
> if (IS_ERR(handle))
> return PTR_ERR(handle);
> ext4_update_i_disksize(inode, size);
> - ext4_mark_inode_dirty(handle, inode);
> + ret = ext4_mark_inode_dirty(handle, inode);
> ext4_journal_stop(handle);
>
> - return 0;
> + return ret;
> }
>
> static void ext4_wait_dax_page(struct ext4_inode_info *ei)
> @@ -4281,7 +4283,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
> loff_t first_block_offset, last_block_offset;
> handle_t *handle;
> unsigned int credits;
> - int ret = 0;
> + int ret = 0, ret2 = 0;
>
> if (!S_ISREG(inode->i_mode))
> return -EOPNOTSUPP;
> @@ -4407,7 +4409,9 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
> ext4_handle_sync(handle);
>
> inode->i_mtime = inode->i_ctime = current_time(inode);
> - ext4_mark_inode_dirty(handle, inode);
> + ret2 = ext4_mark_inode_dirty(handle, inode);
> + if (unlikely(ret2))
> + ret = ret2;
> if (ret >= 0)
> ext4_update_inode_fsync_trans(handle, inode, 1);
> out_stop:
> @@ -4476,7 +4480,7 @@ int ext4_truncate(struct inode *inode)
> {
> struct ext4_inode_info *ei = EXT4_I(inode);
> unsigned int credits;
> - int err = 0;
> + int err = 0, err2;
> handle_t *handle;
> struct address_space *mapping = inode->i_mapping;
>
> @@ -4566,7 +4570,9 @@ int ext4_truncate(struct inode *inode)
> ext4_orphan_del(handle, inode);
>
> inode->i_mtime = inode->i_ctime = current_time(inode);
> - ext4_mark_inode_dirty(handle, inode);
> + err2 = ext4_mark_inode_dirty(handle, inode);
> + if (unlikely(err2 && !err))
> + err = err2;
> ext4_journal_stop(handle);
>
> trace_ext4_truncate_exit(inode);
> @@ -5604,6 +5610,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
> inode->i_gid = attr->ia_gid;
> error = ext4_mark_inode_dirty(handle, inode);
> ext4_journal_stop(handle);
> + if (unlikely(error))
> + return error;
> }
>
> if (attr->ia_valid & ATTR_SIZE) {
> @@ -6082,7 +6090,8 @@ int ext4_expand_extra_isize(struct inode *inode,
> * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync)
> * we start and wait on commits.
> */
> -int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
> +int __ext4_mark_inode_dirty(handle_t *handle, struct inode *inode,
> + const char *func, unsigned int line)
> {
> struct ext4_iloc iloc;
> struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
> @@ -6092,13 +6101,18 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
> trace_ext4_mark_inode_dirty(inode, _RET_IP_);
> err = ext4_reserve_inode_write(handle, inode, &iloc);
> if (err)
> - return err;
> + goto out;
>
> if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize)
> ext4_try_to_expand_extra_isize(inode, sbi->s_want_extra_isize,
> iloc, handle);
>
> - return ext4_mark_iloc_dirty(handle, inode, &iloc);
> + err = ext4_mark_iloc_dirty(handle, inode, &iloc);
> +out:
> + if (unlikely(err))
> + ext4_error_inode_err(inode, func, line, 0, err,
> + "mark_inode_dirty error");
> + return err;
> }
>
> /*
> diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
> index fb6520f37135..c5e3fc998211 100644
> --- a/fs/ext4/migrate.c
> +++ b/fs/ext4/migrate.c
> @@ -287,7 +287,7 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
> static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
> struct inode *tmp_inode)
> {
> - int retval;
> + int retval, retval2 = 0;
> __le32 i_data[3];
> struct ext4_inode_info *ei = EXT4_I(inode);
> struct ext4_inode_info *tmp_ei = EXT4_I(tmp_inode);
> @@ -342,7 +342,9 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
> * i_blocks when freeing the indirect meta-data blocks
> */
> retval = free_ind_block(handle, inode, i_data);
> - ext4_mark_inode_dirty(handle, inode);
> + retval2 = ext4_mark_inode_dirty(handle, inode);
> + if (unlikely(retval2 && !retval))
> + retval = retval2;
>
> err_out:
> return retval;
> @@ -601,7 +603,7 @@ int ext4_ind_migrate(struct inode *inode)
> ext4_lblk_t start, end;
> ext4_fsblk_t blk;
> handle_t *handle;
> - int ret;
> + int ret, ret2 = 0;
>
> if (!ext4_has_feature_extents(inode->i_sb) ||
> (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
> @@ -655,7 +657,9 @@ int ext4_ind_migrate(struct inode *inode)
> memset(ei->i_data, 0, sizeof(ei->i_data));
> for (i = start; i <= end; i++)
> ei->i_data[i] = cpu_to_le32(blk++);
> - ext4_mark_inode_dirty(handle, inode);
> + ret2 = ext4_mark_inode_dirty(handle, inode);
> + if (unlikely(ret2 && !ret))
> + ret = ret2;
> errout:
> ext4_journal_stop(handle);
> up_write(&EXT4_I(inode)->i_data_sem);
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index 56dd9d4ab223..1a38715145e0 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -1861,7 +1861,7 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
> {
> unsigned int blocksize = dir->i_sb->s_blocksize;
> int csum_size = 0;
> - int err;
> + int err, err2;
>
> if (ext4_has_metadata_csum(inode->i_sb))
> csum_size = sizeof(struct ext4_dir_entry_tail);
> @@ -1896,12 +1896,12 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
> dir->i_mtime = dir->i_ctime = current_time(dir);
> ext4_update_dx_flag(dir);
> inode_inc_iversion(dir);
> - ext4_mark_inode_dirty(handle, dir);
> + err2 = ext4_mark_inode_dirty(handle, dir);
> BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
> err = ext4_handle_dirty_dirent_node(handle, dir, bh);
> if (err)
> ext4_std_error(dir->i_sb, err);
> - return 0;
> + return err ? err : err2;
> }
>
> /*
> @@ -2086,7 +2086,9 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
> }
> ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
> dx_fallback++;
> - ext4_mark_inode_dirty(handle, dir);
> + retval = ext4_mark_inode_dirty(handle, dir);
> + if (unlikely(retval))
> + goto out;
> }
> blocks = dir->i_size >> sb->s_blocksize_bits;
> for (block = 0; block < blocks; block++) {
> @@ -2435,12 +2437,12 @@ static int ext4_add_nondir(handle_t *handle,
> struct inode *inode = *inodep;
> int err = ext4_add_entry(handle, dentry, inode);
> if (!err) {
> - ext4_mark_inode_dirty(handle, inode);
> + err = ext4_mark_inode_dirty(handle, inode);
> if (IS_DIRSYNC(dir))
> ext4_handle_sync(handle);
> d_instantiate_new(dentry, inode);
> *inodep = NULL;
> - return 0;
> + return err;
> }
> drop_nlink(inode);
> ext4_orphan_add(handle, inode);
> @@ -2637,7 +2639,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
> {
> handle_t *handle;
> struct inode *inode;
> - int err, credits, retries = 0;
> + int err, err2 = 0, credits, retries = 0;
>
> if (EXT4_DIR_LINK_MAX(dir))
> return -EMLINK;
> @@ -2670,7 +2672,9 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
> clear_nlink(inode);
> ext4_orphan_add(handle, inode);
> unlock_new_inode(inode);
> - ext4_mark_inode_dirty(handle, inode);
> + err2 = ext4_mark_inode_dirty(handle, inode);
> + if (unlikely(err2))
> + err = err2;
> ext4_journal_stop(handle);
> iput(inode);
> goto out_retry;
> @@ -2999,10 +3003,12 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
> inode->i_size = 0;
> ext4_orphan_add(handle, inode);
> inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
> - ext4_mark_inode_dirty(handle, inode);
> + retval = ext4_mark_inode_dirty(handle, inode);
> + if (retval)
> + goto end_rmdir;
> ext4_dec_count(handle, dir);
> ext4_update_dx_flag(dir);
> - ext4_mark_inode_dirty(handle, dir);
> + retval = ext4_mark_inode_dirty(handle, dir);
>
> end_rmdir:
> brelse(bh);
> @@ -3061,7 +3067,9 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
> goto end_unlink;
> dir->i_ctime = dir->i_mtime = current_time(dir);
> ext4_update_dx_flag(dir);
> - ext4_mark_inode_dirty(handle, dir);
> + retval = ext4_mark_inode_dirty(handle, dir);
> + if (retval)
> + goto end_unlink;
> if (inode->i_nlink == 0)
> ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
> dentry->d_name.len, dentry->d_name.name);
> @@ -3070,7 +3078,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
> if (!inode->i_nlink)
> ext4_orphan_add(handle, inode);
> inode->i_ctime = current_time(inode);
> - ext4_mark_inode_dirty(handle, inode);
> + retval = ext4_mark_inode_dirty(handle, inode);
>
> end_unlink:
> brelse(bh);
> @@ -3248,7 +3256,7 @@ static int ext4_link(struct dentry *old_dentry,
>
> err = ext4_add_entry(handle, dentry, inode);
> if (!err) {
> - ext4_mark_inode_dirty(handle, inode);
> + err = ext4_mark_inode_dirty(handle, inode);
> /* this can happen only for tmpfile being
> * linked the first time
> */
> @@ -3358,7 +3366,7 @@ static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent,
> static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
> unsigned ino, unsigned file_type)
> {
> - int retval;
> + int retval, retval2;
>
> BUFFER_TRACE(ent->bh, "get write access");
> retval = ext4_journal_get_write_access(handle, ent->bh);
> @@ -3370,20 +3378,20 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
> inode_inc_iversion(ent->dir);
> ent->dir->i_ctime = ent->dir->i_mtime =
> current_time(ent->dir);
> - ext4_mark_inode_dirty(handle, ent->dir);
> + retval = ext4_mark_inode_dirty(handle, ent->dir);
> BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata");
> if (!ent->inlined) {
> - retval = ext4_handle_dirty_dirent_node(handle,
> - ent->dir, ent->bh);
> - if (unlikely(retval)) {
> - ext4_std_error(ent->dir->i_sb, retval);
> - return retval;
> + retval2 = ext4_handle_dirty_dirent_node(handle,
> + ent->dir, ent->bh);
> + if (unlikely(retval2)) {
> + ext4_std_error(ent->dir->i_sb, retval2);
> + return retval2;
> }
> }
> brelse(ent->bh);
> ent->bh = NULL;
>
> - return 0;
> + return retval;
> }
>
> static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
> @@ -3618,7 +3626,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
> EXT4_FT_CHRDEV);
> if (retval)
> goto end_rename;
> - ext4_mark_inode_dirty(handle, whiteout);
> + retval = ext4_mark_inode_dirty(handle, whiteout);
> + if (unlikely(retval))
> + goto end_rename;
> }
> if (!new.bh) {
> retval = ext4_add_entry(handle, new.dentry, old.inode);
> @@ -3639,7 +3649,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
> * rename.
> */
> old.inode->i_ctime = current_time(old.inode);
> - ext4_mark_inode_dirty(handle, old.inode);
> + retval = ext4_mark_inode_dirty(handle, old.inode);
> + if (unlikely(retval))
> + goto end_rename;
>
> if (!whiteout) {
> /*
> @@ -3668,12 +3680,18 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
> } else {
> ext4_inc_count(handle, new.dir);
> ext4_update_dx_flag(new.dir);
> - ext4_mark_inode_dirty(handle, new.dir);
> + retval = ext4_mark_inode_dirty(handle, new.dir);
> + if (unlikely(retval))
> + goto end_rename;
> }
> }
> - ext4_mark_inode_dirty(handle, old.dir);
> + retval = ext4_mark_inode_dirty(handle, old.dir);
> + if (unlikely(retval))
> + goto end_rename;
> if (new.inode) {
> - ext4_mark_inode_dirty(handle, new.inode);
> + retval = ext4_mark_inode_dirty(handle, new.inode);
> + if (unlikely(retval))
> + goto end_rename;
> if (!new.inode->i_nlink)
> ext4_orphan_add(handle, new.inode);
> }
> @@ -3807,8 +3825,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
> ctime = current_time(old.inode);
> old.inode->i_ctime = ctime;
> new.inode->i_ctime = ctime;
> - ext4_mark_inode_dirty(handle, old.inode);
> - ext4_mark_inode_dirty(handle, new.inode);
> + retval = ext4_mark_inode_dirty(handle, old.inode);
> + if (unlikely(retval))
> + goto end_rename;
> + retval = ext4_mark_inode_dirty(handle, new.inode);
> + if (unlikely(retval))
> + goto end_rename;
>
> if (old.dir_bh) {
> retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 60c9fb110be3..1bb88cb510d5 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -5942,7 +5942,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
> EXT4_I(inode)->i_flags |= EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL;
> inode_set_flags(inode, S_NOATIME | S_IMMUTABLE,
> S_NOATIME | S_IMMUTABLE);
> - ext4_mark_inode_dirty(handle, inode);
> + err = ext4_mark_inode_dirty(handle, inode);
> ext4_journal_stop(handle);
> unlock_inode:
> inode_unlock(inode);
> @@ -6044,12 +6044,14 @@ static int ext4_quota_off(struct super_block *sb, int type)
> * this is not a hard failure and quotas are already disabled.
> */
> handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1);
> - if (IS_ERR(handle))
> + if (IS_ERR(handle)) {
> + err = PTR_ERR(handle);
> goto out_unlock;
> + }
> EXT4_I(inode)->i_flags &= ~(EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL);
> inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE);
> inode->i_mtime = inode->i_ctime = current_time(inode);
> - ext4_mark_inode_dirty(handle, inode);
> + err = ext4_mark_inode_dirty(handle, inode);
> ext4_journal_stop(handle);
> out_unlock:
> inode_unlock(inode);
> @@ -6107,7 +6109,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
> {
> struct inode *inode = sb_dqopt(sb)->files[type];
> ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
> - int err, offset = off & (sb->s_blocksize - 1);
> + int err = 0, err2 = 0, offset = off & (sb->s_blocksize - 1);
> int retries = 0;
> struct buffer_head *bh;
> handle_t *handle = journal_current_handle();
> @@ -6155,9 +6157,11 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
> if (inode->i_size < off + len) {
> i_size_write(inode, off + len);
> EXT4_I(inode)->i_disksize = inode->i_size;
> - ext4_mark_inode_dirty(handle, inode);
> + err2 = ext4_mark_inode_dirty(handle, inode);
> + if (unlikely(err2 && !err))
> + err = err2;
> }
> - return len;
> + return err ? err : len;
> }
>
> static int ext4_get_next_id(struct super_block *sb, struct kqid *qid)
> diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
> index f2a98b642d5c..6d12ac4a814e 100644
> --- a/fs/ext4/xattr.c
> +++ b/fs/ext4/xattr.c
> @@ -1327,7 +1327,7 @@ static int ext4_xattr_inode_write(handle_t *handle, struct inode *ea_inode,
> int blocksize = ea_inode->i_sb->s_blocksize;
> int max_blocks = (bufsize + blocksize - 1) >> ea_inode->i_blkbits;
> int csize, wsize = 0;
> - int ret = 0;
> + int ret = 0, ret2 = 0;
> int retries = 0;
>
> retry:
> @@ -1385,7 +1385,9 @@ static int ext4_xattr_inode_write(handle_t *handle, struct inode *ea_inode,
> ext4_update_i_disksize(ea_inode, wsize);
> inode_unlock(ea_inode);
>
> - ext4_mark_inode_dirty(handle, ea_inode);
> + ret2 = ext4_mark_inode_dirty(handle, ea_inode);
> + if (unlikely(ret2 && !ret))
> + ret = ret2;
>
> out:
> brelse(bh);
>
More information about the Devel
mailing list