]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/ext4/ialloc.c
Merge remote-tracking branch 'ext4/dev'
[karo-tx-linux.git] / fs / ext4 / ialloc.c
index 619bfc1fda8cc0956ba87bfd9e9fa20b41c10cee..1b8024d26f654c5458c7e84db5a2c439adc6500e 100644 (file)
@@ -64,7 +64,7 @@ void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
 }
 
 /* Initializes an uninitialized inode bitmap */
-static unsigned ext4_init_inode_bitmap(struct super_block *sb,
+static int ext4_init_inode_bitmap(struct super_block *sb,
                                       struct buffer_head *bh,
                                       ext4_group_t block_group,
                                       struct ext4_group_desc *gdp)
@@ -89,7 +89,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
                                           count);
                }
                set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
-               return 0;
+               return -EFSBADCRC;
        }
 
        memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
@@ -99,7 +99,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
                                   EXT4_INODES_PER_GROUP(sb) / 8);
        ext4_group_desc_csum_set(sb, block_group, gdp);
 
-       return EXT4_INODES_PER_GROUP(sb);
+       return 0;
 }
 
 void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
@@ -112,6 +112,42 @@ void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
        put_bh(bh);
 }
 
+static int ext4_validate_inode_bitmap(struct super_block *sb,
+                                     struct ext4_group_desc *desc,
+                                     ext4_group_t block_group,
+                                     struct buffer_head *bh)
+{
+       ext4_fsblk_t    blk;
+       struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+       if (buffer_verified(bh))
+               return 0;
+       if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp))
+               return -EFSCORRUPTED;
+
+       ext4_lock_group(sb, block_group);
+       blk = ext4_inode_bitmap(sb, desc);
+       if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh,
+                                          EXT4_INODES_PER_GROUP(sb) / 8)) {
+               ext4_unlock_group(sb, block_group);
+               ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
+                          "inode_bitmap = %llu", block_group, blk);
+               grp = ext4_get_group_info(sb, block_group);
+               if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
+                       int count;
+                       count = ext4_free_inodes_count(sb, desc);
+                       percpu_counter_sub(&sbi->s_freeinodes_counter,
+                                          count);
+               }
+               set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
+               return -EFSBADCRC;
+       }
+       set_buffer_verified(bh);
+       ext4_unlock_group(sb, block_group);
+       return 0;
+}
+
 /*
  * Read the inode allocation bitmap for a given block_group, reading
  * into the specified slot in the superblock's bitmap cache.
@@ -124,12 +160,11 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
        struct ext4_group_desc *desc;
        struct buffer_head *bh = NULL;
        ext4_fsblk_t bitmap_blk;
-       struct ext4_group_info *grp;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       int err;
 
        desc = ext4_get_group_desc(sb, block_group, NULL);
        if (!desc)
-               return NULL;
+               return ERR_PTR(-EFSCORRUPTED);
 
        bitmap_blk = ext4_inode_bitmap(sb, desc);
        bh = sb_getblk(sb, bitmap_blk);
@@ -137,7 +172,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                ext4_error(sb, "Cannot read inode bitmap - "
                            "block_group = %u, inode_bitmap = %llu",
                            block_group, bitmap_blk);
-               return NULL;
+               return ERR_PTR(-EIO);
        }
        if (bitmap_uptodate(bh))
                goto verify;
@@ -150,12 +185,14 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
 
        ext4_lock_group(sb, block_group);
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
-               ext4_init_inode_bitmap(sb, bh, block_group, desc);
+               err = ext4_init_inode_bitmap(sb, bh, block_group, desc);
                set_bitmap_uptodate(bh);
                set_buffer_uptodate(bh);
                set_buffer_verified(bh);
                ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
+               if (err)
+                       goto out;
                return bh;
        }
        ext4_unlock_group(sb, block_group);
@@ -182,31 +219,17 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                ext4_error(sb, "Cannot read inode bitmap - "
                           "block_group = %u, inode_bitmap = %llu",
                           block_group, bitmap_blk);
-               return NULL;
+               return ERR_PTR(-EIO);
        }
 
 verify:
-       ext4_lock_group(sb, block_group);
-       if (!buffer_verified(bh) &&
-           !ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh,
-                                          EXT4_INODES_PER_GROUP(sb) / 8)) {
-               ext4_unlock_group(sb, block_group);
-               put_bh(bh);
-               ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
-                          "inode_bitmap = %llu", block_group, bitmap_blk);
-               grp = ext4_get_group_info(sb, block_group);
-               if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
-                       int count;
-                       count = ext4_free_inodes_count(sb, desc);
-                       percpu_counter_sub(&sbi->s_freeinodes_counter,
-                                          count);
-               }
-               set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
-               return NULL;
-       }
-       ext4_unlock_group(sb, block_group);
-       set_buffer_verified(bh);
+       err = ext4_validate_inode_bitmap(sb, desc, block_group, bh);
+       if (err)
+               goto out;
        return bh;
+out:
+       put_bh(bh);
+       return ERR_PTR(err);
 }
 
 /*
@@ -286,8 +309,15 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
        bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
        /* Don't bother if the inode bitmap is corrupt. */
        grp = ext4_get_group_info(sb, block_group);
-       if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) || !bitmap_bh)
+       if (IS_ERR(bitmap_bh)) {
+               fatal = PTR_ERR(bitmap_bh);
+               bitmap_bh = NULL;
+               goto error_return;
+       }
+       if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp))) {
+               fatal = -EFSCORRUPTED;
                goto error_return;
+       }
 
        BUFFER_TRACE(bitmap_bh, "get_write_access");
        fatal = ext4_journal_get_write_access(handle, bitmap_bh);
@@ -826,7 +856,9 @@ got_group:
                brelse(inode_bitmap_bh);
                inode_bitmap_bh = ext4_read_inode_bitmap(sb, group);
                /* Skip groups with suspicious inode tables */
-               if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || !inode_bitmap_bh) {
+               if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) ||
+                   IS_ERR(inode_bitmap_bh)) {
+                       inode_bitmap_bh = NULL;
                        if (++group == ngroups)
                                group = 0;
                        continue;
@@ -902,8 +934,8 @@ got:
                struct buffer_head *block_bitmap_bh;
 
                block_bitmap_bh = ext4_read_block_bitmap(sb, group);
-               if (!block_bitmap_bh) {
-                       err = -EIO;
+               if (IS_ERR(block_bitmap_bh)) {
+                       err = PTR_ERR(block_bitmap_bh);
                        goto out;
                }
                BUFFER_TRACE(block_bitmap_bh, "get block bitmap access");
@@ -1045,7 +1077,7 @@ got:
 
        ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
        ei->i_inline_off = 0;
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA))
+       if (ext4_has_feature_inline_data(sb))
                ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
        ret = inode;
        err = dquot_alloc_inode(inode);
@@ -1060,7 +1092,7 @@ got:
        if (err)
                goto fail_free_drop;
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+       if (ext4_has_feature_extents(sb)) {
                /* set extent flag only for directory, file and normal symlink*/
                if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) {
                        ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
@@ -1116,14 +1148,17 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
        /* Error cases - e2fsck has already cleaned up for us */
        if (ino > max_ino) {
                ext4_warning(sb, "bad orphan ino %lu!  e2fsck was run?", ino);
+               err = -EFSCORRUPTED;
                goto error;
        }
 
        block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
        bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
        bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
-       if (!bitmap_bh) {
-               ext4_warning(sb, "inode bitmap error for orphan %lu", ino);
+       if (IS_ERR(bitmap_bh)) {
+               err = PTR_ERR(bitmap_bh);
+               ext4_warning(sb, "inode bitmap error %ld for orphan %lu",
+                            ino, err);
                goto error;
        }
 
@@ -1198,8 +1233,10 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
                desc_count += ext4_free_inodes_count(sb, gdp);
                brelse(bitmap_bh);
                bitmap_bh = ext4_read_inode_bitmap(sb, i);
-               if (!bitmap_bh)
+               if (IS_ERR(bitmap_bh)) {
+                       bitmap_bh = NULL;
                        continue;
+               }
 
                x = ext4_count_free(bitmap_bh->b_data,
                                    EXT4_INODES_PER_GROUP(sb) / 8);