return ret;
 }
 
-static int tree_move_down(struct btrfs_path *path, int *level)
+static int tree_move_down(struct btrfs_path *path, int *level, u64 reada_min_gen)
 {
        struct extent_buffer *eb;
+       struct extent_buffer *parent = path->nodes[*level];
+       int slot = path->slots[*level];
+       const int nritems = btrfs_header_nritems(parent);
+       u64 reada_max;
+       u64 reada_done = 0;
 
        BUG_ON(*level == 0);
-       eb = btrfs_read_node_slot(path->nodes[*level], path->slots[*level]);
+       eb = btrfs_read_node_slot(parent, slot);
        if (IS_ERR(eb))
                return PTR_ERR(eb);
 
+       /*
+        * Trigger readahead for the next leaves we will process, so that it is
+        * very likely that when we need them they are already in memory and we
+        * will not block on disk IO. For nodes we only do readahead for one,
+        * since the time window between processing nodes is typically larger.
+        */
+       reada_max = (*level == 1 ? SZ_128K : eb->fs_info->nodesize);
+
+       for (slot++; slot < nritems && reada_done < reada_max; slot++) {
+               if (btrfs_node_ptr_generation(parent, slot) > reada_min_gen) {
+                       btrfs_readahead_node_child(parent, slot);
+                       reada_done += eb->fs_info->nodesize;
+               }
+       }
+
        path->nodes[*level - 1] = eb;
        path->slots[*level - 1] = 0;
        (*level)--;
 static int tree_advance(struct btrfs_path *path,
                        int *level, int root_level,
                        int allow_down,
-                       struct btrfs_key *key)
+                       struct btrfs_key *key,
+                       u64 reada_min_gen)
 {
        int ret;
 
        if (*level == 0 || !allow_down) {
                ret = tree_move_next_or_upnext(path, level, root_level);
        } else {
-               ret = tree_move_down(path, level);
+               ret = tree_move_down(path, level, reada_min_gen);
        }
        if (ret >= 0) {
                if (*level == 0)
        u64 right_blockptr;
        u64 left_gen;
        u64 right_gen;
+       u64 reada_min_gen;
 
        left_path = btrfs_alloc_path();
        if (!left_path) {
                ret = -ENOMEM;
                goto out;
        }
+       /*
+        * Our right root is the parent root, while the left root is the "send"
+        * root. We know that all new nodes/leaves in the left root must have
+        * a generation greater than the right root's generation, so we trigger
+        * readahead for those nodes and leaves of the left root, as we know we
+        * will need to read them at some point.
+        */
+       reada_min_gen = btrfs_header_generation(right_root->commit_root);
        up_read(&fs_info->commit_root_sem);
 
        if (left_level == 0)
                        ret = tree_advance(left_path, &left_level,
                                        left_root_level,
                                        advance_left != ADVANCE_ONLY_NEXT,
-                                       &left_key);
+                                       &left_key, reada_min_gen);
                        if (ret == -1)
                                left_end_reached = ADVANCE;
                        else if (ret < 0)
                        ret = tree_advance(right_path, &right_level,
                                        right_root_level,
                                        advance_right != ADVANCE_ONLY_NEXT,
-                                       &right_key);
+                                       &right_key, reada_min_gen);
                        if (ret == -1)
                                right_end_reached = ADVANCE;
                        else if (ret < 0)