blob: 1e69693c3d54a07858f6cd188d0a556f28471aa7 [file] [log] [blame]
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2019 Nikolay Borisov, SUSE LLC. All Rights Reserved.
#
# Parses btrfs' extent tree for holes. Holes are the ranges between 2 adjacent
# extent blocks. For example if we have the following 2 metadata items in the
# extent tree:
# item 6 key (30425088 METADATA_ITEM 0) itemoff 16019 itemsize 33
# item 7 key (30490624 METADATA_ITEM 0) itemoff 15986 itemsize 33
#
# There is a whole of 64k between then - 30490624−30425088 = 65536
# Same logic applies for adjacent EXTENT_ITEMS.
#
# The script requires the following parameters passed on command line:
# * sectorsize - how many bytes per sector, used to convert the output of
# the script to sectors.
# * nodesize - size of metadata extents, used for internal calculations
# Given an extent line "item 2 key (13672448 EXTENT_ITEM 65536) itemoff 16153 itemsize 53"
# or "item 6 key (30425088 METADATA_ITEM 0) itemoff 16019 itemsize 33" returns
# either 65536 (for data extents) or the fixes nodesize value for metadata
# extents.
function get_extent_size(line, tmp) {
if (line ~ data_match || line ~ bg_match) {
split(line, tmp)
gsub(/\)/,"", tmp[6])
return tmp[6]
} else if (line ~ metadata_match) {
return nodesize
}
}
# given a 'item 2 key (13672448 EXTENT_ITEM 65536) itemoff 16153 itemsize 53'
# and returns 13672448.
function get_extent_offset(line, tmp) {
split(line, tmp)
gsub(/\(/,"",tmp[4])
return tmp[4]
}
# This function parses all the extents belonging to a particular block group
# which are accumulated in lines[] and calculates the offsets of the holes
# part of this block group.
#
# base_offset and bg_line are local variables
function print_array(base_offset, bg_line)
{
if (match(lines[0], bg_match)) {
# we don't have an extent at the beginning of of blockgroup, so we
# have a hole between blockgroup offset and first extent offset
bg_line = lines[0]
prev_size=0
prev_offset=get_extent_offset(bg_line)
delete lines[0]
} else {
# we have an extent at the beginning of block group, so initialize
# the prev_* vars correctly
bg_line = lines[1]
prev_size = get_extent_size(lines[0])
prev_offset = get_extent_offset(lines[0])
delete lines[1]
delete lines[0]
}
bg_offset=get_extent_offset(bg_line)
bgend=bg_offset + get_extent_size(bg_line)
for (i in lines) {
cur_size = get_extent_size(lines[i])
cur_offset = get_extent_offset(lines[i])
if (cur_offset != prev_offset + prev_size)
print int((prev_size + prev_offset) / sectorsize), int((cur_offset-1) / sectorsize)
prev_size = cur_size
prev_offset = cur_offset
}
print int((prev_size + prev_offset) / sectorsize), int((bgend-1) / sectorsize)
total_printed++
delete lines
}
BEGIN {
loi_match="^.item [0-9]* key \\([0-9]* (BLOCK_GROUP_ITEM|METADATA_ITEM|EXTENT_ITEM) [0-9]*\\).*"
metadata_match="^.item [0-9]* key \\([0-9]* METADATA_ITEM [0-9]*\\).*"
data_match="^.item [0-9]* key \\([0-9]* EXTENT_ITEM [0-9]*\\).*"
bg_match="^.item [0-9]* key \\([0-9]* BLOCK_GROUP_ITEM [0-9]*\\).*"
node_match="^node.*$"
leaf_match="^leaf [0-9]* flags"
line_count=0
total_printed=0
skip_lines=0
}
{
# skip lines not belonging to a leaf
if (match($0, node_match)) {
skip_lines=1
} else if (match($0, leaf_match)) {
skip_lines=0
}
if (!match($0, loi_match) || skip_lines == 1) next;
# we have a line of interest, we need to parse it. First check if there is
# anything in the array
if (line_count==0) {
lines[line_count++]=$0;
} else {
prev_line=lines[line_count-1]
split(prev_line, prev_line_fields)
prev_objectid=prev_line_fields[4]
objectid=$4
if (objectid == prev_objectid && match($0, bg_match)) {
if (total_printed>0) {
# We are adding a BG after we have added its first extent
# previously, consider this a record ending event and just print
# the array
delete lines[line_count-1]
print_array()
# we now start a new array with current and previous lines
line_count=0
lines[line_count++]=prev_line
lines[line_count++]=$0
} else {
# first 2 added lines are EXTENT and BG that match, in this case
# just add them
lines[line_count++]=$0
}
} else if (match($0, bg_match)) {
# ordinary end of record
print_array()
line_count=0
lines[line_count++]=$0
} else {
lines[line_count++]=$0
}
}
}
END {
print_array()
}