Clarify error message when a range-tree double-add occurs
In various other pieces of logic have resulted in situations where we double-free space in ZFS. This in turn results in a double-add to the range trees. These issues have been much more difficult to diagnose than they should have been, because the error handling around this case is much weaker than around the double remove case. Reviewed-by: Matt Ahrens <matt@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: George Wilson <gwilson@delphix.com> Signed-off-by: Paul Dagnelie <pcd@delphix.com> Closes #10654
This commit is contained in:
parent
d4e6e9597d
commit
12045d0278
|
@ -251,9 +251,19 @@ range_tree_destroy(range_tree_t *rt)
|
||||||
void
|
void
|
||||||
range_tree_adjust_fill(range_tree_t *rt, range_seg_t *rs, int64_t delta)
|
range_tree_adjust_fill(range_tree_t *rt, range_seg_t *rs, int64_t delta)
|
||||||
{
|
{
|
||||||
ASSERT3U(rs_get_fill(rs, rt) + delta, !=, 0);
|
if (delta < 0 && delta * -1 >= rs_get_fill(rs, rt)) {
|
||||||
ASSERT3U(rs_get_fill(rs, rt) + delta, <=, rs_get_end(rs, rt) -
|
zfs_panic_recover("zfs: attempting to decrease fill to or "
|
||||||
rs_get_start(rs, rt));
|
"below 0; probable double remove in segment [%llx:%llx]",
|
||||||
|
(longlong_t)rs_get_start(rs, rt),
|
||||||
|
(longlong_t)rs_get_end(rs, rt));
|
||||||
|
}
|
||||||
|
if (rs_get_fill(rs, rt) + delta > rs_get_end(rs, rt) -
|
||||||
|
rs_get_start(rs, rt)) {
|
||||||
|
zfs_panic_recover("zfs: attempting to increase fill beyond "
|
||||||
|
"max; probable double add in segment [%llx:%llx]",
|
||||||
|
(longlong_t)rs_get_start(rs, rt),
|
||||||
|
(longlong_t)rs_get_end(rs, rt));
|
||||||
|
}
|
||||||
|
|
||||||
if (rt->rt_ops != NULL && rt->rt_ops->rtop_remove != NULL)
|
if (rt->rt_ops != NULL && rt->rt_ops->rtop_remove != NULL)
|
||||||
rt->rt_ops->rtop_remove(rt, rs, rt->rt_arg);
|
rt->rt_ops->rtop_remove(rt, rs, rt->rt_arg);
|
||||||
|
@ -290,10 +300,14 @@ range_tree_add_impl(void *arg, uint64_t start, uint64_t size, uint64_t fill)
|
||||||
* the normal code paths.
|
* the normal code paths.
|
||||||
*/
|
*/
|
||||||
if (rs != NULL) {
|
if (rs != NULL) {
|
||||||
ASSERT3U(rt->rt_gap, !=, 0);
|
if (gap == 0) {
|
||||||
|
zfs_panic_recover("zfs: adding existent segment to "
|
||||||
|
"range tree (offset=%llx size=%llx)",
|
||||||
|
(longlong_t)start, (longlong_t)size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
uint64_t rstart = rs_get_start(rs, rt);
|
uint64_t rstart = rs_get_start(rs, rt);
|
||||||
uint64_t rend = rs_get_end(rs, rt);
|
uint64_t rend = rs_get_end(rs, rt);
|
||||||
ASSERT3U(gap, !=, 0);
|
|
||||||
if (rstart <= start && rend >= end) {
|
if (rstart <= start && rend >= end) {
|
||||||
range_tree_adjust_fill(rt, rs, fill);
|
range_tree_adjust_fill(rt, rs, fill);
|
||||||
return;
|
return;
|
||||||
|
@ -431,7 +445,7 @@ range_tree_remove_impl(range_tree_t *rt, uint64_t start, uint64_t size,
|
||||||
/* Make sure we completely overlap with someone */
|
/* Make sure we completely overlap with someone */
|
||||||
if (rs == NULL) {
|
if (rs == NULL) {
|
||||||
zfs_panic_recover("zfs: removing nonexistent segment from "
|
zfs_panic_recover("zfs: removing nonexistent segment from "
|
||||||
"range tree (offset=%llu size=%llu)",
|
"range tree (offset=%llx size=%llx)",
|
||||||
(longlong_t)start, (longlong_t)size);
|
(longlong_t)start, (longlong_t)size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -455,8 +469,8 @@ range_tree_remove_impl(range_tree_t *rt, uint64_t start, uint64_t size,
|
||||||
} else if (rs_get_start(rs, rt) != start ||
|
} else if (rs_get_start(rs, rt) != start ||
|
||||||
rs_get_end(rs, rt) != end) {
|
rs_get_end(rs, rt) != end) {
|
||||||
zfs_panic_recover("zfs: freeing partial segment of "
|
zfs_panic_recover("zfs: freeing partial segment of "
|
||||||
"gap tree (offset=%llu size=%llu) of "
|
"gap tree (offset=%llx size=%llx) of "
|
||||||
"(offset=%llu size=%llu)",
|
"(offset=%llx size=%llx)",
|
||||||
(longlong_t)start, (longlong_t)size,
|
(longlong_t)start, (longlong_t)size,
|
||||||
(longlong_t)rs_get_start(rs, rt),
|
(longlong_t)rs_get_start(rs, rt),
|
||||||
(longlong_t)rs_get_end(rs, rt) - rs_get_start(rs,
|
(longlong_t)rs_get_end(rs, rt) - rs_get_start(rs,
|
||||||
|
|
Loading…
Reference in New Issue