btrfs-progs: convert chunk info to struct array

Use the struct array for passing around the chunk info instead of the
pointer and size.

Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
David Sterba 2023-07-17 03:23:05 +02:00
parent 05d338d4ab
commit 0fdfcddac4
3 changed files with 96 additions and 107 deletions

View File

@ -836,27 +836,25 @@ static int _cmd_device_usage(int fd, const char *path, unsigned unit_mode)
{ {
int i; int i;
int ret = 0; int ret = 0;
struct chunk_info *chunkinfo = NULL; struct array chunkinfos = { 0 };
struct device_info *devinfo = NULL; struct device_info *devinfo = NULL;
int chunkcount = 0;
int devcount = 0; int devcount = 0;
ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, &devinfo, ret = load_chunk_and_device_info(fd, &chunkinfos, &devinfo, &devcount);
&devcount);
if (ret) if (ret)
goto out; goto out;
for (i = 0; i < devcount; i++) { for (i = 0; i < devcount; i++) {
pr_verbose(LOG_DEFAULT, "%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid); pr_verbose(LOG_DEFAULT, "%s, ID: %llu\n", devinfo[i].path, devinfo[i].devid);
print_device_sizes(&devinfo[i], unit_mode); print_device_sizes(&devinfo[i], unit_mode);
print_device_chunks(&devinfo[i], chunkinfo, chunkcount, print_device_chunks(&devinfo[i], &chunkinfos, unit_mode);
unit_mode);
pr_verbose(LOG_DEFAULT, "\n"); pr_verbose(LOG_DEFAULT, "\n");
} }
out: out:
free(devinfo); free(devinfo);
free(chunkinfo); array_free_elements(&chunkinfos);
array_free(&chunkinfos);
return ret; return ret;
} }

View File

@ -50,9 +50,7 @@
/* /*
* Add the chunk info to the chunk_info list * Add the chunk info to the chunk_info list
*/ */
static int add_info_to_list(struct chunk_info **chunkinfo_ret, static int add_info_to_list(struct array *chunkinfos, struct btrfs_chunk *chunk)
int *info_count,
struct btrfs_chunk *chunk)
{ {
u64 type = btrfs_stack_chunk_type(chunk); u64 type = btrfs_stack_chunk_type(chunk);
@ -69,32 +67,35 @@ static int add_info_to_list(struct chunk_info **chunkinfo_ret,
stripe = btrfs_stripe_nr(chunk, j); stripe = btrfs_stripe_nr(chunk, j);
devid = btrfs_stack_stripe_devid(stripe); devid = btrfs_stack_stripe_devid(stripe);
for (i = 0 ; i < *info_count ; i++) for (i = 0; i < chunkinfos->length; i++) {
if ((*chunkinfo_ret)[i].type == type && struct chunk_info *cinfo = chunkinfos->data[i];
(*chunkinfo_ret)[i].devid == devid &&
(*chunkinfo_ret)[i].num_stripes == num_stripes ) { if (cinfo->type == type &&
p = (*chunkinfo_ret) + i; cinfo->devid == devid &&
cinfo->num_stripes == num_stripes ) {
p = cinfo;
break; break;
} }
}
if (!p) { if (!p) {
int tmp = sizeof(struct btrfs_chunk) * (*info_count + 1); int ret;
struct chunk_info *res = realloc(*chunkinfo_ret, tmp);
if (!res) { p = calloc(1, sizeof(struct chunk_info));
free(*chunkinfo_ret); if (!p) {
error_msg(ERROR_MSG_MEMORY, NULL); error_msg(ERROR_MSG_MEMORY, NULL);
return -ENOMEM; return -ENOMEM;
} }
*chunkinfo_ret = res;
p = res + *info_count;
(*info_count)++;
p->devid = devid; p->devid = devid;
p->type = type; p->type = type;
p->size = 0; p->size = 0;
p->num_stripes = num_stripes; p->num_stripes = num_stripes;
ret = array_append(chunkinfos, p);
if (ret < 0) {
error_msg(ERROR_MSG_MEMORY, NULL);
return -ENOMEM;
}
} }
p->size += size; p->size += size;
@ -109,7 +110,6 @@ static int add_info_to_list(struct chunk_info **chunkinfo_ret,
*/ */
static int cmp_chunk_block_group(u64 f1, u64 f2) static int cmp_chunk_block_group(u64 f1, u64 f2)
{ {
u64 mask; u64 mask;
if ((f1 & BTRFS_BLOCK_GROUP_TYPE_MASK) == if ((f1 & BTRFS_BLOCK_GROUP_TYPE_MASK) ==
@ -135,13 +135,13 @@ static int cmp_chunk_block_group(u64 f1, u64 f2)
*/ */
static int cmp_chunk_info(const void *a, const void *b) static int cmp_chunk_info(const void *a, const void *b)
{ {
return cmp_chunk_block_group( const struct chunk_info * const *pa = a;
((struct chunk_info *)a)->type, const struct chunk_info * const *pb = b;
((struct chunk_info *)b)->type);
return cmp_chunk_block_group((*pa)->type, (*pb)->type);
} }
static int load_chunk_info(int fd, struct chunk_info **chunkinfo_ret, static int load_chunk_info(int fd, struct array *chunkinfos)
int *chunkcount_ret)
{ {
int ret; int ret;
struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_args args;
@ -191,11 +191,9 @@ static int load_chunk_info(int fd, struct chunk_info **chunkinfo_ret,
off += sizeof(*sh); off += sizeof(*sh);
item = (struct btrfs_chunk *)(args.buf + off); item = (struct btrfs_chunk *)(args.buf + off);
ret = add_info_to_list(chunkinfo_ret, chunkcount_ret, item); ret = add_info_to_list(chunkinfos, item);
if (ret) { if (ret)
*chunkinfo_ret = NULL;
return 1; return 1;
}
off += btrfs_search_header_len(sh); off += btrfs_search_header_len(sh);
@ -218,7 +216,7 @@ static int load_chunk_info(int fd, struct chunk_info **chunkinfo_ret,
break; break;
} }
qsort(*chunkinfo_ret, *chunkcount_ret, sizeof(struct chunk_info), qsort(chunkinfos->data, chunkinfos->length, sizeof(struct chunk_info *),
cmp_chunk_info); cmp_chunk_info);
return 0; return 0;
@ -339,13 +337,12 @@ static void get_raid56_logical_ratio(struct btrfs_ioctl_space_args *sargs,
* and the "raw" space used by a chunk (r_*_used) * and the "raw" space used by a chunk (r_*_used)
*/ */
static void get_raid56_space_info(struct btrfs_ioctl_space_args *sargs, static void get_raid56_space_info(struct btrfs_ioctl_space_args *sargs,
struct chunk_info *chunkinfo, int chunkcount, const struct array *chunkinfos,
double *max_data_ratio, double *max_data_ratio,
u64 *r_data_chunks, u64 *r_data_used, u64 *r_data_chunks, u64 *r_data_used,
u64 *r_metadata_chunks, u64 *r_metadata_used, u64 *r_metadata_chunks, u64 *r_metadata_used,
u64 *r_system_chunks, u64 *r_system_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_r5, l_metadata_ratio_r5, l_system_ratio_r5;
double l_data_ratio_r6, l_metadata_ratio_r6, l_system_ratio_r6; double l_data_ratio_r6, l_metadata_ratio_r6, l_system_ratio_r6;
@ -354,7 +351,8 @@ static void get_raid56_space_info(struct btrfs_ioctl_space_args *sargs,
get_raid56_logical_ratio(sargs, BTRFS_BLOCK_GROUP_RAID6, get_raid56_logical_ratio(sargs, BTRFS_BLOCK_GROUP_RAID6,
&l_data_ratio_r6, &l_metadata_ratio_r6, &l_system_ratio_r6); &l_data_ratio_r6, &l_metadata_ratio_r6, &l_system_ratio_r6);
for(info_ptr = chunkinfo; chunkcount > 0; chunkcount--, info_ptr++) { for (int i = 0; i < chunkinfos->length; i++) {
const struct chunk_info *info_ptr = chunkinfos->data[i];
int parities_count; int parities_count;
u64 size; u64 size;
double l_data_ratio, l_metadata_ratio, l_system_ratio, rt; double l_data_ratio, l_metadata_ratio, l_system_ratio, rt;
@ -440,8 +438,8 @@ static u64 calc_slack_size(const struct device_info *devinfo)
} }
#define MIN_UNALOCATED_THRESH SZ_16M #define MIN_UNALOCATED_THRESH SZ_16M
static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, static int print_filesystem_usage_overall(int fd, const struct array *chunkinfos,
int chunkcount, struct device_info *devinfo, int devcount, struct device_info *devinfo, int devcount,
const char *path, unsigned unit_mode) const char *path, unsigned unit_mode)
{ {
struct btrfs_ioctl_space_args *sargs = NULL; struct btrfs_ioctl_space_args *sargs = NULL;
@ -503,7 +501,7 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo,
goto exit; goto exit;
} }
get_raid56_space_info(sargs, chunkinfo, chunkcount, &max_data_ratio, get_raid56_space_info(sargs, chunkinfos, &max_data_ratio,
&r_data_chunks, &r_data_used, &r_data_chunks, &r_data_used,
&r_metadata_chunks, &r_metadata_used, &r_metadata_chunks, &r_metadata_used,
&r_system_chunks, &r_system_used); &r_system_chunks, &r_system_used);
@ -829,13 +827,12 @@ out:
return ret; return ret;
} }
int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo_ret, int load_chunk_and_device_info(int fd, struct array *chunkinfos,
int *chunkcount_ret, struct device_info **devinfo_ret, struct device_info **devinfo_ret, int *devcount_ret)
int *devcount_ret)
{ {
int ret; int ret;
ret = load_chunk_info(fd, chunkinfo_ret, chunkcount_ret); ret = load_chunk_info(fd, chunkinfos);
if (ret == -EPERM) { if (ret == -EPERM) {
warning( warning(
"cannot read detailed chunk info, per-device usage will not be shown, run as root"); "cannot read detailed chunk info, per-device usage will not be shown, run as root");
@ -856,7 +853,7 @@ int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo_ret,
/* /*
* This function computes the size of a chunk in a disk * This function computes the size of a chunk in a disk
*/ */
static u64 calc_chunk_size(struct chunk_info *ci) static u64 calc_chunk_size(const struct chunk_info *ci)
{ {
u32 div = 1; u32 div = 1;
@ -879,8 +876,7 @@ static u64 calc_chunk_size(struct chunk_info *ci)
*/ */
static void _cmd_filesystem_usage_tabular(unsigned unit_mode, static void _cmd_filesystem_usage_tabular(unsigned unit_mode,
struct btrfs_ioctl_space_args *sargs, struct btrfs_ioctl_space_args *sargs,
struct chunk_info *chunks_info_ptr, const struct array *chunkinfos,
int chunks_info_count,
struct device_info *devinfo, struct device_info *devinfo,
int devcount) int devcount)
{ {
@ -966,19 +962,20 @@ static void _cmd_filesystem_usage_tabular(unsigned unit_mode,
for (col = spaceinfos_col, k = 0; k < sargs->total_spaces; k++) { for (col = spaceinfos_col, k = 0; k < sargs->total_spaces; k++) {
u64 flags = sargs->spaces[k].flags; u64 flags = sargs->spaces[k].flags;
u64 devid = devinfo[i].devid; u64 devid = devinfo[i].devid;
int j;
u64 size = 0; u64 size = 0;
if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
continue; continue;
for (j = 0 ; j < chunks_info_count ; j++) { for (int j = 0; j < chunkinfos->length; j++) {
if (chunks_info_ptr[j].type != flags ) const struct chunk_info *chunk = chunkinfos->data[j];
if (chunk->type != flags)
continue; continue;
if (chunks_info_ptr[j].devid != devid) if (chunk->devid != devid)
continue; continue;
size += calc_chunk_size(chunks_info_ptr+j); size += calc_chunk_size(chunk);
} }
if (size) if (size)
@ -1073,20 +1070,20 @@ static void _cmd_filesystem_usage_tabular(unsigned unit_mode,
/* /*
* This function prints the unused space per every disk * This function prints the unused space per every disk
*/ */
static void print_unused(struct chunk_info *info_ptr, static void print_unused(const struct array *chunkinfos, struct device_info *devinfo,
int info_count, int devcount, unsigned unit_mode)
struct device_info *devinfo,
int devcount,
unsigned unit_mode)
{ {
int i; int i;
for (i = 0; i < devcount; i++) { for (i = 0; i < devcount; i++) {
int j;
u64 total = 0; u64 total = 0;
for (j = 0; j < info_count; j++) for (int j = 0; j < chunkinfos->length; j++) {
if (info_ptr[j].devid == devinfo[i].devid) const struct chunk_info *chunk = chunkinfos->data[j];
total += calc_chunk_size(info_ptr+j);
if (chunk->devid == devinfo[i].devid)
total += calc_chunk_size(chunk);
}
pr_verbose(LOG_DEFAULT, " %s\t%10s\n", pr_verbose(LOG_DEFAULT, " %s\t%10s\n",
devinfo[i].path, devinfo[i].path,
@ -1097,28 +1094,24 @@ static void print_unused(struct chunk_info *info_ptr,
/* /*
* This function prints the allocated chunk per every disk * This function prints the allocated chunk per every disk
*/ */
static void print_chunk_device(u64 chunk_type, static void print_chunk_device(u64 chunk_type, const struct array *chunkinfos,
struct chunk_info *chunks_info_ptr, struct device_info *devinfo, int devcount,
int chunks_info_count,
struct device_info *devinfo,
int devcount,
unsigned unit_mode) unsigned unit_mode)
{ {
int i; int i;
for (i = 0; i < devcount; i++) { for (i = 0; i < devcount; i++) {
int j;
u64 total = 0; u64 total = 0;
for (j = 0; j < chunks_info_count; j++) { for (int j = 0; j < chunkinfos->length; j++) {
const struct chunk_info *chunk = chunkinfos->data[j];
if (chunks_info_ptr[j].type != chunk_type) if (chunk->type != chunk_type)
continue; continue;
if (chunks_info_ptr[j].devid != devinfo[i].devid) if (chunk->devid != devinfo[i].devid)
continue; continue;
total += calc_chunk_size(&(chunks_info_ptr[j])); total += calc_chunk_size(chunk);
//total += chunks_info_ptr[j].size;
} }
if (total > 0) if (total > 0)
@ -1134,8 +1127,7 @@ static void print_chunk_device(u64 chunk_type,
*/ */
static void _cmd_filesystem_usage_linear(unsigned unit_mode, static void _cmd_filesystem_usage_linear(unsigned unit_mode,
struct btrfs_ioctl_space_args *sargs, struct btrfs_ioctl_space_args *sargs,
struct chunk_info *info_ptr, const struct array *chunkinfos,
int info_count,
struct device_info *devinfo, struct device_info *devinfo,
int devcount) int devcount)
{ {
@ -1161,20 +1153,18 @@ static void _cmd_filesystem_usage_linear(unsigned unit_mode,
pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode), pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode),
100.0f * sargs->spaces[i].used_bytes / 100.0f * sargs->spaces[i].used_bytes /
(sargs->spaces[i].total_bytes + 1)); (sargs->spaces[i].total_bytes + 1));
print_chunk_device(flags, info_ptr, info_count, print_chunk_device(flags, chunkinfos, devinfo, devcount, unit_mode);
devinfo, devcount, unit_mode);
pr_verbose(LOG_DEFAULT, "\n"); pr_verbose(LOG_DEFAULT, "\n");
} }
if (info_count) { if (chunkinfos->length > 0) {
pr_verbose(LOG_DEFAULT, "Unallocated:\n"); pr_verbose(LOG_DEFAULT, "Unallocated:\n");
print_unused(info_ptr, info_count, devinfo, print_unused(chunkinfos, devinfo, devcount, unit_mode | UNITS_NEGATIVE);
devcount, unit_mode | UNITS_NEGATIVE);
} }
} }
static int print_filesystem_usage_by_chunk(int fd, static int print_filesystem_usage_by_chunk(int fd,
struct chunk_info *chunkinfo, int chunkcount, const struct array *chunkinfos,
struct device_info *devinfo, int devcount, struct device_info *devinfo, int devcount,
const char *path, unsigned unit_mode, int tabular) const char *path, unsigned unit_mode, int tabular)
{ {
@ -1188,11 +1178,11 @@ static int print_filesystem_usage_by_chunk(int fd,
} }
if (tabular) if (tabular)
_cmd_filesystem_usage_tabular(unit_mode, sargs, chunkinfo, _cmd_filesystem_usage_tabular(unit_mode, sargs, chunkinfos,
chunkcount, devinfo, devcount); devinfo, devcount);
else else
_cmd_filesystem_usage_linear(unit_mode, sargs, chunkinfo, _cmd_filesystem_usage_linear(unit_mode, sargs, chunkinfos,
chunkcount, devinfo, devcount); devinfo, devcount);
free(sargs); free(sargs);
out: out:
@ -1242,9 +1232,8 @@ static int cmd_filesystem_usage(const struct cmd_struct *cmd,
for (i = optind; i < argc; i++) { for (i = optind; i < argc; i++) {
int fd; int fd;
DIR *dirstream = NULL; DIR *dirstream = NULL;
struct chunk_info *chunkinfo = NULL; struct array chunkinfos = { 0 };
struct device_info *devinfo = NULL; struct device_info *devinfo = NULL;
int chunkcount = 0;
int devcount = 0; int devcount = 0;
fd = btrfs_open_dir(argv[i], &dirstream, 1); fd = btrfs_open_dir(argv[i], &dirstream, 1);
@ -1255,21 +1244,22 @@ static int cmd_filesystem_usage(const struct cmd_struct *cmd,
if (more_than_one) if (more_than_one)
pr_verbose(LOG_DEFAULT, "\n"); pr_verbose(LOG_DEFAULT, "\n");
ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount, ret = load_chunk_and_device_info(fd, &chunkinfos,
&devinfo, &devcount); &devinfo, &devcount);
if (ret) if (ret)
goto cleanup; goto cleanup;
ret = print_filesystem_usage_overall(fd, chunkinfo, chunkcount, ret = print_filesystem_usage_overall(fd, &chunkinfos,
devinfo, devcount, argv[i], unit_mode); devinfo, devcount, argv[i], unit_mode);
if (ret) if (ret)
goto cleanup; goto cleanup;
pr_verbose(LOG_DEFAULT, "\n"); pr_verbose(LOG_DEFAULT, "\n");
ret = print_filesystem_usage_by_chunk(fd, chunkinfo, chunkcount, ret = print_filesystem_usage_by_chunk(fd, &chunkinfos,
devinfo, devcount, argv[i], unit_mode, tabular); devinfo, devcount, argv[i], unit_mode, tabular);
cleanup: cleanup:
close_file_or_dir(fd, dirstream); close_file_or_dir(fd, dirstream);
free(chunkinfo); array_free_elements(&chunkinfos);
array_free(&chunkinfos);
free(devinfo); free(devinfo);
if (ret) if (ret)
@ -1283,30 +1273,31 @@ out:
DEFINE_SIMPLE_COMMAND(filesystem_usage, "usage"); DEFINE_SIMPLE_COMMAND(filesystem_usage, "usage");
void print_device_chunks(struct device_info *devinfo, void print_device_chunks(struct device_info *devinfo,
struct chunk_info *chunks_info_ptr, const struct array *chunkinfos, unsigned unit_mode)
int chunks_info_count, unsigned unit_mode)
{ {
int i; int i;
u64 allocated = 0; u64 allocated = 0;
for (i = 0 ; i < chunks_info_count ; i++) { for (i = 0; i < chunkinfos->length; i++) {
const char *description; const char *description;
const char *r_mode; const char *r_mode;
const struct chunk_info *chunk_info;
u64 flags; u64 flags;
u64 size; u64 size;
u64 num_stripes; u64 num_stripes;
u64 profile; u64 profile;
if (chunks_info_ptr[i].devid != devinfo->devid) chunk_info = chunkinfos->data[i];
if (chunk_info->devid != devinfo->devid)
continue; continue;
flags = chunks_info_ptr[i].type; flags = chunk_info->type;
profile = (flags & BTRFS_BLOCK_GROUP_PROFILE_MASK); profile = (flags & BTRFS_BLOCK_GROUP_PROFILE_MASK);
description = btrfs_group_type_str(flags); description = btrfs_group_type_str(flags);
r_mode = btrfs_group_profile_str(flags); r_mode = btrfs_group_profile_str(flags);
size = calc_chunk_size(chunks_info_ptr+i); size = calc_chunk_size(chunk_info);
num_stripes = chunks_info_ptr[i].num_stripes; num_stripes = chunk_info->num_stripes;
if (btrfs_bg_type_is_stripey(profile)) { if (btrfs_bg_type_is_stripey(profile)) {
pr_verbose(LOG_DEFAULT, " %s,%s/%llu:%*s%10s\n", pr_verbose(LOG_DEFAULT, " %s,%s/%llu:%*s%10s\n",

View File

@ -21,6 +21,7 @@
#include "kerncompat.h" #include "kerncompat.h"
#include "kernel-shared/volumes.h" #include "kernel-shared/volumes.h"
#include "common/array.h"
struct device_info { struct device_info {
u64 devid; u64 devid;
@ -44,11 +45,10 @@ struct chunk_info {
u64 num_stripes; u64 num_stripes;
}; };
int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo_ret, int load_chunk_and_device_info(int fd, struct array *chunkinfos,
int *chunkcount_ret, struct device_info **devinfo_ret, struct device_info **devinfo_ret, int *devcount_ret);
int *devcount_ret);
void print_device_chunks(struct device_info *devinfo, void print_device_chunks(struct device_info *devinfo,
struct chunk_info *chunk_info, int chunkcount, unsigned unit_mode); const struct array *chunkinfos, unsigned unit_mode);
void print_device_sizes(struct device_info *devinfo, unsigned unit_mode); void print_device_sizes(struct device_info *devinfo, unsigned unit_mode);
int dev_to_fsid(const char *dev, u8 *fsid); int dev_to_fsid(const char *dev, u8 *fsid);