btrfs-progs: fi usage: add support for RAID5/6

The function print_filesystem_usage_overall() prints the info on the
basis of the r_*_chunk, r_*_used and l_*_chunks values computed for
data, metadata and system chunks.

For the RAID1/10/1C3/1C4/DUP these info are easily accessible from the
info returned by load_space_info().

However for RAID5/6 this is not true because the ratios between the l_*
and r_* values are not fixed but depend by the number of devices
involved in the chunk.

A new function called get_raid56_space_info() is created to compute
the values r_*_chunk, and r_*_used for data, metadata and system
chunks in case of a RAID5/6 profile.

The r_*_chunk values are computed from the chunk_info array.

In order to compute the r_*_used values, a new function
get_raid56_logical_ratio() is created. This function computes the ratio
l_*_used / l_*_chunk from the ioctl_space_args array.  So we can get:

	'r_*_used' = 'r_*_chunk' * 'l_*_used' / 'l_*_chunk'

Even tough this is not mathematically true every time, it is true on
"average" (for example if the RAID5 chunks use different number of disks
the real values depend by which chunk contains the data).

Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Goffredo Baroncelli 2020-05-27 22:37:48 +02:00 committed by David Sterba
parent 5ba0f70c60
commit cf15c0eb0e

View file

@ -282,24 +282,113 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, const char *path)
}
/*
* This function computes the space occupied by a *single* RAID5/RAID6 chunk.
* The computation is performed on the basis of the number of stripes
* which compose the chunk, which could be different from the number of devices
* if a disk is added later.
* Compute the ratio between logical space used over logical space allocated
* by profile basis
*/
static void get_raid56_used(struct chunk_info *chunks, int chunkcount,
u64 *raid5_used, u64 *raid6_used)
static void get_raid56_logical_ratio(struct btrfs_ioctl_space_args *sargs,
u64 type, double *data_ratio,
double *metadata_ratio,
double *system_ratio)
{
struct chunk_info *info_ptr = chunks;
*raid5_used = 0;
*raid6_used = 0;
u64 l_data_chunk = 0, l_data_used = 0;
u64 l_metadata_chunk = 0, l_metadata_used = 0;
u64 l_system_chunk = 0, l_system_used = 0;
int i;
while (chunkcount-- > 0) {
if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID5)
(*raid5_used) += info_ptr->size / (info_ptr->num_stripes - 1);
if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID6)
(*raid6_used) += info_ptr->size / (info_ptr->num_stripes - 2);
info_ptr++;
for (i = 0; i < sargs->total_spaces; i++) {
u64 flags = sargs->spaces[i].flags;
if (!(flags & type))
continue;
if (flags & BTRFS_BLOCK_GROUP_DATA) {
l_data_used += sargs->spaces[i].used_bytes;
l_data_chunk += sargs->spaces[i].total_bytes;
} else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
l_metadata_used += sargs->spaces[i].used_bytes;
l_metadata_chunk += sargs->spaces[i].total_bytes;
} else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
l_system_used += sargs->spaces[i].used_bytes;
l_system_chunk += sargs->spaces[i].total_bytes;
}
}
*data_ratio = -1.0;
*metadata_ratio = -1.0;
*system_ratio = -1.0;
if (l_data_chunk)
*data_ratio = (double)l_data_used / l_data_chunk;
if (l_metadata_chunk)
*metadata_ratio = (double)l_metadata_used / l_metadata_chunk;
if (l_system_chunk)
*system_ratio = (double)l_system_used / l_system_chunk;
}
/*
* Compute the "raw" space allocated for a chunk (r_*_chunks)
* and the "raw" space used by a chunk (r_*_used)
*/
static void get_raid56_space_info(struct btrfs_ioctl_space_args *sargs,
struct chunk_info *chunks, int chunkcount,
double *max_data_ratio,
u64 *r_data_chunks, u64 *r_data_used,
u64 *r_metadata_chunks, u64 *r_metadata_used,
u64 *r_system_chunks, u64 *r_system_used)
{
struct chunk_info *info_ptr;
double l_data_ratio_r5, l_metadata_ratio_r5, l_system_ratio_r5;
double l_data_ratio_r6, l_metadata_ratio_r6, l_system_ratio_r6;
get_raid56_logical_ratio(sargs, BTRFS_BLOCK_GROUP_RAID5,
&l_data_ratio_r5, &l_metadata_ratio_r5, &l_system_ratio_r5);
get_raid56_logical_ratio(sargs, BTRFS_BLOCK_GROUP_RAID6,
&l_data_ratio_r6, &l_metadata_ratio_r6, &l_system_ratio_r6);
for(info_ptr = chunks; chunkcount > 0; chunkcount--, info_ptr++) {
int parities_count;
u64 size;
double l_data_ratio, l_metadata_ratio, l_system_ratio, rt;
if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID5) {
parities_count = 1;
l_data_ratio = l_data_ratio_r5;
l_metadata_ratio = l_metadata_ratio_r5;
l_system_ratio = l_system_ratio_r5;
} else if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID6) {
parities_count = 2;
l_data_ratio = l_data_ratio_r6;
l_metadata_ratio = l_metadata_ratio_r6;
l_system_ratio = l_system_ratio_r6;
} else {
continue;
}
rt = (double)info_ptr->num_stripes /
(info_ptr->num_stripes - parities_count);
if (rt > *max_data_ratio)
*max_data_ratio = rt;
/*
* size is the total disk(s) space occuped by a chunk
* the product of 'size' and '*_ratio' is "in average"
* the disk(s) space used by the data
*/
size = info_ptr->size / (info_ptr->num_stripes - parities_count);
if (info_ptr->type & BTRFS_BLOCK_GROUP_DATA) {
assert(l_data_ratio >= 0);
*r_data_chunks += size;
*r_data_used += size * l_data_ratio;
} else if (info_ptr->type & BTRFS_BLOCK_GROUP_METADATA) {
assert(l_metadata_ratio >= 0);
*r_metadata_chunks += size;
*r_metadata_used += size * l_metadata_ratio;
} else if (info_ptr->type & BTRFS_BLOCK_GROUP_SYSTEM) {
assert(l_system_ratio >= 0);
*r_system_chunks += size;
*r_system_used += size * l_system_ratio;
}
}
}
@ -315,7 +404,9 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo,
int width = 10; /* default 10 for human units */
/*
* r_* prefix is for raw data
* l_* is for logical
* l_* prefix is for logical
* *_used suffix is for space used for data or metadata
* *_chunks suffix is for total space used by the chunk
*/
u64 r_total_size = 0; /* filesystem size, sum of device sizes */
u64 r_total_chunks = 0; /* sum of chunks sizes on disk(s) */
@ -333,13 +424,11 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo,
double data_ratio;
double metadata_ratio;
/* logical */
u64 raid5_used = 0;
u64 raid6_used = 0;
u64 l_global_reserve = 0;
u64 l_global_reserve_used = 0;
u64 free_estimated = 0;
u64 free_min = 0;
int max_data_ratio = 1;
double max_data_ratio = 1.0;
int mixed = 0;
sargs = load_space_info(fd, path);
@ -361,15 +450,20 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo,
ret = 1;
goto exit;
}
get_raid56_used(chunkinfo, chunkcount, &raid5_used, &raid6_used);
get_raid56_space_info(sargs, chunkinfo, chunkcount, &max_data_ratio,
&r_data_chunks, &r_data_used,
&r_metadata_chunks, &r_metadata_used,
&r_system_chunks, &r_system_used);
for (i = 0; i < sargs->total_spaces; i++) {
int ratio;
u64 flags = sargs->spaces[i].flags;
/*
* The raid5/raid6 ratio depends by the stripes number
* used by every chunk. It is computed separately
* The RAID5/6 ratio depends on the number of stripes and is
* computed separately. Setting ratio to 0 will not account
* the chunks in this loop.
*/
if (flags & BTRFS_BLOCK_GROUP_RAID0)
ratio = 1;
@ -390,9 +484,6 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo,
else
ratio = 1;
if (!ratio)
warning("RAID56 detected, not implemented");
if (ratio > max_data_ratio)
max_data_ratio = ratio;
@ -435,11 +526,6 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo,
else
metadata_ratio = (double)r_metadata_chunks / l_metadata_chunks;
#if 0
/* add the raid5/6 allocated space */
total_chunks += raid5_used + raid6_used;
#endif
/*
* We're able to fill at least DATA for the unused space
*