ext4: add error checking to calls to ext4_handle_dirty_metadata()
authorTheodore Ts'o <tytso@mit.edu>
Mon, 10 Jan 2011 17:46:59 +0000 (12:46 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 10 Jan 2011 17:46:59 +0000 (12:46 -0500)
Call ext4_std_error() in various places when we can't bail out
cleanly, so the file system can be marked as in error.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/resize.c

index 2693fcda30d82925e0fc3b44a44bcdcde7503152..84b616269265be918f6835c0c7fe65724b116fc1 100644 (file)
@@ -4185,6 +4185,7 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
 {
        __le32 *p;
        int     flags = EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_VALIDATED;
+       int     err;
 
        if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
                flags |= EXT4_FREE_BLOCKS_METADATA;
@@ -4200,11 +4201,23 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
        if (try_to_extend_transaction(handle, inode)) {
                if (bh) {
                        BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
-                       ext4_handle_dirty_metadata(handle, inode, bh);
+                       err = ext4_handle_dirty_metadata(handle, inode, bh);
+                       if (unlikely(err)) {
+                               ext4_std_error(inode->i_sb, err);
+                               return 1;
+                       }
+               }
+               err = ext4_mark_inode_dirty(handle, inode);
+               if (unlikely(err)) {
+                       ext4_std_error(inode->i_sb, err);
+                       return 1;
+               }
+               err = ext4_truncate_restart_trans(handle, inode,
+                                                 blocks_for_truncate(inode));
+               if (unlikely(err)) {
+                       ext4_std_error(inode->i_sb, err);
+                       return 1;
                }
-               ext4_mark_inode_dirty(handle, inode);
-               ext4_truncate_restart_trans(handle, inode,
-                                           blocks_for_truncate(inode));
                if (bh) {
                        BUFFER_TRACE(bh, "retaking write access");
                        ext4_journal_get_write_access(handle, bh);
index 6dfc5b9de3e67523d9ffa62702ec124dacee10f4..5485390d32c56e1b9b4ed7bd3802213827f8894c 100644 (file)
@@ -1602,7 +1602,11 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
                        if (err)
                                goto journal_error;
                }
-               ext4_handle_dirty_metadata(handle, inode, frames[0].bh);
+               err = ext4_handle_dirty_metadata(handle, inode, frames[0].bh);
+               if (err) {
+                       ext4_std_error(inode->i_sb, err);
+                       goto cleanup;
+               }
        }
        de = do_split(handle, dir, &bh, frame, &hinfo, &err);
        if (!de)
@@ -1630,7 +1634,7 @@ static int ext4_delete_entry(handle_t *handle,
 {
        struct ext4_dir_entry_2 *de, *pde;
        unsigned int blocksize = dir->i_sb->s_blocksize;
-       int i;
+       int i, err;
 
        i = 0;
        pde = NULL;
@@ -1640,7 +1644,11 @@ static int ext4_delete_entry(handle_t *handle,
                        return -EIO;
                if (de == de_del)  {
                        BUFFER_TRACE(bh, "get_write_access");
-                       ext4_journal_get_write_access(handle, bh);
+                       err = ext4_journal_get_write_access(handle, bh);
+                       if (unlikely(err)) {
+                               ext4_std_error(dir->i_sb, err);
+                               return err;
+                       }
                        if (pde)
                                pde->rec_len = ext4_rec_len_to_disk(
                                        ext4_rec_len_from_disk(pde->rec_len,
@@ -1652,7 +1660,11 @@ static int ext4_delete_entry(handle_t *handle,
                                de->inode = 0;
                        dir->i_version++;
                        BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
-                       ext4_handle_dirty_metadata(handle, dir, bh);
+                       err = ext4_handle_dirty_metadata(handle, dir, bh);
+                       if (unlikely(err)) {
+                               ext4_std_error(dir->i_sb, err);
+                               return err;
+                       }
                        return 0;
                }
                i += ext4_rec_len_from_disk(de->rec_len, blocksize);
@@ -2414,7 +2426,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                                        ext4_current_time(new_dir);
                ext4_mark_inode_dirty(handle, new_dir);
                BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata");
-               ext4_handle_dirty_metadata(handle, new_dir, new_bh);
+               retval = ext4_handle_dirty_metadata(handle, new_dir, new_bh);
+               if (unlikely(retval)) {
+                       ext4_std_error(new_dir->i_sb, retval);
+                       goto end_rename;
+               }
                brelse(new_bh);
                new_bh = NULL;
        }
@@ -2466,7 +2482,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) =
                                                cpu_to_le32(new_dir->i_ino);
                BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata");
-               ext4_handle_dirty_metadata(handle, old_dir, dir_bh);
+               retval = ext4_handle_dirty_metadata(handle, old_dir, dir_bh);
+               if (retval) {
+                       ext4_std_error(old_dir->i_sb, retval);
+                       goto end_rename;
+               }
                ext4_dec_count(handle, old_dir);
                if (new_inode) {
                        /* checked empty_dir above, can't have another parent,
index dc963929de652cb997550e38338855823832e53c..7faf47dde7fb9e0533413cdb12de8fa5c944b1e8 100644 (file)
@@ -220,7 +220,11 @@ static int setup_new_group_blocks(struct super_block *sb,
                memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size);
                set_buffer_uptodate(gdb);
                unlock_buffer(gdb);
-               ext4_handle_dirty_metadata(handle, NULL, gdb);
+               err = ext4_handle_dirty_metadata(handle, NULL, gdb);
+               if (unlikely(err)) {
+                       brelse(gdb);
+                       goto exit_bh;
+               }
                ext4_set_bit(bit, bh->b_data);
                brelse(gdb);
        }
@@ -253,7 +257,11 @@ static int setup_new_group_blocks(struct super_block *sb,
 
        ext4_mark_bitmap_end(input->blocks_count, sb->s_blocksize * 8,
                             bh->b_data);
-       ext4_handle_dirty_metadata(handle, NULL, bh);
+       err = ext4_handle_dirty_metadata(handle, NULL, bh);
+       if (unlikely(err)) {
+               ext4_std_error(sb, err);
+               goto exit_bh;
+       }
        brelse(bh);
        /* Mark unused entries in inode bitmap used */
        ext4_debug("clear inode bitmap %#04llx (+%llu)\n",
@@ -265,7 +273,9 @@ static int setup_new_group_blocks(struct super_block *sb,
 
        ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
                             bh->b_data);
-       ext4_handle_dirty_metadata(handle, NULL, bh);
+       err = ext4_handle_dirty_metadata(handle, NULL, bh);
+       if (unlikely(err))
+               ext4_std_error(sb, err);
 exit_bh:
        brelse(bh);
 
@@ -417,17 +427,21 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
                goto exit_dind;
        }
 
-       if ((err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh)))
+       err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
+       if (unlikely(err))
                goto exit_dind;
 
-       if ((err = ext4_journal_get_write_access(handle, *primary)))
+       err = ext4_journal_get_write_access(handle, *primary);
+       if (unlikely(err))
                goto exit_sbh;
 
-       if ((err = ext4_journal_get_write_access(handle, dind)))
-               goto exit_primary;
+       err = ext4_journal_get_write_access(handle, dind);
+       if (unlikely(err))
+               ext4_std_error(sb, err);
 
        /* ext4_reserve_inode_write() gets a reference on the iloc */
-       if ((err = ext4_reserve_inode_write(handle, inode, &iloc)))
+       err = ext4_reserve_inode_write(handle, inode, &iloc);
+       if (unlikely(err))
                goto exit_dindj;
 
        n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *),
@@ -449,12 +463,20 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
         * reserved inode, and will become GDT blocks (primary and backup).
         */
        data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)] = 0;
-       ext4_handle_dirty_metadata(handle, NULL, dind);
-       brelse(dind);
+       err = ext4_handle_dirty_metadata(handle, NULL, dind);
+       if (unlikely(err)) {
+               ext4_std_error(sb, err);
+               goto exit_inode;
+       }
        inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9;
        ext4_mark_iloc_dirty(handle, inode, &iloc);
        memset((*primary)->b_data, 0, sb->s_blocksize);
-       ext4_handle_dirty_metadata(handle, NULL, *primary);
+       err = ext4_handle_dirty_metadata(handle, NULL, *primary);
+       if (unlikely(err)) {
+               ext4_std_error(sb, err);
+               goto exit_inode;
+       }
+       brelse(dind);
 
        o_group_desc = EXT4_SB(sb)->s_group_desc;
        memcpy(n_group_desc, o_group_desc,
@@ -465,19 +487,19 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
        kfree(o_group_desc);
 
        le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
-       ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
+       err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
+       if (err)
+               ext4_std_error(sb, err);
 
-       return 0;
+       return err;
 
 exit_inode:
        /* ext4_journal_release_buffer(handle, iloc.bh); */
        brelse(iloc.bh);
 exit_dindj:
        /* ext4_journal_release_buffer(handle, dind); */
-exit_primary:
-       /* ext4_journal_release_buffer(handle, *primary); */
 exit_sbh:
-       /* ext4_journal_release_buffer(handle, *primary); */
+       /* ext4_journal_release_buffer(handle, EXT4_SB(sb)->s_sbh); */
 exit_dind:
        brelse(dind);
 exit_bh:
@@ -660,7 +682,9 @@ static void update_backups(struct super_block *sb,
                        memset(bh->b_data + size, 0, rest);
                set_buffer_uptodate(bh);
                unlock_buffer(bh);
-               ext4_handle_dirty_metadata(handle, NULL, bh);
+               err = ext4_handle_dirty_metadata(handle, NULL, bh);
+               if (unlikely(err))
+                       ext4_std_error(sb, err);
                brelse(bh);
        }
        if ((err2 = ext4_journal_stop(handle)) && !err)
@@ -878,7 +902,11 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
        /* Update the global fs size fields */
        sbi->s_groups_count++;
 
-       ext4_handle_dirty_metadata(handle, NULL, primary);
+       err = ext4_handle_dirty_metadata(handle, NULL, primary);
+       if (unlikely(err)) {
+               ext4_std_error(sb, err);
+               goto exit_journal;
+       }
 
        /* Update the reserved block counts only once the new group is
         * active. */