summaryrefslogtreecommitdiff
path: root/fs/btrfs/backref.c
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2015-10-02 11:15:13 -0700
committerStephen Boyd <sboyd@codeaurora.org>2015-10-02 11:22:23 -0700
commit9f30a04d768f64280dc0c40b730746e82f298d88 (patch)
treee112853eb73627ed7b9a2ef8e4feab6685a0200e /fs/btrfs/backref.c
parent9e294bf88a583825a413df408b9fe9e658fb93ac (diff)
parent7aba4f5201d1b7b3ddb0b03883d9edf69851ddad (diff)
Merge branch 'for-4.3-rc/ti-clk-fixes' of https://github.com/t-kristo/linux-pm into clk-fixes
Pull fixes from Tero Kristo: "A few TI clock driver fixes to pull against 4.3-rc" * 'for-4.3-rc/ti-clk-fixes' of https://github.com/t-kristo/linux-pm: (3 commits) clk: ti: dflt: fix enable_reg validity check clk: ti: fix dual-registration of uart4_ick clk: ti: clk-7xx: Remove hardwired ABE clock configuration
Diffstat (limited to 'fs/btrfs/backref.c')
-rw-r--r--fs/btrfs/backref.c35
1 files changed, 27 insertions, 8 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 802fabb30e157..ecbc63d3143e7 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -206,10 +206,33 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
return -ENOMEM;
ref->root_id = root_id;
- if (key)
+ if (key) {
ref->key_for_search = *key;
- else
+ /*
+ * We can often find data backrefs with an offset that is too
+ * large (>= LLONG_MAX, maximum allowed file offset) due to
+ * underflows when subtracting a file's offset with the data
+ * offset of its corresponding extent data item. This can
+ * happen for example in the clone ioctl.
+ * So if we detect such case we set the search key's offset to
+ * zero to make sure we will find the matching file extent item
+ * at add_all_parents(), otherwise we will miss it because the
+ * offset taken form the backref is much larger then the offset
+ * of the file extent item. This can make us scan a very large
+ * number of file extent items, but at least it will not make
+ * us miss any.
+ * This is an ugly workaround for a behaviour that should have
+ * never existed, but it does and a fix for the clone ioctl
+ * would touch a lot of places, cause backwards incompatibility
+ * and would not fix the problem for extents cloned with older
+ * kernels.
+ */
+ if (ref->key_for_search.type == BTRFS_EXTENT_DATA_KEY &&
+ ref->key_for_search.offset >= LLONG_MAX)
+ ref->key_for_search.offset = 0;
+ } else {
memset(&ref->key_for_search, 0, sizeof(ref->key_for_search));
+ }
ref->inode_list = NULL;
ref->level = level;
@@ -632,7 +655,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
struct btrfs_delayed_tree_ref *ref;
ref = btrfs_delayed_node_to_tree_ref(node);
- ret = __add_prelim_ref(prefs, ref->root, NULL,
+ ret = __add_prelim_ref(prefs, 0, NULL,
ref->level + 1, ref->parent,
node->bytenr,
node->ref_mod * sgn, GFP_ATOMIC);
@@ -664,11 +687,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
struct btrfs_delayed_data_ref *ref;
ref = btrfs_delayed_node_to_data_ref(node);
-
- key.objectid = ref->objectid;
- key.type = BTRFS_EXTENT_DATA_KEY;
- key.offset = ref->offset;
- ret = __add_prelim_ref(prefs, ref->root, &key, 0,
+ ret = __add_prelim_ref(prefs, 0, NULL, 0,
ref->parent, node->bytenr,
node->ref_mod * sgn, GFP_ATOMIC);
break;