libbtrfsutil: don't return free space cache inodes from deleted_subvolumes()
[platform/upstream/btrfs-progs.git] / extent_io.c
index 069c199..eda1fb6 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 021110-1307, USA.
  */
-#define _XOPEN_SOURCE 600
-#define __USE_XOPEN2K
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <stdbool.h>
 #include "kerncompat.h"
 #include "extent_io.h"
 #include "list.h"
-
-u64 cache_max = 1024 * 1024 * 32;
+#include "ctree.h"
+#include "volumes.h"
+#include "utils.h"
+#include "internal.h"
 
 void extent_io_tree_init(struct extent_io_tree *tree)
 {
@@ -36,6 +37,14 @@ void extent_io_tree_init(struct extent_io_tree *tree)
        cache_tree_init(&tree->cache);
        INIT_LIST_HEAD(&tree->lru);
        tree->cache_size = 0;
+       tree->max_cache_size = (u64)total_memory() / 4;
+}
+
+void extent_io_tree_init_cache_max(struct extent_io_tree *tree,
+                                  u64 max_cache_size)
+{
+       extent_io_tree_init(tree);
+       tree->max_cache_size = max_cache_size;
 }
 
 static struct extent_state *alloc_extent_state(void)
@@ -45,13 +54,14 @@ static struct extent_state *alloc_extent_state(void)
        state = malloc(sizeof(*state));
        if (!state)
                return NULL;
+       state->cache_node.objectid = 0;
        state->refs = 1;
        state->state = 0;
-       state->private = 0;
+       state->xprivate = 0;
        return state;
 }
 
-static void free_extent_state(struct extent_state *state)
+static void btrfs_free_extent_state(struct extent_state *state)
 {
        state->refs--;
        BUG_ON(state->refs < 0);
@@ -59,30 +69,32 @@ static void free_extent_state(struct extent_state *state)
                free(state);
 }
 
-void extent_io_tree_cleanup(struct extent_io_tree *tree)
+static void free_extent_state_func(struct cache_extent *cache)
 {
        struct extent_state *es;
+
+       es = container_of(cache, struct extent_state, cache_node);
+       btrfs_free_extent_state(es);
+}
+
+static void free_extent_buffer_final(struct extent_buffer *eb);
+void extent_io_tree_cleanup(struct extent_io_tree *tree)
+{
        struct extent_buffer *eb;
-       struct cache_extent *cache;
 
        while(!list_empty(&tree->lru)) {
                eb = list_entry(tree->lru.next, struct extent_buffer, lru);
-               if (eb->refs != 1) {
-                       fprintf(stderr, "extent buffer leak: "
-                               "start %llu len %u\n",
+               if (eb->refs) {
+                       fprintf(stderr,
+                               "extent buffer leak: start %llu len %u\n",
                                (unsigned long long)eb->start, eb->len);
-                       eb->refs = 1;
+                       free_extent_buffer_nocache(eb);
+               } else {
+                       free_extent_buffer_final(eb);
                }
-               free_extent_buffer(eb);
-       }
-       while (1) {
-               cache = find_first_cache_extent(&tree->state, 0);
-               if (!cache)
-                       break;
-               es = container_of(cache, struct extent_state, cache_node);
-               remove_cache_extent(&tree->state, &es->cache_node);
-               free_extent_state(es);
        }
+
+       cache_tree_free_extents(&tree->state, free_extent_state_func);
 }
 
 static inline void update_extent_state(struct extent_state *state)
@@ -115,7 +127,7 @@ static int merge_state(struct extent_io_tree *tree,
                        state->start = other->start;
                        update_extent_state(state);
                        remove_cache_extent(&tree->state, &other->cache_node);
-                       free_extent_state(other);
+                       btrfs_free_extent_state(other);
                }
        }
        other_node = next_cache_extent(&state->cache_node);
@@ -127,7 +139,7 @@ static int merge_state(struct extent_io_tree *tree,
                        other->start = state->start;
                        update_extent_state(other);
                        remove_cache_extent(&tree->state, &state->cache_node);
-                       free_extent_state(state);
+                       btrfs_free_extent_state(state);
                }
        }
        return 0;
@@ -148,7 +160,7 @@ static int insert_state(struct extent_io_tree *tree,
        state->start = start;
        state->end = end;
        update_extent_state(state);
-       ret = insert_existing_cache_extent(&tree->state, &state->cache_node);
+       ret = insert_cache_extent(&tree->state, &state->cache_node);
        BUG_ON(ret);
        merge_state(tree, state);
        return 0;
@@ -169,8 +181,7 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig,
        update_extent_state(prealloc);
        orig->start = split;
        update_extent_state(orig);
-       ret = insert_existing_cache_extent(&tree->state,
-                                          &prealloc->cache_node);
+       ret = insert_cache_extent(&tree->state, &prealloc->cache_node);
        BUG_ON(ret);
        return 0;
 }
@@ -186,7 +197,7 @@ static int clear_state_bit(struct extent_io_tree *tree,
        state->state &= ~bits;
        if (state->state == 0) {
                remove_cache_extent(&tree->state, &state->cache_node);
-               free_extent_state(state);
+               btrfs_free_extent_state(state);
        } else {
                merge_state(tree, state);
        }
@@ -194,10 +205,9 @@ static int clear_state_bit(struct extent_io_tree *tree,
 }
 
 /*
- * set some bits on a range in the tree.
+ * clear some bits on a range in the tree.
  */
-int clear_extent_bits(struct extent_io_tree *tree, u64 start,
-                     u64 end, int bits, gfp_t mask)
+int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits)
 {
        struct extent_state *state;
        struct extent_state *prealloc = NULL;
@@ -207,15 +217,17 @@ int clear_extent_bits(struct extent_io_tree *tree, u64 start,
        int set = 0;
 
 again:
-       prealloc = alloc_extent_state();
-       if (!prealloc)
-               return -ENOMEM;
+       if (!prealloc) {
+               prealloc = alloc_extent_state();
+               if (!prealloc)
+                       return -ENOMEM;
+       }
 
        /*
         * this search will find the extents that end after
         * our range starts
         */
-       node = find_first_cache_extent(&tree->state, start);
+       node = search_cache_extent(&tree->state, start);
        if (!node)
                goto out;
        state = container_of(node, struct extent_state, cache_node);
@@ -277,7 +289,7 @@ again:
        goto search_again;
 out:
        if (prealloc)
-               free_extent_state(prealloc);
+               btrfs_free_extent_state(prealloc);
        return set;
 
 search_again:
@@ -289,26 +301,26 @@ search_again:
 /*
  * set some bits on a range in the tree.
  */
-int set_extent_bits(struct extent_io_tree *tree, u64 start,
-                   u64 end, int bits, gfp_t mask)
+int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits)
 {
        struct extent_state *state;
        struct extent_state *prealloc = NULL;
        struct cache_extent *node;
        int err = 0;
-       int set;
        u64 last_start;
        u64 last_end;
 again:
-       prealloc = alloc_extent_state();
-       if (!prealloc)
-               return -ENOMEM;
+       if (!prealloc) {
+               prealloc = alloc_extent_state();
+               if (!prealloc)
+                       return -ENOMEM;
+       }
 
        /*
         * this search will find the extents that end after
         * our range starts
         */
-       node = find_first_cache_extent(&tree->state, start);
+       node = search_cache_extent(&tree->state, start);
        if (!node) {
                err = insert_state(tree, prealloc, start, end, bits);
                BUG_ON(err == -EEXIST);
@@ -327,7 +339,6 @@ again:
         * Just lock what we found and keep going
         */
        if (state->start == start && state->end <= end) {
-               set = state->state & bits;
                state->state |= bits;
                merge_state(tree, state);
                if (last_end == (u64)-1)
@@ -352,7 +363,6 @@ again:
         * desired bit on it.
         */
        if (state->start < start) {
-               set = state->state & bits;
                err = split_state(tree, state, prealloc, start);
                BUG_ON(err == -EEXIST);
                prealloc = NULL;
@@ -398,7 +408,6 @@ again:
         * We need to split the extent, and set the bit
         * on the first half
         */
-       set = state->state & bits;
        err = split_state(tree, state, prealloc, end + 1);
        BUG_ON(err == -EEXIST);
 
@@ -407,7 +416,7 @@ again:
        prealloc = NULL;
 out:
        if (prealloc)
-               free_extent_state(prealloc);
+               btrfs_free_extent_state(prealloc);
        return err;
 search_again:
        if (start > end)
@@ -415,16 +424,14 @@ search_again:
        goto again;
 }
 
-int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
-                    gfp_t mask)
+int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end)
 {
-       return set_extent_bits(tree, start, end, EXTENT_DIRTY, mask);
+       return set_extent_bits(tree, start, end, EXTENT_DIRTY);
 }
 
-int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
-                      gfp_t mask)
+int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end)
 {
-       return clear_extent_bits(tree, start, end, EXTENT_DIRTY, mask);
+       return clear_extent_bits(tree, start, end, EXTENT_DIRTY);
 }
 
 int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
@@ -438,7 +445,7 @@ int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
         * this search will find all the extents that end after
         * our range starts.
         */
-       node = find_first_cache_extent(&tree->state, start);
+       node = search_cache_extent(&tree->state, start);
        if (!node)
                goto out;
 
@@ -465,7 +472,7 @@ int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
        struct cache_extent *node;
        int bitset = 0;
 
-       node = find_first_cache_extent(&tree->state, start);
+       node = search_cache_extent(&tree->state, start);
        while (node && start <= end) {
                state = container_of(node, struct extent_state, cache_node);
 
@@ -502,7 +509,7 @@ int set_state_private(struct extent_io_tree *tree, u64 start, u64 private)
        struct extent_state *state;
        int ret = 0;
 
-       node = find_first_cache_extent(&tree->state, start);
+       node = search_cache_extent(&tree->state, start);
        if (!node) {
                ret = -ENOENT;
                goto out;
@@ -512,7 +519,7 @@ int set_state_private(struct extent_io_tree *tree, u64 start, u64 private)
                ret = -ENOENT;
                goto out;
        }
-       state->private = private;
+       state->xprivate = private;
 out:
        return ret;
 }
@@ -523,7 +530,7 @@ int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private)
        struct extent_state *state;
        int ret = 0;
 
-       node = find_first_cache_extent(&tree->state, start);
+       node = search_cache_extent(&tree->state, start);
        if (!node) {
                ret = -ENOENT;
                goto out;
@@ -533,93 +540,96 @@ int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private)
                ret = -ENOENT;
                goto out;
        }
-       *private = state->private;
+       *private = state->xprivate;
 out:
        return ret;
 }
 
-static int free_some_buffers(struct extent_io_tree *tree)
-{
-       u32 nrscan = 0;
-       struct extent_buffer *eb;
-       struct list_head *node, *next;
-
-       if (tree->cache_size < cache_max)
-               return 0;
-       list_for_each_safe(node, next, &tree->lru) {
-               eb = list_entry(node, struct extent_buffer, lru);
-               if (eb->refs == 1) {
-                       free_extent_buffer(eb);
-                       if (tree->cache_size < cache_max)
-                               break;
-               } else {
-                       list_move_tail(&eb->lru, &tree->lru);
-               }
-               if (nrscan++ > 64)
-                       break;
-       }
-       return 0;
-}
-
 static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
                                                   u64 bytenr, u32 blocksize)
 {
        struct extent_buffer *eb;
-       int ret;
 
-       eb = malloc(sizeof(struct extent_buffer) + blocksize);
-       if (!eb) {
-               BUG();
+       eb = calloc(1, sizeof(struct extent_buffer) + blocksize);
+       if (!eb)
                return NULL;
-       }
 
        eb->start = bytenr;
        eb->len = blocksize;
-       eb->refs = 2;
+       eb->refs = 1;
        eb->flags = 0;
        eb->tree = tree;
        eb->fd = -1;
        eb->dev_bytenr = (u64)-1;
        eb->cache_node.start = bytenr;
        eb->cache_node.size = blocksize;
+       INIT_LIST_HEAD(&eb->recow);
+
+       return eb;
+}
+
+struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src)
+{
+       struct extent_buffer *new;
 
-       free_some_buffers(tree);
-       ret = insert_existing_cache_extent(&tree->cache, &eb->cache_node);
-       if (ret) {
-               free(eb);
+       new = __alloc_extent_buffer(NULL, src->start, src->len);
+       if (!new)
                return NULL;
+
+       copy_extent_buffer(new, src, 0, 0, src->len);
+       new->flags |= EXTENT_BUFFER_DUMMY;
+
+       return new;
+}
+
+static void free_extent_buffer_final(struct extent_buffer *eb)
+{
+       struct extent_io_tree *tree = eb->tree;
+
+       BUG_ON(eb->refs);
+       BUG_ON(tree->cache_size < eb->len);
+       list_del_init(&eb->lru);
+       if (!(eb->flags & EXTENT_BUFFER_DUMMY)) {
+               remove_cache_extent(&tree->cache, &eb->cache_node);
+               tree->cache_size -= eb->len;
        }
-       list_add_tail(&eb->lru, &tree->lru);
-       tree->cache_size += blocksize;
-       return eb;
+       free(eb);
 }
 
-void free_extent_buffer(struct extent_buffer *eb)
+static void free_extent_buffer_internal(struct extent_buffer *eb, bool free_now)
 {
-       if (!eb)
+       if (!eb || IS_ERR(eb))
                return;
 
        eb->refs--;
        BUG_ON(eb->refs < 0);
        if (eb->refs == 0) {
-               struct extent_io_tree *tree = eb->tree;
                BUG_ON(eb->flags & EXTENT_DIRTY);
-               list_del_init(&eb->lru);
-               remove_cache_extent(&tree->cache, &eb->cache_node);
-               BUG_ON(tree->cache_size < eb->len);
-               tree->cache_size -= eb->len;
-               free(eb);
+               list_del_init(&eb->recow);
+               if (eb->flags & EXTENT_BUFFER_DUMMY || free_now)
+                       free_extent_buffer_final(eb);
        }
 }
 
+void free_extent_buffer(struct extent_buffer *eb)
+{
+       free_extent_buffer_internal(eb, 0);
+}
+
+void free_extent_buffer_nocache(struct extent_buffer *eb)
+{
+       free_extent_buffer_internal(eb, 1);
+}
+
 struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
                                         u64 bytenr, u32 blocksize)
 {
        struct extent_buffer *eb = NULL;
        struct cache_extent *cache;
 
-       cache = find_cache_extent(&tree->cache, bytenr, blocksize);
-       if (cache && cache->start == bytenr && cache->size == blocksize) {
+       cache = lookup_cache_extent(&tree->cache, bytenr, blocksize);
+       if (cache && cache->start == bytenr &&
+           cache->size == blocksize) {
                eb = container_of(cache, struct extent_buffer, cache_node);
                list_move_tail(&eb->lru, &tree->lru);
                eb->refs++;
@@ -633,7 +643,7 @@ struct extent_buffer *find_first_extent_buffer(struct extent_io_tree *tree,
        struct extent_buffer *eb = NULL;
        struct cache_extent *cache;
 
-       cache = find_first_cache_extent(&tree->cache, start);
+       cache = search_cache_extent(&tree->cache, start);
        if (cache) {
                eb = container_of(cache, struct extent_buffer, cache_node);
                list_move_tail(&eb->lru, &tree->lru);
@@ -642,36 +652,64 @@ struct extent_buffer *find_first_extent_buffer(struct extent_io_tree *tree,
        return eb;
 }
 
+static void trim_extent_buffer_cache(struct extent_io_tree *tree)
+{
+       struct extent_buffer *eb, *tmp;
+
+       list_for_each_entry_safe(eb, tmp, &tree->lru, lru) {
+               if (eb->refs == 0)
+                       free_extent_buffer_final(eb);
+               if (tree->cache_size <= ((tree->max_cache_size * 9) / 10))
+                       break;
+       }
+}
+
 struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
                                          u64 bytenr, u32 blocksize)
 {
        struct extent_buffer *eb;
        struct cache_extent *cache;
 
-       cache = find_cache_extent(&tree->cache, bytenr, blocksize);
-       if (cache && cache->start == bytenr && cache->size == blocksize) {
+       cache = lookup_cache_extent(&tree->cache, bytenr, blocksize);
+       if (cache && cache->start == bytenr &&
+           cache->size == blocksize) {
                eb = container_of(cache, struct extent_buffer, cache_node);
                list_move_tail(&eb->lru, &tree->lru);
                eb->refs++;
        } else {
+               int ret;
+
                if (cache) {
                        eb = container_of(cache, struct extent_buffer,
                                          cache_node);
-                       BUG_ON(eb->refs != 1);
                        free_extent_buffer(eb);
                }
                eb = __alloc_extent_buffer(tree, bytenr, blocksize);
+               if (!eb)
+                       return NULL;
+               ret = insert_cache_extent(&tree->cache, &eb->cache_node);
+               if (ret) {
+                       free(eb);
+                       return NULL;
+               }
+               list_add_tail(&eb->lru, &tree->lru);
+               tree->cache_size += blocksize;
+               if (tree->cache_size >= tree->max_cache_size)
+                       trim_extent_buffer_cache(tree);
        }
        return eb;
 }
 
-int read_extent_from_disk(struct extent_buffer *eb)
+int read_extent_from_disk(struct extent_buffer *eb,
+                         unsigned long offset, unsigned long len)
 {
        int ret;
-       ret = pread(eb->fd, eb->data, eb->len, eb->dev_bytenr);
-       if (ret < 0)
+       ret = pread(eb->fd, eb->data + offset, len, eb->dev_bytenr);
+       if (ret < 0) {
+               ret = -errno;
                goto out;
-       if (ret != eb->len) {
+       }
+       if (ret != len) {
                ret = -EIO;
                goto out;
        }
@@ -695,24 +733,147 @@ out:
        return ret;
 }
 
-int set_extent_buffer_uptodate(struct extent_buffer *eb)
+int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 offset,
+                       u64 bytes, int mirror)
 {
-       eb->flags |= EXTENT_UPTODATE;
-       return 0;
-}
+       struct btrfs_multi_bio *multi = NULL;
+       struct btrfs_device *device;
+       u64 bytes_left = bytes;
+       u64 read_len;
+       u64 total_read = 0;
+       int ret;
+
+       while (bytes_left) {
+               read_len = bytes_left;
+               ret = btrfs_map_block(info, READ, offset, &read_len, &multi,
+                                     mirror, NULL);
+               if (ret) {
+                       fprintf(stderr, "Couldn't map the block %Lu\n",
+                               offset);
+                       return -EIO;
+               }
+               device = multi->stripes[0].dev;
+
+               read_len = min(bytes_left, read_len);
+               if (device->fd <= 0) {
+                       kfree(multi);
+                       return -EIO;
+               }
+
+               ret = pread(device->fd, buf + total_read, read_len,
+                           multi->stripes[0].physical);
+               kfree(multi);
+               if (ret < 0) {
+                       fprintf(stderr, "Error reading %Lu, %d\n", offset,
+                               ret);
+                       return ret;
+               }
+               if (ret != read_len) {
+                       fprintf(stderr, "Short read for %Lu, read %d, "
+                               "read_len %Lu\n", offset, ret, read_len);
+                       return -EIO;
+               }
+
+               bytes_left -= read_len;
+               offset += read_len;
+               total_read += read_len;
+       }
 
-int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
-                               struct extent_buffer *eb)
-{
-       eb->flags &= ~EXTENT_UPTODATE;
        return 0;
 }
 
-int extent_buffer_uptodate(struct extent_buffer *eb)
+int write_data_to_disk(struct btrfs_fs_info *info, void *buf, u64 offset,
+                     u64 bytes, int mirror)
 {
-       if (eb->flags & EXTENT_UPTODATE)
-               return 1;
+       struct btrfs_multi_bio *multi = NULL;
+       struct btrfs_device *device;
+       u64 bytes_left = bytes;
+       u64 this_len;
+       u64 total_write = 0;
+       u64 *raid_map = NULL;
+       u64 dev_bytenr;
+       int dev_nr;
+       int ret = 0;
+
+       while (bytes_left > 0) {
+               this_len = bytes_left;
+               dev_nr = 0;
+
+               ret = btrfs_map_block(info, WRITE, offset, &this_len, &multi,
+                                     mirror, &raid_map);
+               if (ret) {
+                       fprintf(stderr, "Couldn't map the block %Lu\n",
+                               offset);
+                       return -EIO;
+               }
+
+               if (raid_map) {
+                       struct extent_buffer *eb;
+                       u64 stripe_len = this_len;
+
+                       this_len = min(this_len, bytes_left);
+                       this_len = min(this_len, (u64)info->nodesize);
+
+                       eb = malloc(sizeof(struct extent_buffer) + this_len);
+                       if (!eb) {
+                               fprintf(stderr, "cannot allocate memory for eb\n");
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+
+                       memset(eb, 0, sizeof(struct extent_buffer) + this_len);
+                       eb->start = offset;
+                       eb->len = this_len;
+
+                       memcpy(eb->data, buf + total_write, this_len);
+                       ret = write_raid56_with_parity(info, eb, multi,
+                                                      stripe_len, raid_map);
+                       BUG_ON(ret);
+
+                       free(eb);
+                       kfree(raid_map);
+                       raid_map = NULL;
+               } else while (dev_nr < multi->num_stripes) {
+                       device = multi->stripes[dev_nr].dev;
+                       if (device->fd <= 0) {
+                               kfree(multi);
+                               return -EIO;
+                       }
+
+                       dev_bytenr = multi->stripes[dev_nr].physical;
+                       this_len = min(this_len, bytes_left);
+                       dev_nr++;
+
+                       ret = pwrite(device->fd, buf + total_write, this_len, dev_bytenr);
+                       if (ret != this_len) {
+                               if (ret < 0) {
+                                       fprintf(stderr, "Error writing to "
+                                               "device %d\n", errno);
+                                       ret = errno;
+                                       kfree(multi);
+                                       return ret;
+                               } else {
+                                       fprintf(stderr, "Short write\n");
+                                       kfree(multi);
+                                       return -EIO;
+                               }
+                       }
+               }
+
+               BUG_ON(bytes_left < this_len);
+
+               bytes_left -= this_len;
+               offset += this_len;
+               total_write += this_len;
+
+               kfree(multi);
+               multi = NULL;
+       }
        return 0;
+
+out:
+       kfree(raid_map);
+       return ret;
 }
 
 int set_extent_buffer_dirty(struct extent_buffer *eb)
@@ -720,7 +881,7 @@ int set_extent_buffer_dirty(struct extent_buffer *eb)
        struct extent_io_tree *tree = eb->tree;
        if (!(eb->flags & EXTENT_DIRTY)) {
                eb->flags |= EXTENT_DIRTY;
-               set_extent_dirty(tree, eb->start, eb->start + eb->len - 1, 0);
+               set_extent_dirty(tree, eb->start, eb->start + eb->len - 1);
                extent_buffer_get(eb);
        }
        return 0;
@@ -731,7 +892,7 @@ int clear_extent_buffer_dirty(struct extent_buffer *eb)
        struct extent_io_tree *tree = eb->tree;
        if (eb->flags & EXTENT_DIRTY) {
                eb->flags &= ~EXTENT_DIRTY;
-               clear_extent_dirty(tree, eb->start, eb->start + eb->len - 1, 0);
+               clear_extent_dirty(tree, eb->start, eb->start + eb->len - 1);
                free_extent_buffer(eb);
        }
        return 0;
@@ -762,12 +923,6 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
        memcpy(dst->data + dst_offset, src->data + src_offset, len);
 }
 
-void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
-                         unsigned long src_offset, unsigned long len)
-{
-       memcpy(dst->data + dst_offset, dst->data + src_offset, len);
-}
-
 void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
                           unsigned long src_offset, unsigned long len)
 {
@@ -779,3 +934,9 @@ void memset_extent_buffer(struct extent_buffer *eb, char c,
 {
        memset(eb->data + start, c, len);
 }
+
+int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start,
+                          unsigned long nr)
+{
+       return le_test_bit(nr, (u8 *)eb->data + start);
+}