summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ctree.c24
-rw-r--r--ctree.h2
-rw-r--r--extent-tree.c63
3 files changed, 89 insertions, 0 deletions
diff --git a/ctree.c b/ctree.c
index 6875bb48..a98ad185 100644
--- a/ctree.c
+++ b/ctree.c
@@ -2951,3 +2951,27 @@ int btrfs_previous_extent_item(struct btrfs_root *root,
}
return 1;
}
+
+/*
+ * Search in extent tree to found next meta/data extent
+ * Caller needs to check for no-hole or skinny metadata features.
+ */
+int btrfs_next_extent_item(struct btrfs_root *root,
+ struct btrfs_path *path, u64 max_objectid)
+{
+ struct btrfs_key found_key;
+ int ret;
+
+ while (1) {
+ ret = btrfs_next_item(root, path);
+ if (ret)
+ return ret;
+ btrfs_item_key_to_cpu(path->nodes[0], &found_key,
+ path->slots[0]);
+ if (found_key.objectid > max_objectid)
+ return 1;
+ if (found_key.type == BTRFS_EXTENT_ITEM_KEY ||
+ found_key.type == BTRFS_METADATA_ITEM_KEY)
+ return 0;
+ }
+}
diff --git a/ctree.h b/ctree.h
index 6943e508..6dfd5113 100644
--- a/ctree.h
+++ b/ctree.h
@@ -2388,6 +2388,8 @@ int btrfs_previous_item(struct btrfs_root *root,
int type);
int btrfs_previous_extent_item(struct btrfs_root *root,
struct btrfs_path *path, u64 min_objectid);
+int btrfs_next_extent_item(struct btrfs_root *root,
+ struct btrfs_path *path, u64 max_objectid);
int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot,
diff --git a/extent-tree.c b/extent-tree.c
index 4a41717e..6ccd4245 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -3909,6 +3909,69 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
return 0;
}
+static void __get_extent_size(struct btrfs_root *root, struct btrfs_path *path,
+ u64 *start, u64 *len)
+{
+ struct btrfs_key key;
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ BUG_ON(!(key.type == BTRFS_EXTENT_ITEM_KEY ||
+ key.type == BTRFS_METADATA_ITEM_KEY));
+ *start = key.objectid;
+ if (key.type == BTRFS_EXTENT_ITEM_KEY)
+ *len = key.offset;
+ else
+ *len = root->nodesize;
+}
+
+/*
+ * Find first overlap extent for range [bytenr, bytenr + len)
+ * Return 0 for found and point path to it.
+ * Return >0 for not found.
+ * Return <0 for err
+ */
+int btrfs_search_overlap_extent(struct btrfs_root *root,
+ struct btrfs_path *path, u64 bytenr, u64 len)
+{
+ struct btrfs_key key;
+ u64 cur_start;
+ u64 cur_len;
+ int ret;
+
+ key.objectid = bytenr;
+ key.type = BTRFS_EXTENT_DATA_KEY;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+ BUG_ON(ret == 0);
+
+ ret = btrfs_previous_extent_item(root, path, 0);
+ if (ret < 0)
+ return ret;
+ /* no previous, check next extent */
+ if (ret > 0)
+ goto next;
+ __get_extent_size(root, path, &cur_start, &cur_len);
+ /* Tail overlap */
+ if (cur_start + cur_len > bytenr)
+ return 1;
+
+next:
+ ret = btrfs_next_extent_item(root, path, bytenr + len);
+ if (ret < 0)
+ return ret;
+ /* No next, prev already checked, no overlap */
+ if (ret > 0)
+ return 0;
+ __get_extent_size(root, path, &cur_start, &cur_len);
+ /* head overlap*/
+ if (cur_start < bytenr + len)
+ return 1;
+ return 0;
+}
+
/*
* Record a file extent. Do all the required works, such as inserting
* file extent item, inserting extent item and backref item into extent