ext4: add new helper interface ext4_try_to_trim_range()
[sfrench/cifs-2.6.git] / fs / ext4 / mballoc.c
index 018d5d3c6eeb7ca3687e88c7be8a32d8844ab747..e3844152a643054628727367d7d25482b23da29b 100644 (file)
@@ -6218,6 +6218,54 @@ __acquires(bitlock)
        return ret;
 }
 
+static int ext4_try_to_trim_range(struct super_block *sb,
+               struct ext4_buddy *e4b, ext4_grpblk_t start,
+               ext4_grpblk_t max, ext4_grpblk_t minblocks)
+{
+       ext4_grpblk_t next, count, free_count;
+       void *bitmap;
+       int ret = 0;
+
+       bitmap = e4b->bd_bitmap;
+       start = (e4b->bd_info->bb_first_free > start) ?
+               e4b->bd_info->bb_first_free : start;
+       count = 0;
+       free_count = 0;
+
+       while (start <= max) {
+               start = mb_find_next_zero_bit(bitmap, max + 1, start);
+               if (start > max)
+                       break;
+               next = mb_find_next_bit(bitmap, max + 1, start);
+
+               if ((next - start) >= minblocks) {
+                       ret = ext4_trim_extent(sb, start, next - start, e4b);
+                       if (ret && ret != -EOPNOTSUPP)
+                               break;
+                       ret = 0;
+                       count += next - start;
+               }
+               free_count += next - start;
+               start = next + 1;
+
+               if (fatal_signal_pending(current)) {
+                       count = -ERESTARTSYS;
+                       break;
+               }
+
+               if (need_resched()) {
+                       ext4_unlock_group(sb, e4b->bd_group);
+                       cond_resched();
+                       ext4_lock_group(sb, e4b->bd_group);
+               }
+
+               if ((e4b->bd_info->bb_free - free_count) < minblocks)
+                       break;
+       }
+
+       return count;
+}
+
 /**
  * ext4_trim_all_free -- function to trim all free space in alloc. group
  * @sb:                        super block for file system
@@ -6241,10 +6289,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
                   ext4_grpblk_t start, ext4_grpblk_t max,
                   ext4_grpblk_t minblocks)
 {
-       void *bitmap;
-       ext4_grpblk_t next, count = 0, free_count = 0;
        struct ext4_buddy e4b;
-       int ret = 0;
+       int ret;
 
        trace_ext4_trim_all_free(sb, group, start, max);
 
@@ -6254,57 +6300,23 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group,
                             ret, group);
                return ret;
        }
-       bitmap = e4b.bd_bitmap;
 
        ext4_lock_group(sb, group);
-       if (EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) &&
-           minblocks >= atomic_read(&EXT4_SB(sb)->s_last_trim_minblks))
-               goto out;
-
-       start = (e4b.bd_info->bb_first_free > start) ?
-               e4b.bd_info->bb_first_free : start;
 
-       while (start <= max) {
-               start = mb_find_next_zero_bit(bitmap, max + 1, start);
-               if (start > max)
-                       break;
-               next = mb_find_next_bit(bitmap, max + 1, start);
-
-               if ((next - start) >= minblocks) {
-                       ret = ext4_trim_extent(sb, start, next - start, &e4b);
-                       if (ret && ret != -EOPNOTSUPP)
-                               break;
-                       ret = 0;
-                       count += next - start;
-               }
-               free_count += next - start;
-               start = next + 1;
-
-               if (fatal_signal_pending(current)) {
-                       count = -ERESTARTSYS;
-                       break;
-               }
-
-               if (need_resched()) {
-                       ext4_unlock_group(sb, group);
-                       cond_resched();
-                       ext4_lock_group(sb, group);
-               }
-
-               if ((e4b.bd_info->bb_free - free_count) < minblocks)
-                       break;
+       if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) ||
+           minblocks < atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) {
+               ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks);
+               if (ret >= 0)
+                       EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
+       } else {
+               ret = 0;
        }
 
-       if (!ret) {
-               ret = count;
-               EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info);
-       }
-out:
        ext4_unlock_group(sb, group);
        ext4_mb_unload_buddy(&e4b);
 
        ext4_debug("trimmed %d blocks in the group %d\n",
-               count, group);
+               ret, group);
 
        return ret;
 }