X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=cmds-fi-usage.c;h=de7ad668ba2de26a92201de2b625276fe1236f79;hb=a5ef445f05fb077736d47624e31b9f6c7bbb0f1b;hp=65c16b80e8a974c80cbe2c46c361015b0a0248d4;hpb=5205097bacbc64a7590d3139430b456bedf57de2;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/cmds-fi-usage.c b/cmds-fi-usage.c index 65c16b8..de7ad66 100644 --- a/cmds-fi-usage.c +++ b/cmds-fi-usage.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "utils.h" #include "kerncompat.h" @@ -29,8 +30,10 @@ #include "string-table.h" #include "cmds-fi-usage.h" #include "commands.h" +#include "disk-io.h" #include "version.h" +#include "help.h" /* * Add the chunk info to the chunk_info list @@ -47,7 +50,7 @@ static int add_info_to_list(struct chunk_info **info_ptr, 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; @@ -63,12 +66,12 @@ static int add_info_to_list(struct chunk_info **info_ptr, } 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; } @@ -161,9 +164,7 @@ static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count return -e; if (ret < 0) { - fprintf(stderr, - "ERROR: can't perform the search - %s\n", - strerror(e)); + error("cannot look up chunk tree info: %m"); return 1; } /* the ioctl returns the number of item it found in nr_items */ @@ -182,15 +183,15 @@ static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count 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 */ @@ -228,12 +229,12 @@ static int cmp_btrfs_ioctl_space_info(const void *a, const void *b) */ 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; } @@ -241,11 +242,8 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) 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': %m", path); free(sargs); return NULL; } @@ -261,7 +259,7 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) (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; } @@ -269,12 +267,9 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) 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: %m", + count); free(sargs); return NULL; } @@ -286,12 +281,12 @@ static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path) } /* - * 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. */ -static void get_raid56_used(int fd, struct chunk_info *chunks, int chunkcount, +static void get_raid56_used(struct chunk_info *chunks, int chunkcount, u64 *raid5_used, u64 *raid6_used) { struct chunk_info *info_ptr = chunks; @@ -307,12 +302,12 @@ static void get_raid56_used(int fd, struct chunk_info *chunks, int chunkcount, } } -#define MIN_UNALOCATED_THRESH (16 * 1024 * 1024) +#define MIN_UNALOCATED_THRESH SZ_16M 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; + struct btrfs_ioctl_space_args *sargs = NULL; int i; int ret = 0; int width = 10; /* default 10 for human units */ @@ -343,6 +338,7 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, u64 free_estimated = 0; u64 free_min = 0; int max_data_ratio = 1; + int mixed = 0; sargs = load_space_info(fd, path); if (!sargs) { @@ -358,14 +354,12 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, } if (r_total_size == 0) { - fprintf(stderr, - "ERROR: couldn't get space info on '%s' - %s\n", - path, strerror(errno)); + error("cannot get space info on '%s': %m", path); ret = 1; goto exit; } - get_raid56_used(fd, chunkinfo, chunkcount, &raid5_used, &raid6_used); + get_raid56_used(chunkinfo, chunkcount, &raid5_used, &raid6_used); for (i = 0; i < sargs->total_spaces; i++) { int ratio; @@ -391,7 +385,7 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, 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; @@ -401,10 +395,9 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, 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; @@ -421,13 +414,20 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, } } - 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 */ @@ -444,6 +444,13 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, * 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 */ @@ -464,7 +471,7 @@ static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo, 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)); + pretty_size_mode(r_total_unused, unit_mode | UNITS_NEGATIVE)); printf(" Device missing:\t\t%*s\n", width, pretty_size_mode(r_total_missing, unit_mode)); printf(" Used:\t\t\t%*s\n", width, @@ -498,6 +505,33 @@ static int cmp_device_info(const void *a, const void *b) ((struct device_info *)b)->path); } +int dev_to_fsid(const char *dev, u8 *fsid) +{ + struct btrfs_super_block *disk_super; + char buf[BTRFS_SUPER_INFO_SIZE]; + int ret; + int fd; + + fd = open(dev, O_RDONLY); + if (fd < 0) { + ret = -errno; + return ret; + } + + disk_super = (struct btrfs_super_block *)buf; + ret = btrfs_read_dev_super(fd, disk_super, + BTRFS_SUPER_INFO_OFFSET, SBREAD_DEFAULT); + if (ret) + goto out; + + memcpy(fsid, disk_super->fsid, BTRFS_FSID_SIZE); + ret = 0; + +out: + close(fd); + return ret; +} + /* * This function loads the device_info structure and put them in an array */ @@ -508,40 +542,54 @@ static int load_device_info(int fd, struct device_info **device_info_ptr, struct btrfs_ioctl_fs_info_args fi_args; struct btrfs_ioctl_dev_info_args dev_info; struct device_info *info; + u8 fsid[BTRFS_UUID_SIZE]; *device_info_count = 0; - *device_info_ptr = 0; + *device_info_ptr = NULL; ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args); if (ret < 0) { if (errno == EPERM) return -errno; - fprintf(stderr, "ERROR: cannot get filesystem info - %s\n", - strerror(errno)); + error("cannot get filesystem info: %m"); 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; } for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) { - BUG_ON(ndevs >= fi_args.num_devices); + if (ndevs >= fi_args.num_devices) { + error("unexpected number of devices: %d >= %llu", ndevs, + (unsigned long long)fi_args.num_devices); + error( + "if seed device is used, try running this command as root"); + goto out; + } memset(&dev_info, 0, sizeof(dev_info)); ret = get_device_info(fd, i, &dev_info); if (ret == -ENODEV) continue; if (ret) { - fprintf(stderr, - "ERROR: cannot get info about device devid=%d\n", - i); - free(info); - return ret; + error("cannot get info about device devid=%d", i); + goto out; } + /* + * Skip seed device by checking device's fsid (requires root). + * And we will skip only if dev_to_fsid is successful and dev + * is a seed device. + * Ignore any other error including -EACCES, which is seen when + * a non-root process calls dev_to_fsid(path)->open(path). + */ + ret = dev_to_fsid((const char *)dev_info.path, fsid); + if (!ret && memcmp(fi_args.fsid, fsid, BTRFS_FSID_SIZE) != 0) + continue; + info[ndevs].devid = dev_info.devid; if (!dev_info.path[0]) { strcpy(info[ndevs].path, "missing"); @@ -554,7 +602,12 @@ static int load_device_info(int fd, struct device_info **device_info_ptr, ++ndevs; } - BUG_ON(ndevs != fi_args.num_devices); + if (ndevs != fi_args.num_devices) { + error("unexpected number of devices: %d != %llu", ndevs, + (unsigned long long)fi_args.num_devices); + goto out; + } + qsort(info, fi_args.num_devices, sizeof(struct device_info), cmp_device_info); @@ -562,6 +615,10 @@ static int load_device_info(int fd, struct device_info **device_info_ptr, *device_info_ptr = info; return 0; + +out: + free(info); + return ret; } int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo, @@ -571,16 +628,16 @@ int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo, 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; } @@ -620,19 +677,29 @@ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, { 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++; + } - /* data/metadata/system, unallocated */ - ncols = sargs->total_spaces + 1; /* 2 for header, empty line, devices, ===, total, used */ - nrows = 2 + 1 + device_info_count + 1 + 2; + 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; } @@ -642,7 +709,7 @@ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, */ /* header */ - for (i = 0, col = 1; i < sargs->total_spaces; i++) { + for (i = 0, col = spaceinfos_col; i < sargs->total_spaces; i++) { u64 flags = sargs->spaces[i].flags; if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) @@ -656,6 +723,8 @@ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, } unallocated_col = col; + table_printf(matrix, 0, 1, "%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; @@ -692,10 +764,10 @@ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, } 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++; @@ -704,40 +776,51 @@ static void _cmd_filesystem_usage_tabular(unsigned unit_mode, unused = get_partition_size(device_info_ptr[i].path) - total_allocated; - table_printf(matrix, unallocated_col, i + 3, - ">%s", pretty_size_mode(unused, unit_mode)); + table_printf(matrix, unallocated_col, vhdr_skip + i, ">%s", + pretty_size_mode(unused, unit_mode | UNITS_NEGATIVE)); total_unused += unused; } - for (i = 0, col = 1; i < sargs->total_spaces; i++) { + 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++, device_info_count + 3, "="); + table_printf(matrix, col, vhdr_skip - 1, "*-"); + table_printf(matrix, col, vhdr_skip + device_info_count, "*-"); + col++; } /* One for Unallocated */ - table_printf(matrix, col, device_info_count + 3, "="); + 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_spaces; i++) { + table_printf(matrix, 1, vhdr_skip + device_info_count + 1, "total_spaces; i++) { if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; - table_printf(matrix, col++, device_info_count + 4, ">%s", + 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, device_info_count + 4, - ">%s", pretty_size_mode(total_unused, unit_mode)); + table_printf(matrix, unallocated_col, vhdr_skip + device_info_count + 1, + ">%s", + pretty_size_mode(total_unused, unit_mode | UNITS_NEGATIVE)); - table_printf(matrix, 0, device_info_count + 5, "total_spaces; i++) { + table_printf(matrix, 1, vhdr_skip + device_info_count + 2, "total_spaces; i++) { if (sargs->spaces[i].flags & BTRFS_SPACE_INFO_GLOBAL_RSV) continue; - table_printf(matrix, col++, device_info_count+5, ">%s", + table_printf(matrix, col++, vhdr_skip + device_info_count + 2, + ">%s", pretty_size_mode(sargs->spaces[i].used_bytes, unit_mode)); } @@ -842,7 +925,7 @@ static void _cmd_filesystem_usage_linear(unsigned unit_mode, printf("Unallocated:\n"); print_unused(info_ptr, info_count, device_info_ptr, device_info_count, - unit_mode); + unit_mode | UNITS_NEGATIVE); } static int print_filesystem_usage_by_chunk(int fd, @@ -877,7 +960,7 @@ out: const char * const cmd_filesystem_usage_usage[] = { "btrfs filesystem usage [options] [..]", "Show detailed information about internal filesystem usage .", - HELPINFO_OUTPUT_UNIT_DF, + HELPINFO_UNITS_SHORT_LONG, "-T show data in tabular format", NULL }; @@ -892,7 +975,6 @@ int cmd_filesystem_usage(int argc, char **argv) unit_mode = get_unit_mode_from_arg(&argc, argv, 1); - optind = 1; while (1) { int c; @@ -954,7 +1036,7 @@ out: return !!ret; } -void print_device_chunks(int fd, struct device_info *devinfo, +void print_device_chunks(struct device_info *devinfo, struct chunk_info *chunks_info_ptr, int chunks_info_count, unsigned unit_mode) { @@ -986,21 +1068,18 @@ void print_device_chunks(int fd, struct device_info *devinfo, } printf(" Unallocated: %*s%10s\n", (int)(20 - strlen("Unallocated")), "", - pretty_size_mode(devinfo->size - allocated, unit_mode)); + pretty_size_mode(devinfo->size - allocated, + unit_mode | UNITS_NEGATIVE)); } -void print_device_sizes(int fd, struct device_info *devinfo, unsigned unit_mode) +void print_device_sizes(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 + printf(" Device slack: %*s%10s\n", + (int)(20 - strlen("Device slack")), "", + pretty_size_mode(devinfo->device_size > 0 ? + devinfo->device_size - devinfo->size : 0, + unit_mode)); }