Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / ext4 / mballoc.c
index 28e421c208a5fd8c259ef24243c32f87a51290bc..b1ed9e07434ba4a15d86d1a538e6b808917901d6 100644 (file)
@@ -405,6 +405,12 @@ static inline void mb_clear_bit(int bit, void *addr)
        ext4_clear_bit(bit, addr);
 }
 
+static inline int mb_test_and_clear_bit(int bit, void *addr)
+{
+       addr = mb_correct_addr_and_bit(&bit, addr);
+       return ext4_test_and_clear_bit(bit, addr);
+}
+
 static inline int mb_find_next_zero_bit(void *addr, int max, int start)
 {
        int fix = 0, ret, tmpmax;
@@ -764,6 +770,24 @@ void ext4_mb_generate_buddy(struct super_block *sb,
        spin_unlock(&EXT4_SB(sb)->s_bal_lock);
 }
 
+static void mb_regenerate_buddy(struct ext4_buddy *e4b)
+{
+       int count;
+       int order = 1;
+       void *buddy;
+
+       while ((buddy = mb_find_buddy(e4b, order++, &count))) {
+               ext4_set_bits(buddy, 0, count);
+       }
+       e4b->bd_info->bb_fragments = 0;
+       memset(e4b->bd_info->bb_counters, 0,
+               sizeof(*e4b->bd_info->bb_counters) *
+               (e4b->bd_sb->s_blocksize_bits + 2));
+
+       ext4_mb_generate_buddy(e4b->bd_sb, e4b->bd_buddy,
+               e4b->bd_bitmap, e4b->bd_group);
+}
+
 /* The buddy information is attached the buddy cache inode
  * for convenience. The information regarding each group
  * is loaded via ext4_mb_load_buddy. The information involve
@@ -860,8 +884,6 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
 
        first_block = page->index * blocks_per_page;
        for (i = 0; i < blocks_per_page; i++) {
-               int group;
-
                group = (first_block + i) >> 1;
                if (group >= ngroups)
                        break;
@@ -1011,6 +1033,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
        struct page *page;
        int ret = 0;
 
+       might_sleep();
        mb_debug(1, "init group %u\n", group);
        this_grp = ext4_get_group_info(sb, group);
        /*
@@ -1082,6 +1105,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct inode *inode = sbi->s_buddy_cache;
 
+       might_sleep();
        mb_debug(1, "load group %u\n", group);
 
        blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
@@ -1244,6 +1268,33 @@ static void mb_clear_bits(void *bm, int cur, int len)
        }
 }
 
+/* clear bits in given range
+ * will return first found zero bit if any, -1 otherwise
+ */
+static int mb_test_and_clear_bits(void *bm, int cur, int len)
+{
+       __u32 *addr;
+       int zero_bit = -1;
+
+       len = cur + len;
+       while (cur < len) {
+               if ((cur & 31) == 0 && (len - cur) >= 32) {
+                       /* fast path: clear whole word at once */
+                       addr = bm + (cur >> 3);
+                       if (*addr != (__u32)(-1) && zero_bit == -1)
+                               zero_bit = cur + mb_find_next_zero_bit(addr, 32, 0);
+                       *addr = 0;
+                       cur += 32;
+                       continue;
+               }
+               if (!mb_test_and_clear_bit(cur, bm) && zero_bit == -1)
+                       zero_bit = cur;
+               cur++;
+       }
+
+       return zero_bit;
+}
+
 void ext4_set_bits(void *bm, int cur, int len)
 {
        __u32 *addr;
@@ -1262,17 +1313,90 @@ void ext4_set_bits(void *bm, int cur, int len)
        }
 }
 
+/*
+ * _________________________________________________________________ */
+
+static inline int mb_buddy_adjust_border(int* bit, void* bitmap, int side)
+{
+       if (mb_test_bit(*bit + side, bitmap)) {
+               mb_clear_bit(*bit, bitmap);
+               (*bit) -= side;
+               return 1;
+       }
+       else {
+               (*bit) += side;
+               mb_set_bit(*bit, bitmap);
+               return -1;
+       }
+}
+
+static void mb_buddy_mark_free(struct ext4_buddy *e4b, int first, int last)
+{
+       int max;
+       int order = 1;
+       void *buddy = mb_find_buddy(e4b, order, &max);
+
+       while (buddy) {
+               void *buddy2;
+
+               /* Bits in range [first; last] are known to be set since
+                * corresponding blocks were allocated. Bits in range
+                * (first; last) will stay set because they form buddies on
+                * upper layer. We just deal with borders if they don't
+                * align with upper layer and then go up.
+                * Releasing entire group is all about clearing
+                * single bit of highest order buddy.
+                */
+
+               /* Example:
+                * ---------------------------------
+                * |   1   |   1   |   1   |   1   |
+                * ---------------------------------
+                * | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+                * ---------------------------------
+                *   0   1   2   3   4   5   6   7
+                *      \_____________________/
+                *
+                * Neither [1] nor [6] is aligned to above layer.
+                * Left neighbour [0] is free, so mark it busy,
+                * decrease bb_counters and extend range to
+                * [0; 6]
+                * Right neighbour [7] is busy. It can't be coaleasced with [6], so
+                * mark [6] free, increase bb_counters and shrink range to
+                * [0; 5].
+                * Then shift range to [0; 2], go up and do the same.
+                */
+
+
+               if (first & 1)
+                       e4b->bd_info->bb_counters[order] += mb_buddy_adjust_border(&first, buddy, -1);
+               if (!(last & 1))
+                       e4b->bd_info->bb_counters[order] += mb_buddy_adjust_border(&last, buddy, 1);
+               if (first > last)
+                       break;
+               order++;
+
+               if (first == last || !(buddy2 = mb_find_buddy(e4b, order, &max))) {
+                       mb_clear_bits(buddy, first, last - first + 1);
+                       e4b->bd_info->bb_counters[order - 1] += last - first + 1;
+                       break;
+               }
+               first >>= 1;
+               last >>= 1;
+               buddy = buddy2;
+       }
+}
+
 static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
-                         int first, int count)
+                          int first, int count)
 {
-       int block = 0;
-       int max = 0;
-       int order;
-       void *buddy;
-       void *buddy2;
+       int left_is_free = 0;
+       int right_is_free = 0;
+       int block;
+       int last = first + count - 1;
        struct super_block *sb = e4b->bd_sb;
 
-       BUG_ON(first + count > (sb->s_blocksize << 3));
+       BUG_ON(last >= (sb->s_blocksize << 3));
        assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
        mb_check_buddy(e4b);
        mb_free_blocks_double(inode, e4b, first, count);
@@ -1281,67 +1405,54 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
        if (first < e4b->bd_info->bb_first_free)
                e4b->bd_info->bb_first_free = first;
 
-       /* let's maintain fragments counter */
+       /* access memory sequentially: check left neighbour,
+        * clear range and then check right neighbour
+        */
        if (first != 0)
-               block = !mb_test_bit(first - 1, e4b->bd_bitmap);
-       if (first + count < EXT4_SB(sb)->s_mb_maxs[0])
-               max = !mb_test_bit(first + count, e4b->bd_bitmap);
-       if (block && max)
-               e4b->bd_info->bb_fragments--;
-       else if (!block && !max)
-               e4b->bd_info->bb_fragments++;
+               left_is_free = !mb_test_bit(first - 1, e4b->bd_bitmap);
+       block = mb_test_and_clear_bits(e4b->bd_bitmap, first, count);
+       if (last + 1 < EXT4_SB(sb)->s_mb_maxs[0])
+               right_is_free = !mb_test_bit(last + 1, e4b->bd_bitmap);
 
-       /* let's maintain buddy itself */
-       while (count-- > 0) {
-               block = first++;
-               order = 0;
+       if (unlikely(block != -1)) {
+               ext4_fsblk_t blocknr;
 
-               if (!mb_test_bit(block, e4b->bd_bitmap)) {
-                       ext4_fsblk_t blocknr;
-
-                       blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
-                       blocknr += EXT4_C2B(EXT4_SB(sb), block);
-                       ext4_grp_locked_error(sb, e4b->bd_group,
-                                             inode ? inode->i_ino : 0,
-                                             blocknr,
-                                             "freeing already freed block "
-                                             "(bit %u)", block);
-               }
-               mb_clear_bit(block, e4b->bd_bitmap);
-               e4b->bd_info->bb_counters[order]++;
-
-               /* start of the buddy */
-               buddy = mb_find_buddy(e4b, order, &max);
-
-               do {
-                       block &= ~1UL;
-                       if (mb_test_bit(block, buddy) ||
-                                       mb_test_bit(block + 1, buddy))
-                               break;
-
-                       /* both the buddies are free, try to coalesce them */
-                       buddy2 = mb_find_buddy(e4b, order + 1, &max);
+               blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
+               blocknr += EXT4_C2B(EXT4_SB(sb), block);
+               ext4_grp_locked_error(sb, e4b->bd_group,
+                                     inode ? inode->i_ino : 0,
+                                     blocknr,
+                                     "freeing already freed block "
+                                     "(bit %u)", block);
+               mb_regenerate_buddy(e4b);
+               goto done;
+       }
 
-                       if (!buddy2)
-                               break;
+       /* let's maintain fragments counter */
+       if (left_is_free && right_is_free)
+               e4b->bd_info->bb_fragments--;
+       else if (!left_is_free && !right_is_free)
+               e4b->bd_info->bb_fragments++;
 
-                       if (order > 0) {
-                               /* for special purposes, we don't set
-                                * free bits in bitmap */
-                               mb_set_bit(block, buddy);
-                               mb_set_bit(block + 1, buddy);
-                       }
-                       e4b->bd_info->bb_counters[order]--;
-                       e4b->bd_info->bb_counters[order]--;
+       /* buddy[0] == bd_bitmap is a special case, so handle
+        * it right away and let mb_buddy_mark_free stay free of
+        * zero order checks.
+        * Check if neighbours are to be coaleasced,
+        * adjust bitmap bb_counters and borders appropriately.
+        */
+       if (first & 1) {
+               first += !left_is_free;
+               e4b->bd_info->bb_counters[0] += left_is_free ? -1 : 1;
+       }
+       if (!(last & 1)) {
+               last -= !right_is_free;
+               e4b->bd_info->bb_counters[0] += right_is_free ? -1 : 1;
+       }
 
-                       block = block >> 1;
-                       order++;
-                       e4b->bd_info->bb_counters[order]++;
+       if (first <= last)
+               mb_buddy_mark_free(e4b, first >> 1, last >> 1);
 
-                       mb_clear_bit(block, buddy2);
-                       buddy = buddy2;
-               } while (1);
-       }
+done:
        mb_set_largest_free_order(sb, e4b->bd_info);
        mb_check_buddy(e4b);
 }
@@ -3342,7 +3453,7 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
        if (pa->pa_type == MB_GROUP_PA)
                grp_blk--;
 
-       ext4_get_group_no_and_offset(sb, grp_blk, &grp, NULL);
+       grp = ext4_get_group_number(sb, grp_blk);
 
        /*
         * possible race:
@@ -3807,7 +3918,7 @@ repeat:
 
        list_for_each_entry_safe(pa, tmp, &list, u.pa_tmp_list) {
                BUG_ON(pa->pa_type != MB_INODE_PA);
-               ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+               group = ext4_get_group_number(sb, pa->pa_pstart);
 
                err = ext4_mb_load_buddy(sb, group, &e4b);
                if (err) {
@@ -4069,7 +4180,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
 
        list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
 
-               ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+               group = ext4_get_group_number(sb, pa->pa_pstart);
                if (ext4_mb_load_buddy(sb, group, &e4b)) {
                        ext4_error(sb, "Error loading buddy information for %u",
                                        group);
@@ -4217,6 +4328,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
        unsigned int inquota = 0;
        unsigned int reserv_clstrs = 0;
 
+       might_sleep();
        sb = ar->inode->i_sb;
        sbi = EXT4_SB(sb);
 
@@ -4420,11 +4532,11 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        node = rb_prev(new_node);
        if (node) {
                entry = rb_entry(node, struct ext4_free_data, efd_node);
-               if (can_merge(entry, new_entry)) {
+               if (can_merge(entry, new_entry) &&
+                   ext4_journal_callback_try_del(handle, &entry->efd_jce)) {
                        new_entry->efd_start_cluster = entry->efd_start_cluster;
                        new_entry->efd_count += entry->efd_count;
                        rb_erase(node, &(db->bb_free_root));
-                       ext4_journal_callback_del(handle, &entry->efd_jce);
                        kmem_cache_free(ext4_free_data_cachep, entry);
                }
        }
@@ -4432,10 +4544,10 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
        node = rb_next(new_node);
        if (node) {
                entry = rb_entry(node, struct ext4_free_data, efd_node);
-               if (can_merge(new_entry, entry)) {
+               if (can_merge(new_entry, entry) &&
+                   ext4_journal_callback_try_del(handle, &entry->efd_jce)) {
                        new_entry->efd_count += entry->efd_count;
                        rb_erase(node, &(db->bb_free_root));
-                       ext4_journal_callback_del(handle, &entry->efd_jce);
                        kmem_cache_free(ext4_free_data_cachep, entry);
                }
        }
@@ -4470,6 +4582,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
        int err = 0;
        int ret;
 
+       might_sleep();
        if (bh) {
                if (block)
                        BUG_ON(block != bh->b_blocknr);