for (j = 0 ; j < num_stripes ; j++) {
int i;
- struct chunk_info *p = 0;
+ struct chunk_info *p = NULL;
struct btrfs_stripe *stripe;
u64 devid;
}
if (!p) {
- int size = sizeof(struct btrfs_chunk) * (*info_count+1);
- struct chunk_info *res = realloc(*info_ptr, size);
+ int tmp = sizeof(struct btrfs_chunk) * (*info_count + 1);
+ struct chunk_info *res = realloc(*info_ptr, tmp);
if (!res) {
free(*info_ptr);
- fprintf(stderr, "ERROR: not enough memory\n");
+ error("not enough memory");
return -ENOMEM;
}
return -e;
if (ret < 0) {
- fprintf(stderr,
- "ERROR: can't perform the search - %s\n",
+ error("cannot look up chunk tree info: %s",
strerror(e));
return 1;
}
ret = add_info_to_list(info_ptr, info_count, item);
if (ret) {
- *info_ptr = 0;
+ *info_ptr = NULL;
return 1;
}
- off += sh->len;
+ off += btrfs_search_header_len(sh);
- sk->min_objectid = sh->objectid;
- sk->min_type = sh->type;
- sk->min_offset = sh->offset+1;
+ sk->min_objectid = btrfs_search_header_objectid(sh);
+ sk->min_type = btrfs_search_header_type(sh);
+ sk->min_offset = btrfs_search_header_offset(sh)+1;
}
if (!sk->min_offset) /* overflow */
*/
static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path)
{
- struct btrfs_ioctl_space_args *sargs = 0, *sargs_orig = 0;
- int e, ret, count;
+ struct btrfs_ioctl_space_args *sargs = NULL, *sargs_orig = NULL;
+ int ret, count;
sargs_orig = sargs = calloc(1, sizeof(struct btrfs_ioctl_space_args));
if (!sargs) {
- fprintf(stderr, "ERROR: not enough memory\n");
+ error("not enough memory");
return NULL;
}
sargs->total_spaces = 0;
ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
- e = errno;
- if (ret) {
- fprintf(stderr,
- "ERROR: couldn't get space info on '%s' - %s\n",
- path, strerror(e));
+ if (ret < 0) {
+ error("cannot get space info on '%s': %s", path,
+ strerror(errno));
free(sargs);
return NULL;
}
(count * sizeof(struct btrfs_ioctl_space_info)));
if (!sargs) {
free(sargs_orig);
- fprintf(stderr, "ERROR: not enough memory\n");
+ error("not enough memory");
return NULL;
}
sargs->total_spaces = 0;
ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
- e = errno;
-
- if (ret) {
- fprintf(stderr,
- "ERROR: couldn't get space info on '%s' - %s\n",
- path, strerror(e));
+ if (ret < 0) {
+ error("cannot get space info with %u slots: %s",
+ count, strerror(errno));
free(sargs);
return NULL;
}
}
/*
- * This function computes the space occuped by a *single* RAID5/RAID6 chunk.
+ * 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.
int chunkcount, struct device_info *devinfo, int devcount,
char *path, unsigned unit_mode)
{
- struct btrfs_ioctl_space_args *sargs = 0;
+ struct btrfs_ioctl_space_args *sargs = NULL;
int i;
int ret = 0;
int width = 10; /* default 10 for human units */
u64 free_estimated = 0;
u64 free_min = 0;
int max_data_ratio = 1;
+ int mixed = 0;
sargs = load_space_info(fd, path);
if (!sargs) {
}
if (r_total_size == 0) {
- fprintf(stderr,
- "ERROR: couldn't get space info on '%s' - %s\n",
+ error("cannot get space info on '%s': %s",
path, strerror(errno));
ret = 1;
ratio = 1;
if (!ratio)
- fprintf(stderr, "WARNING: RAID56 detected, not implemented\n");
+ warning("RAID56 detected, not implemented");
if (ratio > max_data_ratio)
max_data_ratio = ratio;
l_global_reserve_used = sargs->spaces[i].used_bytes;
}
if ((flags & (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA))
- == (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA)) {
- fprintf(stderr, "WARNING: MIXED blockgroups not handled\n");
+ == (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA)) {
+ mixed = 1;
}
-
if (flags & BTRFS_BLOCK_GROUP_DATA) {
r_data_used += sargs->spaces[i].used_bytes * ratio;
r_data_chunks += sargs->spaces[i].total_bytes * ratio;
}
}
- r_total_chunks = r_data_chunks + r_metadata_chunks + r_system_chunks;
- r_total_used = r_data_used + r_metadata_used + r_system_used;
+ r_total_chunks = r_data_chunks + r_system_chunks;
+ r_total_used = r_data_used + r_system_used;
+ if (!mixed) {
+ r_total_chunks += r_metadata_chunks;
+ r_total_used += r_metadata_used;
+ }
r_total_unused = r_total_size - r_total_chunks;
/* Raw / Logical = raid factor, >= 1 */
data_ratio = (double)r_data_chunks / l_data_chunks;
- metadata_ratio = (double)r_metadata_chunks / l_metadata_chunks;
+ if (mixed)
+ metadata_ratio = data_ratio;
+ else
+ metadata_ratio = (double)r_metadata_chunks / l_metadata_chunks;
#if 0
/* add the raid5/6 allocated space */
* In non-mixed case there's no difference.
*/
free_estimated = (r_data_chunks - r_data_used) / data_ratio;
+ /*
+ * For mixed-bg the metadata are left out in calculations thus global
+ * reserve would be lost. Part of it could be permanently allocated,
+ * we have to subtract the used bytes so we don't go under zero free.
+ */
+ if (mixed)
+ free_estimated -= l_global_reserve - l_global_reserve_used;
free_min = free_estimated;
/* Chop unallocatable space */
static int load_device_info(int fd, struct device_info **device_info_ptr,
int *device_info_count)
{
- int ret, i, ndevs, e;
+ int ret, i, ndevs;
struct btrfs_ioctl_fs_info_args fi_args;
struct btrfs_ioctl_dev_info_args dev_info;
struct device_info *info;
*device_info_count = 0;
- *device_info_ptr = 0;
+ *device_info_ptr = NULL;
ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
- e = errno;
- if (e == EPERM)
- return -e;
if (ret < 0) {
- fprintf(stderr, "ERROR: cannot get filesystem info - %s\n",
- strerror(e));
+ if (errno == EPERM)
+ return -errno;
+ error("cannot get filesystem info: %s",
+ strerror(errno));
return 1;
}
info = calloc(fi_args.num_devices, sizeof(struct device_info));
if (!info) {
- fprintf(stderr, "ERROR: not enough memory\n");
+ error("not enough memory");
return 1;
}
if (ret == -ENODEV)
continue;
if (ret) {
- fprintf(stderr,
- "ERROR: cannot get info about device devid=%d\n",
- i);
+ error("cannot get info about device devid=%d", i);
free(info);
return ret;
}
ret = load_chunk_info(fd, chunkinfo, chunkcount);
if (ret == -EPERM) {
- fprintf(stderr,
- "WARNING: can't read detailed chunk info, RAID5/6 numbers will be incorrect, run as root\n");
+ warning(
+"cannot read detailed chunk info, RAID5/6 numbers will be incorrect, run as root");
} else if (ret) {
return ret;
}
ret = load_device_info(fd, devinfo, devcount);
if (ret == -EPERM) {
- fprintf(stderr,
- "WARNING: can't get filesystem info from ioctl(FS_INFO), run as root\n");
+ warning(
+ "cannot get filesystem info from ioctl(FS_INFO), run as root");
ret = 0;
}
{
int i;
u64 total_unused = 0;
- struct string_table *matrix = 0;
+ struct string_table *matrix = NULL;
int ncols, nrows;
+ int col;
+ int unallocated_col;
+ int spaceinfos_col;
+ const int vhdr_skip = 3; /* amount of vertical header space */
+
+ /* id, path, unallocated */
+ ncols = 3;
+ spaceinfos_col = 2;
+ /* Properly count the real space infos */
+ for (i = 0; i < sargs->total_spaces; i++) {
+ if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
+ continue;
+ ncols++;
+ }
- ncols = sargs->total_spaces + 2;
- nrows = 2 + 1 + device_info_count + 1 + 2;
+ /* 2 for header, empty line, devices, ===, total, used */
+ nrows = vhdr_skip + device_info_count + 1 + 2;
matrix = table_create(ncols, nrows);
if (!matrix) {
- fprintf(stderr, "ERROR: not enough memory\n");
+ error("not enough memory");
return;
}
+ /*
+ * We have to skip the global block reserve everywhere as it's an
+ * artificial blockgroup
+ */
+
/* header */
- for (i = 0; i < sargs->total_spaces; i++) {
- const char *description;
+ for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) {
u64 flags = sargs->spaces[i].flags;
if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
continue;
- description = btrfs_group_type_str(flags);
-
- table_printf(matrix, 1+i, 0, "<%s", description);
- }
-
- for (i = 0; i < sargs->total_spaces; i++) {
- const char *r_mode;
-
- u64 flags = sargs->spaces[i].flags;
- r_mode = btrfs_group_profile_str(flags);
-
- table_printf(matrix, 1+i, 1, "<%s", r_mode);
+ table_printf(matrix, col, 0, "<%s",
+ btrfs_group_type_str(flags));
+ table_printf(matrix, col, 1, "<%s",
+ btrfs_group_profile_str(flags));
+ col++;
}
+ unallocated_col = col;
- table_printf(matrix, 1+sargs->total_spaces, 1, "<Unallocated");
+ table_printf(matrix, 0, 1, "<Id");
+ table_printf(matrix, 1, 1, "<Path");
+ table_printf(matrix, unallocated_col, 1, "<Unallocated");
/* body */
for (i = 0; i < device_info_count; i++) {
- int k, col;
+ int k;
char *p;
u64 total_allocated = 0, unused;
else
p++;
- table_printf(matrix, 0, i + 3, "<%s", device_info_ptr[i].path);
+ table_printf(matrix, 0, vhdr_skip + i, ">%llu",
+ device_info_ptr[i].devid);
+ table_printf(matrix, 1, vhdr_skip + i, "<%s",
+ device_info_ptr[i].path);
- for (col = 1, 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 devid = device_info_ptr[i].devid;
int j;
u64 size = 0;
+ if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
+ continue;
+
for (j = 0 ; j < chunks_info_count ; j++) {
if (chunks_info_ptr[j].type != flags )
continue;
}
if (size)
- table_printf(matrix, col, i+3,
+ table_printf(matrix, col, vhdr_skip+ i,
">%s", pretty_size_mode(size, unit_mode));
else
- table_printf(matrix, col, i+3, ">-");
+ table_printf(matrix, col, vhdr_skip + i, ">-");
total_allocated += size;
col++;
unused = get_partition_size(device_info_ptr[i].path)
- total_allocated;
- table_printf(matrix, sargs->total_spaces + 1, i + 3,
+ table_printf(matrix, unallocated_col, vhdr_skip + i,
">%s", pretty_size_mode(unused, unit_mode));
total_unused += unused;
}
- for (i = 0; i <= sargs->total_spaces; i++)
- table_printf(matrix, i + 1, device_info_count + 3, "=");
+ for (i = 0; i < spaceinfos_col; i++) {
+ table_printf(matrix, i, vhdr_skip - 1, "*-");
+ table_printf(matrix, i, vhdr_skip + device_info_count, "*-");
+ }
+
+ for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) {
+ if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
+ continue;
+
+ table_printf(matrix, col, vhdr_skip - 1, "*-");
+ table_printf(matrix, col, vhdr_skip + device_info_count, "*-");
+ col++;
+ }
+ /* One for Unallocated */
+ table_printf(matrix, col, vhdr_skip - 1, "*-");
+ table_printf(matrix, col, vhdr_skip + device_info_count, "*-");
/* footer */
- table_printf(matrix, 0, device_info_count + 4, "<Total");
- for (i = 0; i < sargs->total_spaces; i++)
- table_printf(matrix, 1 + i, device_info_count + 4, ">%s",
+ table_printf(matrix, 1, vhdr_skip + device_info_count + 1, "<Total");
+ for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) {
+ if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
+ continue;
+
+ table_printf(matrix, col++, vhdr_skip + device_info_count + 1,
+ ">%s",
pretty_size_mode(sargs->spaces[i].total_bytes, unit_mode));
+ }
- table_printf(matrix, sargs->total_spaces + 1, device_info_count + 4,
+ table_printf(matrix, unallocated_col, vhdr_skip + device_info_count + 1,
">%s", pretty_size_mode(total_unused, unit_mode));
- table_printf(matrix, 0, device_info_count + 5, "<Used");
- for (i = 0; i < sargs->total_spaces; i++)
- table_printf(matrix, 1 + i, device_info_count+5, ">%s",
+ table_printf(matrix, 1, vhdr_skip + device_info_count + 2, "<Used");
+ for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) {
+ if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
+ continue;
+
+ table_printf(matrix, col++, vhdr_skip + device_info_count + 2,
+ ">%s",
pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode));
+ }
table_dump(matrix);
table_free(matrix);
const char * const cmd_filesystem_usage_usage[] = {
"btrfs filesystem usage [options] <path> [<path>..]",
"Show detailed information about internal filesystem usage .",
- HELPINFO_OUTPUT_UNIT_DF,
+ HELPINFO_UNITS_SHORT_LONG,
"-T show data in tabular format",
NULL
};
unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
- optind = 1;
while (1) {
int c;
int chunkcount = 0;
int devcount = 0;
- fd = open_file_or_dir(argv[i], &dirstream);
+ fd = btrfs_open_dir(argv[i], &dirstream, 1);
if (fd < 0) {
- fprintf(stderr, "ERROR: can't access '%s'\n",
- argv[i]);
ret = 1;
goto out;
}
printf(" Device size: %*s%10s\n",
(int)(20 - strlen("Device size")), "",
pretty_size_mode(devinfo->device_size, unit_mode));
-#if 0
- /*
- * The term has not seen an agreement and we don't want to change it
- * once it's in non-development branches or even released.
- */
- printf(" FS occupied: %*s%10s\n",
- (int)(20 - strlen("FS occupied")), "",
- pretty_size_mode(devinfo->size, unit_mode));
-#endif
+ printf(" Device slack: %*s%10s\n",
+ (int)(20 - strlen("Device slack")), "",
+ pretty_size_mode(devinfo->device_size - devinfo->size,
+ unit_mode));
}