ext4: save all error info in save_error_info() and drop ext4_set_errno()
[linux-block.git] / fs / ext4 / mballoc.c
index f64838187559f25b859ba5acce4d0186a2c4415b..87c85be4c12e568d3d272cc8cf87f634ee13cf9a 100644 (file)
@@ -1901,8 +1901,15 @@ void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,
                BUG_ON(buddy == NULL);
 
                k = mb_find_next_zero_bit(buddy, max, 0);
-               BUG_ON(k >= max);
-
+               if (k >= max) {
+                       ext4_grp_locked_error(ac->ac_sb, e4b->bd_group, 0, 0,
+                               "%d free clusters of order %d. But found 0",
+                               grp->bb_counters[i], i);
+                       ext4_mark_group_bitmap_corrupted(ac->ac_sb,
+                                        e4b->bd_group,
+                                       EXT4_GROUP_INFO_BBITMAP_CORRUPT);
+                       break;
+               }
                ac->ac_found++;
 
                ac->ac_b_ex.fe_len = 1 << i;
@@ -2356,7 +2363,7 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        unsigned size;
-       struct ext4_group_info ***new_groupinfo;
+       struct ext4_group_info ***old_groupinfo, ***new_groupinfo;
 
        size = (ngroups + EXT4_DESC_PER_BLOCK(sb) - 1) >>
                EXT4_DESC_PER_BLOCK_BITS(sb);
@@ -2369,13 +2376,16 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups)
                ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group");
                return -ENOMEM;
        }
-       if (sbi->s_group_info) {
-               memcpy(new_groupinfo, sbi->s_group_info,
+       rcu_read_lock();
+       old_groupinfo = rcu_dereference(sbi->s_group_info);
+       if (old_groupinfo)
+               memcpy(new_groupinfo, old_groupinfo,
                       sbi->s_group_info_size * sizeof(*sbi->s_group_info));
-               kvfree(sbi->s_group_info);
-       }
-       sbi->s_group_info = new_groupinfo;
+       rcu_read_unlock();
+       rcu_assign_pointer(sbi->s_group_info, new_groupinfo);
        sbi->s_group_info_size = size / sizeof(*sbi->s_group_info);
+       if (old_groupinfo)
+               ext4_kvfree_array_rcu(old_groupinfo);
        ext4_debug("allocated s_groupinfo array for %d meta_bg's\n", 
                   sbi->s_group_info_size);
        return 0;
@@ -2387,6 +2397,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
 {
        int i;
        int metalen = 0;
+       int idx = group >> EXT4_DESC_PER_BLOCK_BITS(sb);
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct ext4_group_info **meta_group_info;
        struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
@@ -2405,12 +2416,12 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
                                 "for a buddy group");
                        goto exit_meta_group_info;
                }
-               sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] =
-                       meta_group_info;
+               rcu_read_lock();
+               rcu_dereference(sbi->s_group_info)[idx] = meta_group_info;
+               rcu_read_unlock();
        }
 
-       meta_group_info =
-               sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)];
+       meta_group_info = sbi_array_rcu_deref(sbi, s_group_info, idx);
        i = group & (EXT4_DESC_PER_BLOCK(sb) - 1);
 
        meta_group_info[i] = kmem_cache_zalloc(cachep, GFP_NOFS);
@@ -2458,8 +2469,13 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
 exit_group_info:
        /* If a meta_group_info table has been allocated, release it now */
        if (group % EXT4_DESC_PER_BLOCK(sb) == 0) {
-               kfree(sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]);
-               sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = NULL;
+               struct ext4_group_info ***group_info;
+
+               rcu_read_lock();
+               group_info = rcu_dereference(sbi->s_group_info);
+               kfree(group_info[idx]);
+               group_info[idx] = NULL;
+               rcu_read_unlock();
        }
 exit_meta_group_info:
        return -ENOMEM;
@@ -2472,6 +2488,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        int err;
        struct ext4_group_desc *desc;
+       struct ext4_group_info ***group_info;
        struct kmem_cache *cachep;
 
        err = ext4_mb_alloc_groupinfo(sb, ngroups);
@@ -2507,11 +2524,16 @@ err_freebuddy:
        while (i-- > 0)
                kmem_cache_free(cachep, ext4_get_group_info(sb, i));
        i = sbi->s_group_info_size;
+       rcu_read_lock();
+       group_info = rcu_dereference(sbi->s_group_info);
        while (i-- > 0)
-               kfree(sbi->s_group_info[i]);
+               kfree(group_info[i]);
+       rcu_read_unlock();
        iput(sbi->s_buddy_cache);
 err_freesgi:
-       kvfree(sbi->s_group_info);
+       rcu_read_lock();
+       kvfree(rcu_dereference(sbi->s_group_info));
+       rcu_read_unlock();
        return -ENOMEM;
 }
 
@@ -2700,7 +2722,7 @@ int ext4_mb_release(struct super_block *sb)
        ext4_group_t ngroups = ext4_get_groups_count(sb);
        ext4_group_t i;
        int num_meta_group_infos;
-       struct ext4_group_info *grinfo;
+       struct ext4_group_info *grinfo, ***group_info;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits);
 
@@ -2719,9 +2741,12 @@ int ext4_mb_release(struct super_block *sb)
                num_meta_group_infos = (ngroups +
                                EXT4_DESC_PER_BLOCK(sb) - 1) >>
                        EXT4_DESC_PER_BLOCK_BITS(sb);
+               rcu_read_lock();
+               group_info = rcu_dereference(sbi->s_group_info);
                for (i = 0; i < num_meta_group_infos; i++)
-                       kfree(sbi->s_group_info[i]);
-               kvfree(sbi->s_group_info);
+                       kfree(group_info[i]);
+               kvfree(group_info);
+               rcu_read_unlock();
        }
        kfree(sbi->s_mb_offsets);
        kfree(sbi->s_mb_maxs);
@@ -3020,7 +3045,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
                ext4_group_t flex_group = ext4_flex_group(sbi,
                                                          ac->ac_b_ex.fe_group);
                atomic64_sub(ac->ac_b_ex.fe_len,
-                            &sbi->s_flex_groups[flex_group].free_clusters);
+                            &sbi_array_rcu_deref(sbi, s_flex_groups,
+                                                 flex_group)->free_clusters);
        }
 
        err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
@@ -3895,9 +3921,9 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
        bitmap_bh = ext4_read_block_bitmap(sb, group);
        if (IS_ERR(bitmap_bh)) {
                err = PTR_ERR(bitmap_bh);
-               ext4_set_errno(sb, -err);
-               ext4_error(sb, "Error %d reading block bitmap for %u",
-                          err, group);
+               ext4_error_err(sb, -err,
+                              "Error %d reading block bitmap for %u",
+                              err, group);
                return 0;
        }
 
@@ -4064,18 +4090,16 @@ repeat:
                err = ext4_mb_load_buddy_gfp(sb, group, &e4b,
                                             GFP_NOFS|__GFP_NOFAIL);
                if (err) {
-                       ext4_set_errno(sb, -err);
-                       ext4_error(sb, "Error %d loading buddy information for %u",
-                                  err, group);
+                       ext4_error_err(sb, -err, "Error %d loading buddy information for %u",
+                                      err, group);
                        continue;
                }
 
                bitmap_bh = ext4_read_block_bitmap(sb, group);
                if (IS_ERR(bitmap_bh)) {
                        err = PTR_ERR(bitmap_bh);
-                       ext4_set_errno(sb, -err);
-                       ext4_error(sb, "Error %d reading block bitmap for %u",
-                                       err, group);
+                       ext4_error_err(sb, -err, "Error %d reading block bitmap for %u",
+                                      err, group);
                        ext4_mb_unload_buddy(&e4b);
                        continue;
                }
@@ -4283,7 +4307,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
 
        spin_lock(&lg->lg_prealloc_lock);
        list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order],
-                                               pa_inode_list) {
+                               pa_inode_list,
+                               lockdep_is_held(&lg->lg_prealloc_lock)) {
                spin_lock(&pa->pa_lock);
                if (atomic_read(&pa->pa_count)) {
                        /*
@@ -4328,9 +4353,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
                err = ext4_mb_load_buddy_gfp(sb, group, &e4b,
                                             GFP_NOFS|__GFP_NOFAIL);
                if (err) {
-                       ext4_set_errno(sb, -err);
-                       ext4_error(sb, "Error %d loading buddy information for %u",
-                                  err, group);
+                       ext4_error_err(sb, -err, "Error %d loading buddy information for %u",
+                                      err, group);
                        continue;
                }
                ext4_lock_group(sb, group);
@@ -4367,7 +4391,8 @@ static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac)
        /* Add the prealloc space to lg */
        spin_lock(&lg->lg_prealloc_lock);
        list_for_each_entry_rcu(tmp_pa, &lg->lg_prealloc_list[order],
-                                               pa_inode_list) {
+                               pa_inode_list,
+                               lockdep_is_held(&lg->lg_prealloc_lock)) {
                spin_lock(&tmp_pa->pa_lock);
                if (tmp_pa->pa_deleted) {
                        spin_unlock(&tmp_pa->pa_lock);
@@ -4918,7 +4943,8 @@ do_more:
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
                atomic64_add(count_clusters,
-                            &sbi->s_flex_groups[flex_group].free_clusters);
+                            &sbi_array_rcu_deref(sbi, s_flex_groups,
+                                                 flex_group)->free_clusters);
        }
 
        /*
@@ -5075,7 +5101,8 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
                atomic64_add(clusters_freed,
-                            &sbi->s_flex_groups[flex_group].free_clusters);
+                            &sbi_array_rcu_deref(sbi, s_flex_groups,
+                                                 flex_group)->free_clusters);
        }
 
        ext4_mb_unload_buddy(&e4b);