static int __es_insert_extent(struct inode *inode, struct extent_status *newes);
 static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
                              ext4_lblk_t end);
-static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei,
-                                      int nr_to_scan);
+static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan);
 static int __es_shrink(struct ext4_sb_info *sbi, int nr_to_scan,
                       struct ext4_inode_info *locked_ei);
 
 retry:
        err = __es_insert_extent(inode, &newes);
        if (err == -ENOMEM && __es_shrink(EXT4_SB(inode->i_sb),
-                                         1, EXT4_I(inode)))
+                                         128, EXT4_I(inode)))
                goto retry;
        if (err == -ENOMEM && !ext4_es_is_delayed(&newes))
                err = 0;
                                es->es_len = orig_es.es_len;
                                if ((err == -ENOMEM) &&
                                    __es_shrink(EXT4_SB(inode->i_sb),
-                                                       1, EXT4_I(inode)))
+                                                       128, EXT4_I(inode)))
                                        goto retry;
                                goto out;
                        }
        spin_lock(&sbi->s_es_lock);
        nr_to_walk = sbi->s_es_nr_inode;
        while (nr_to_walk-- > 0) {
-               int shrunk;
-
                if (list_empty(&sbi->s_es_list)) {
                        spin_unlock(&sbi->s_es_lock);
                        goto out;
                ei = list_first_entry(&sbi->s_es_list, struct ext4_inode_info,
                                      i_es_list);
                /* Move the inode to the tail */
-               list_move(&ei->i_es_list, sbi->s_es_list.prev);
+               list_move_tail(&ei->i_es_list, &sbi->s_es_list);
 
                /*
                 * Normally we try hard to avoid shrinking precached inodes,
                 */
                spin_unlock(&sbi->s_es_lock);
 
-               shrunk = __es_try_to_reclaim_extents(ei, nr_to_scan);
+               nr_shrunk += es_reclaim_extents(ei, &nr_to_scan);
                write_unlock(&ei->i_es_lock);
 
-               nr_shrunk += shrunk;
-               nr_to_scan -= shrunk;
-
-               if (nr_to_scan == 0)
+               if (nr_to_scan <= 0)
                        goto out;
                spin_lock(&sbi->s_es_lock);
        }
        }
 
        if (locked_ei && nr_shrunk == 0)
-               nr_shrunk = __es_try_to_reclaim_extents(locked_ei, nr_to_scan);
+               nr_shrunk = es_reclaim_extents(locked_ei, &nr_to_scan);
 
 out:
        scan_time = ktime_to_ns(ktime_sub(ktime_get(), start_time));
        unregister_shrinker(&sbi->s_es_shrinker);
 }
 
-static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei,
-                                      int nr_to_scan)
+/*
+ * Shrink extents in given inode from ei->i_es_shrink_lblk till end. Scan at
+ * most *nr_to_scan extents, update *nr_to_scan accordingly.
+ *
+ * Return 0 if we hit end of tree / interval, 1 if we exhausted nr_to_scan.
+ * Increment *nr_shrunk by the number of reclaimed extents. Also update
+ * ei->i_es_shrink_lblk to where we should continue scanning.
+ */
+static int es_do_reclaim_extents(struct ext4_inode_info *ei, ext4_lblk_t end,
+                                int *nr_to_scan, int *nr_shrunk)
 {
        struct inode *inode = &ei->vfs_inode;
        struct ext4_es_tree *tree = &ei->i_es_tree;
-       struct rb_node *node;
        struct extent_status *es;
-       unsigned long nr_shrunk = 0;
-       static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
-                                     DEFAULT_RATELIMIT_BURST);
-
-       if (ei->i_es_shk_nr == 0)
-               return 0;
+       struct rb_node *node;
 
-       if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED) &&
-           __ratelimit(&_rs))
-               ext4_warning(inode->i_sb, "forced shrink of precached extents");
+       es = __es_tree_search(&tree->root, ei->i_es_shrink_lblk);
+       if (!es)
+               goto out_wrap;
+       node = &es->rb_node;
+       while (*nr_to_scan > 0) {
+               if (es->es_lblk > end) {
+                       ei->i_es_shrink_lblk = end + 1;
+                       return 0;
+               }
 
-       node = rb_first(&tree->root);
-       while (node != NULL) {
-               es = rb_entry(node, struct extent_status, rb_node);
+               (*nr_to_scan)--;
                node = rb_next(&es->rb_node);
                /*
                 * We can't reclaim delayed extent from status tree because
                if (!ext4_es_is_delayed(es)) {
                        rb_erase(&es->rb_node, &tree->root);
                        ext4_es_free_extent(inode, es);
-                       nr_shrunk++;
-                       if (--nr_to_scan == 0)
-                               break;
+                       (*nr_shrunk)++;
                }
+               if (!node)
+                       goto out_wrap;
+               es = rb_entry(node, struct extent_status, rb_node);
        }
-       tree->cache_es = NULL;
+       ei->i_es_shrink_lblk = es->es_lblk;
+       return 1;
+out_wrap:
+       ei->i_es_shrink_lblk = 0;
+       return 0;
+}
+
+static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan)
+{
+       struct inode *inode = &ei->vfs_inode;
+       int nr_shrunk = 0;
+       ext4_lblk_t start = ei->i_es_shrink_lblk;
+       static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
+                                     DEFAULT_RATELIMIT_BURST);
+
+       if (ei->i_es_shk_nr == 0)
+               return 0;
+
+       if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED) &&
+           __ratelimit(&_rs))
+               ext4_warning(inode->i_sb, "forced shrink of precached extents");
+
+       if (!es_do_reclaim_extents(ei, EXT_MAX_BLOCKS, nr_to_scan, &nr_shrunk) &&
+           start != 0)
+               es_do_reclaim_extents(ei, start - 1, nr_to_scan, &nr_shrunk);
+
+       ei->i_es_tree.cache_es = NULL;
        return nr_shrunk;
 }