void print_device_chunks(int fd, struct device_info *devinfo, struct chunk_info *chunks_info_ptr, int chunks_info_count, unsigned unit_mode) { int i; u64 allocated = 0; for (i = 0 ; i < chunks_info_count ; i++) { const char *description; const char *r_mode; u64 flags; u64 size; if (chunks_info_ptr[i].devid != devinfo->devid) continue; flags = chunks_info_ptr[i].type; description = btrfs_group_type_str(flags); r_mode = btrfs_group_profile_str(flags); size = calc_chunk_size(chunks_info_ptr+i); printf(" %s,%s:%*s%10s\n", description, r_mode, (int)(20 - strlen(description) - strlen(r_mode)), "", pretty_size_mode(size, unit_mode)); allocated += size; } printf(" Unallocated: %*s%10s\n", (int)(20 - strlen("Unallocated")), "", pretty_size_mode(devinfo->size - allocated, unit_mode)); }
void print_device_sizes(int fd, struct device_info *devinfo, unsigned unit_mode) { printf(" Device size: %*s%10s\n", (int)(20 - strlen("Device size")), "", pretty_size_mode(devinfo->device_size, unit_mode)); printf(" Device slack: %*s%10s\n", (int)(20 - strlen("Device slack")), "", pretty_size_mode(devinfo->device_size - devinfo->size, unit_mode)); }
void print_device_sizes(int fd, struct device_info *devinfo, unsigned unit_mode) { 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 }
/* * This function prints the allocated chunk per every disk */ static void print_chunk_device(u64 chunk_type, struct chunk_info *chunks_info_ptr, int chunks_info_count, struct device_info *device_info_ptr, int device_info_count, unsigned unit_mode) { int i; for (i = 0; i < device_info_count; i++) { int j; u64 total = 0; for (j = 0; j < chunks_info_count; j++) { if (chunks_info_ptr[j].type != chunk_type) continue; if (chunks_info_ptr[j].devid != device_info_ptr[i].devid) continue; total += calc_chunk_size(&(chunks_info_ptr[j])); //total += chunks_info_ptr[j].size; } if (total > 0) printf(" %s\t%10s\n", device_info_ptr[i].path, pretty_size_mode(total, unit_mode)); } }
/* * This function print the results of the command "btrfs fi usage" * in linear format */ static void _cmd_filesystem_usage_linear(unsigned unit_mode, struct btrfs_ioctl_space_args *sargs, struct chunk_info *info_ptr, int info_count, struct device_info *device_info_ptr, int device_info_count) { int i; for (i = 0; i < sargs->total_spaces; i++) { const char *description; const char *r_mode; u64 flags = sargs->spaces[i].flags; if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; description = btrfs_group_type_str(flags); r_mode = btrfs_group_profile_str(flags); printf("%s,%s: Size:%s, ", description, r_mode, pretty_size_mode(sargs->spaces[i].total_bytes, unit_mode)); printf("Used:%s\n", pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode)); print_chunk_device(flags, info_ptr, info_count, device_info_ptr, device_info_count, unit_mode); printf("\n"); } printf("Unallocated:\n"); print_unused(info_ptr, info_count, device_info_ptr, device_info_count, unit_mode); }
/* * This function prints the unused space per every disk */ static void print_unused(struct chunk_info *info_ptr, int info_count, struct device_info *device_info_ptr, int device_info_count, unsigned unit_mode) { int i; for (i = 0; i < device_info_count; i++) { int j; u64 total = 0; for (j = 0; j < info_count; j++) if (info_ptr[j].devid == device_info_ptr[i].devid) total += calc_chunk_size(info_ptr+j); printf(" %s\t%10s\n", device_info_ptr[i].path, pretty_size_mode(device_info_ptr[i].size - total, unit_mode)); } }
/* * This function print the results of the command "btrfs fi usage" * in tabular format */ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, struct btrfs_ioctl_space_args *sargs, struct chunk_info *chunks_info_ptr, int chunks_info_count, struct device_info *device_info_ptr, int device_info_count) { int i; u64 total_unused = 0; struct string_table *matrix = 0; int ncols, nrows; ncols = sargs->total_spaces + 2; nrows = 2 + 1 + device_info_count + 1 + 2; matrix = table_create(ncols, nrows); if (!matrix) { fprintf(stderr, "ERROR: not enough memory\n"); return; } /* header */ for (i = 0; i < sargs->total_spaces; i++) { const char *description; 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, 1+sargs->total_spaces, 1, "<Unallocated"); /* body */ for (i = 0; i < device_info_count; i++) { int k, col; char *p; u64 total_allocated = 0, unused; p = strrchr(device_info_ptr[i].path, '/'); if (!p) p = device_info_ptr[i].path; else p++; table_printf(matrix, 0, i + 3, "<%s", device_info_ptr[i].path); for (col = 1, 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; for (j = 0 ; j < chunks_info_count ; j++) { if (chunks_info_ptr[j].type != flags ) continue; if (chunks_info_ptr[j].devid != devid) continue; size += calc_chunk_size(chunks_info_ptr+j); } if (size) table_printf(matrix, col, i+3, ">%s", pretty_size_mode(size, unit_mode)); else table_printf(matrix, col, i+3, ">-"); total_allocated += size; col++; } unused = get_partition_size(device_info_ptr[i].path) - total_allocated; table_printf(matrix, sargs->total_spaces + 1, i + 3, ">%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, "="); /* 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", pretty_size_mode(sargs->spaces[i].total_bytes, unit_mode)); table_printf(matrix, sargs->total_spaces + 1, device_info_count + 4, ">%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", pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode)); table_dump(matrix); table_free(matrix); }
static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, int chunkcount, struct device_info *devinfo, int devcount, char *path, unsigned unit_mode) { struct btrfs_ioctl_space_args *sargs = 0; int i; int ret = 0; int width = 10; /* default 10 for human units */ /* * r_* prefix is for raw data * l_* is for logical */ u64 r_total_size = 0; /* filesystem size, sum of device sizes */ u64 r_total_chunks = 0; /* sum of chunks sizes on disk(s) */ u64 r_total_used = 0; u64 r_total_unused = 0; u64 r_total_missing = 0; /* sum of missing devices size */ u64 r_data_used = 0; u64 r_data_chunks = 0; u64 l_data_chunks = 0; u64 r_metadata_used = 0; u64 r_metadata_chunks = 0; u64 l_metadata_chunks = 0; u64 r_system_used = 0; u64 r_system_chunks = 0; 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; sargs = load_space_info(fd, path); if (!sargs) { ret = 1; goto exit; } r_total_size = 0; for (i = 0; i < devcount; i++) { r_total_size += devinfo[i].size; if (!devinfo[i].device_size) r_total_missing += devinfo[i].size; } if (r_total_size == 0) { fprintf(stderr, "ERROR: couldn't get space info on '%s' - %s\n", path, strerror(errno)); ret = 1; goto exit; } get_raid56_used(fd, chunkinfo, chunkcount, &raid5_used, &raid6_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 */ if (flags & BTRFS_BLOCK_GROUP_RAID0) ratio = 1; else if (flags & BTRFS_BLOCK_GROUP_RAID1) ratio = 2; else if (flags & BTRFS_BLOCK_GROUP_RAID5) ratio = 0; else if (flags & BTRFS_BLOCK_GROUP_RAID6) ratio = 0; else if (flags & BTRFS_BLOCK_GROUP_DUP) ratio = 2; else if (flags & BTRFS_BLOCK_GROUP_RAID10) ratio = 2; else ratio = 1; if (!ratio) fprintf(stderr, "WARNING: RAID56 detected, not implemented\n"); if (ratio > max_data_ratio) max_data_ratio = ratio; if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) { l_global_reserve = sargs->spaces[i].total_bytes; 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"); } if (flags & BTRFS_BLOCK_GROUP_DATA) { r_data_used += sargs->spaces[i].used_bytes * ratio; r_data_chunks += sargs->spaces[i].total_bytes * ratio; l_data_chunks += sargs->spaces[i].total_bytes; } if (flags & BTRFS_BLOCK_GROUP_METADATA) { r_metadata_used += sargs->spaces[i].used_bytes * ratio; r_metadata_chunks += sargs->spaces[i].total_bytes * ratio; l_metadata_chunks += sargs->spaces[i].total_bytes; } if (flags & BTRFS_BLOCK_GROUP_SYSTEM) { r_system_used += sargs->spaces[i].used_bytes * ratio; r_system_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_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 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 * * With mixed raid levels, this gives a rough estimate but more * accurate than just counting the logical free space * (l_data_chunks - l_data_used) * * In non-mixed case there's no difference. */ free_estimated = (r_data_chunks - r_data_used) / data_ratio; free_min = free_estimated; /* Chop unallocatable space */ /* FIXME: must be applied per device */ if (r_total_unused >= MIN_UNALOCATED_THRESH) { free_estimated += r_total_unused / data_ratio; /* Match the calculation of 'df', use the highest raid ratio */ free_min += r_total_unused / max_data_ratio; } if (unit_mode != UNITS_HUMAN) width = 18; printf("Overall:\n"); printf(" Device size:\t\t%*s\n", width, pretty_size_mode(r_total_size, unit_mode)); printf(" Device allocated:\t\t%*s\n", width, pretty_size_mode(r_total_chunks, unit_mode)); printf(" Device unallocated:\t\t%*s\n", width, pretty_size_mode(r_total_unused, unit_mode)); printf(" Device missing:\t\t%*s\n", width, pretty_size_mode(r_total_missing, unit_mode)); printf(" Used:\t\t\t%*s\n", width, pretty_size_mode(r_total_used, unit_mode)); printf(" Free (estimated):\t\t%*s\t(", width, pretty_size_mode(free_estimated, unit_mode)); printf("min: %s)\n", pretty_size_mode(free_min, unit_mode)); printf(" Data ratio:\t\t\t%*.2f\n", width, data_ratio); printf(" Metadata ratio:\t\t%*.2f\n", width, metadata_ratio); printf(" Global reserve:\t\t%*s\t(used: %s)\n", width, pretty_size_mode(l_global_reserve, unit_mode), pretty_size_mode(l_global_reserve_used, unit_mode)); exit: if (sargs) free(sargs); return ret; }
/* * This function print the results of the command "btrfs fi usage" * in tabular format */ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, struct btrfs_ioctl_space_args *sargs, struct chunk_info *chunks_info_ptr, int chunks_info_count, struct device_info *device_info_ptr, int device_info_count) { int i; u64 total_unused = 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++; } /* 2 for header, empty line, devices, ===, total, used */ nrows = vhdr_skip + device_info_count + 1 + 2; matrix = table_create(ncols, nrows); if (!matrix) { error("not enough memory"); return; } /* * We have to skip the global block reserve everywhere as it's an * artificial blockgroup */ /* header */ 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; 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, 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; char *p; u64 total_allocated = 0, unused; p = strrchr(device_info_ptr[i].path, '/'); if (!p) p = device_info_ptr[i].path; else p++; 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 = 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 (chunks_info_ptr[j].devid != devid) continue; size += calc_chunk_size(chunks_info_ptr+j); } if (size) table_printf(matrix, col, vhdr_skip+ i, ">%s", pretty_size_mode(size, unit_mode)); else 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, unallocated_col, vhdr_skip + i, ">%s", pretty_size_mode(unused, unit_mode)); total_unused += unused; } 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, 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, unallocated_col, vhdr_skip + device_info_count + 1, ">%s", pretty_size_mode(total_unused, unit_mode)); 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); }