Hello, > From: Goffredo Baroncelli <kreij...@inwind.it> > > Enhance the command "btrfs filesystem df" to show space usage information > for a mount point(s). It shows also an estimation of the space available, > on the basis of the current one used. > > Signed-off-by: Goffredo Baroncelli <kreij...@inwind.it> > --- > Makefile | 2 +- > cmds-fi-disk_usage.c | 530 ++++++++++++++++++++++++++++++++++++++++++++++++++ > cmds-fi-disk_usage.h | 25 +++ > cmds-filesystem.c | 125 +----------- > ctree.h | 17 +- > utils.c | 14 ++ > utils.h | 2 + > 7 files changed, 589 insertions(+), 126 deletions(-) > create mode 100644 cmds-fi-disk_usage.c > create mode 100644 cmds-fi-disk_usage.h > > diff --git a/Makefile b/Makefile > index 0d6c43a..bd792b6 100644 > --- a/Makefile > +++ b/Makefile > @@ -9,7 +9,7 @@ objects = ctree.o disk-io.o radix-tree.o extent-tree.o > print-tree.o \ > string_list.o > cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ > cmds-inspect.o cmds-balance.o cmds-send.o cmds-receive.o \ > - cmds-quota.o cmds-qgroup.o cmds-replace.o > + cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-fi-disk_usage.o > > CHECKFLAGS= -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ > -Wuninitialized -Wshadow -Wundef > diff --git a/cmds-fi-disk_usage.c b/cmds-fi-disk_usage.c > new file mode 100644 > index 0000000..50b2fae > --- /dev/null > +++ b/cmds-fi-disk_usage.c > @@ -0,0 +1,530 @@ > +/* > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public > + * License v2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License for more details. > + * > + * You should have received a copy of the GNU General Public > + * License along with this program; if not, write to the > + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, > + * Boston, MA 021110-1307, USA. > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <sys/ioctl.h> > +#include <errno.h> > + > +#include "utils.h" > +#include "kerncompat.h" > +#include "ctree.h" > +#include "string_list.h" > + > +#include "commands.h" > + > +#include "version.h" > + > +#define DF_HUMAN_UNIT (1<<0) > + > +/* > + * To store the size information about the chunks: > + * the chunks info are grouped by the tuple (type, devid, num_stripes), > + * i.e. if two chunks are of the same type (RAID1, DUP...), are on the > + * same disk, have the same stripes then their sizes are grouped > + */ > +struct chunk_info { > + u64 type; > + u64 size; > + u64 devid; > + u64 num_stripes; > +}; > + > +/* > + * Pretty print the size > + */ > +static char *df_pretty_sizes(u64 size, int mode) > +{ > + char *s; > + > + if (mode & DF_HUMAN_UNIT) { > + s = pretty_sizes(size); > + if (!s) > + return NULL; > + } else { > + s = malloc(21);
I don't really like '21' here... > + if (!s) > + return NULL; > + sprintf(s, "%llu", size); > + } > + > + return s; > +} > + > +/* > + * This function is like the one above, only it passes the string buffer > + * to the string_list_add function to be able to free all the strings > togheter > + * with the string_list_free() function > + */ > +static char *sla_pretty_sizes(u64 size, int mode) > +{ > + return string_list_add(df_pretty_sizes(size,mode)); > +} > + > +/* > + * Add the chunk info to the chunk_info list > + */ > +static int add_info_to_list(struct chunk_info **info_ptr, > + int *info_count, > + struct btrfs_chunk *chunk) > +{ > + > + u64 type = btrfs_stack_chunk_type(chunk); > + u64 size = btrfs_stack_chunk_length(chunk); > + int num_stripes = btrfs_stack_chunk_num_stripes(chunk); why not u64 for num_stripes here? > + int j; > + > + for (j = 0 ; j < num_stripes ; j++) { > + int i; > + struct chunk_info *p = 0; > + struct btrfs_stripe *stripe; > + u64 devid; It is better to move all these declarations to the start of the function… and there are many places..you declare or assign several values in the one line, i think it is not good coding styles ^_^ > + > + stripe = btrfs_stripe_nr(chunk, j); > + devid = btrfs_stack_stripe_devid(stripe); > + > + for (i = 0 ; i < *info_count ; i++) > + if ((*info_ptr)[i].type == type && > + (*info_ptr)[i].devid == devid && > + (*info_ptr)[i].num_stripes == num_stripes ) { > + p = (*info_ptr) + i; > + break; > + } > + > + if (!p) { > + int size = sizeof(struct btrfs_chunk) * (*info_count+1); > + struct chunk_info *res = realloc(*info_ptr, size); > + > + if (!res) { > + fprintf(stderr, "ERROR: not enough memory\n"); a memory leak here.. free(*info_count) > + return -1; > + } > + > + *info_ptr = res; > + p = res + *info_count; > + (*info_count)++; > + > + p->devid = devid; > + p->type = type; > + p->size = 0; > + p->num_stripes = num_stripes; > + } > + > + p->size += size; > + > + } > + > + return 0; > + > +} > + > +/* > + * Helper to sort the chunk type > + */ > +static int cmp_chunk_block_group(u64 f1, u64 f2) > +{ > + > + u64 mask; > + > + if ((f1 & BTRFS_BLOCK_GROUP_TYPE_MASK) == > + (f2 & BTRFS_BLOCK_GROUP_TYPE_MASK)) > + mask = BTRFS_BLOCK_GROUP_PROFILE_MASK; > + else if (f2 & BTRFS_BLOCK_GROUP_SYSTEM) > + return -1; > + else if (f1 & BTRFS_BLOCK_GROUP_SYSTEM) > + return +1; > + else > + mask = BTRFS_BLOCK_GROUP_TYPE_MASK; > + > + if ((f1 & mask) > (f2 & mask)) > + return +1; > + else if ((f1 & mask) < (f2 & mask)) > + return -1; > + else > + return 0; > +} > + > +/* > + * Helper to sort the chunk > + */ > +static int cmp_chunk_info(const void *a, const void *b) > +{ > + return cmp_chunk_block_group( > + ((struct chunk_info *)a)->type, > + ((struct chunk_info *)b)->type); > +} > + > +/* > + * This function load all the chunk info from the 'fd' filesystem > + */ > +static int load_chunk_info(int fd, > + struct chunk_info **info_ptr, > + int *info_count) > +{ > + > + int ret; > + struct btrfs_ioctl_search_args args; > + struct btrfs_ioctl_search_key *sk = &args.key; > + struct btrfs_ioctl_search_header *sh; > + unsigned long off = 0; > + int i, e; > + > + > + memset(&args, 0, sizeof(args)); > + > + /* > + * there may be more than one ROOT_ITEM key if there are > + * snapshots pending deletion, we have to loop through > + * them. > + */ > + > + > + sk->tree_id = BTRFS_CHUNK_TREE_OBJECTID; > + > + sk->min_objectid = 0; > + sk->max_objectid = (u64)-1; > + sk->max_type = 0; > + sk->min_type = (u8)-1; > + sk->min_offset = 0; > + sk->max_offset = (u64)-1; > + sk->min_transid = 0; > + sk->max_transid = (u64)-1; > + sk->nr_items = 4096; > + > + while (1) { > + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); > + e = errno; > + if (ret < 0) { > + fprintf(stderr, > + "ERROR: can't perform the search - %s\n", > + strerror(e)); > + return -99; > + } > + /* the ioctl returns the number of item it found in nr_items */ > + > + if (sk->nr_items == 0) > + break; > + > + off = 0; > + for (i = 0; i < sk->nr_items; i++) { > + struct btrfs_chunk *item; > + sh = (struct btrfs_ioctl_search_header *)(args.buf + > + off); > + > + off += sizeof(*sh); > + item = (struct btrfs_chunk *)(args.buf + off); > + > + if (add_info_to_list(info_ptr, info_count, item)) { > + *info_ptr = 0; > + free(*info_ptr); > + return -100; > + } > + > + off += sh->len; > + > + sk->min_objectid = sh->objectid; > + sk->min_type = sh->type; > + sk->min_offset = sh->offset+1; > + > + } > + if (!sk->min_offset) /* overflow */ > + sk->min_type++; > + else > + continue; > + > + if (!sk->min_type) > + sk->min_objectid++; > + else > + continue; > + > + if (!sk->min_objectid) > + break; > + } > + > + qsort(*info_ptr, *info_count, sizeof(struct chunk_info), > + cmp_chunk_info); > + > + return 0; > + > +} > + > +/* > + * Helper to sort the struct btrfs_ioctl_space_info > + */ > +static int cmp_btrfs_ioctl_space_info(const void *a, const void *b) > +{ > + return cmp_chunk_block_group( > + ((struct btrfs_ioctl_space_info *)a)->flags, > + ((struct btrfs_ioctl_space_info *)b)->flags); > +} > + > +/* > + * This function load all the information about the space usage > + */ > +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; > + > + sargs_orig = sargs = malloc(sizeof(struct btrfs_ioctl_space_args)); > + if (!sargs) { > + fprintf(stderr, "ERROR: not enough memory\n"); > + return NULL; > + } > + > + sargs->space_slots = 0; > + 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)); > + free(sargs); > + return NULL; > + } > + if (!sargs->total_spaces) { > + free(sargs); > + printf("No chunks found\n"); > + return NULL; > + } > + > + count = sargs->total_spaces; > + > + sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) + > + (count * sizeof(struct btrfs_ioctl_space_info))); > + if (!sargs) { > + free(sargs_orig); > + fprintf(stderr, "ERROR: not enough memory\n"); > + return NULL; > + } > + > + sargs->space_slots = count; > + 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)); > + free(sargs); > + return NULL; > + } > + > + qsort(&(sargs->spaces), count, sizeof(struct btrfs_ioctl_space_info), > + cmp_btrfs_ioctl_space_info); > + > + return sargs; > +} > + > +/* > + * This function computes the space occuped 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 disks > + * if a disk is added later. > + */ > +static int get_raid56_used(int fd, u64 *raid5_used, u64 *raid6_used) > +{ > + struct chunk_info *info_ptr=0, *p; > + int info_count=0; > + int ret; > + > + *raid5_used = *raid6_used =0; > + > + ret = load_chunk_info(fd, &info_ptr, &info_count); > + if( ret < 0) > + return ret; > + > + for ( p = info_ptr; info_count ; info_count--, p++ ) { > + if (p->type & BTRFS_BLOCK_GROUP_RAID5) > + (*raid5_used) += p->size / (p->num_stripes -1); > + if (p->type & BTRFS_BLOCK_GROUP_RAID6) > + (*raid6_used) += p->size / (p->num_stripes -2); > + } > + > + return 0; > + > +} > + > +static int _cmd_disk_free(int fd, char *path, int mode) > +{ > + struct btrfs_ioctl_space_args *sargs = 0; > + int i; > + int ret = 0; > + int e, width; > + u64 total_disk; /* filesystem size == sum of > + disks sizes */ > + u64 total_chunks; /* sum of chunks sizes on disk(s) */ > + u64 total_used; /* logical space used */ > + u64 total_free; /* logical space un-used */ > + double K; > + u64 raid5_used, raid6_used; > + > + if ((sargs = load_space_info(fd, path)) == NULL) { > + ret = -1; > + goto exit; > + } > + > + total_disk = disk_size(path); > + e = errno; > + if (total_disk == 0) { > + fprintf(stderr, > + "ERROR: couldn't get space info on '%s' - %s\n", > + path, strerror(e)); > + > + ret = 19; > + goto exit; > + } > + if (get_raid56_used(fd, &raid5_used, &raid6_used) < 0) { > + fprintf(stderr, > + "ERROR: couldn't get space info on '%s'\n", > + path ); > + ret = 20; > + goto exit; > + } > + > + total_chunks = total_used = total_free = 0; > + > + for (i = 0; i < sargs->total_spaces; i++) { > + float ratio = 1; > + u64 allocated; > + u64 flags = sargs->spaces[i].flags; > + > + /* TODO: the raid5/raid6 ratio depends by the number > + of disk 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; > + > + allocated = sargs->spaces[i].total_bytes * ratio; > + > + total_chunks += allocated; > + total_used += sargs->spaces[i].used_bytes; > + total_free += (sargs->spaces[i].total_bytes - > + sargs->spaces[i].used_bytes); > + > + } > + > + /* add the raid5/6 allocated space */ > + total_chunks += raid5_used + raid6_used; > + > + K = ((double)total_used + (double)total_free) / (double)total_chunks; > + > + if (mode & DF_HUMAN_UNIT) > + width = 9; > + else > + width = 18; > + > + printf("Disk size:\t\t%*s\n", width, > + sla_pretty_sizes(total_disk, mode)); > + printf("Disk allocated:\t\t%*s\n", width, > + sla_pretty_sizes(total_chunks, mode)); > + printf("Disk unallocated:\t%*s\n", width, > + sla_pretty_sizes(total_disk-total_chunks, mode)); > + printf("Used:\t\t\t%*s\n", width, > + sla_pretty_sizes(total_used, mode)); > + printf("Free (Estimated):\t%*s\t(Max: %s, min: %s)\n", > + width, > + sla_pretty_sizes((u64)(K*total_disk-total_used), mode), > + sla_pretty_sizes(total_disk-total_chunks+total_free, mode), > + sla_pretty_sizes((total_disk-total_chunks)/2+total_free, > + mode)); > + printf("Data to disk ratio:\t%*.0f %%\n", > + width-2, K*100); > + > +exit: > + > + string_list_free(); > + if (sargs) > + free(sargs); > + > + return ret; > +} > + > +const char * const cmd_filesystem_df_usage[] = { > + "btrfs filesystem df [-b] <path> [<path>..]", > + "Show space usage information for a mount point(s).", > + "", > + "-b\tSet byte as unit", > + NULL > +}; > + > +int cmd_filesystem_df(int argc, char **argv) > +{ > + > + int flags = DF_HUMAN_UNIT; > + int i, more_than_one = 0; > + > + optind = 1; > + while (1) { > + char c = getopt(argc, argv, "b"); > + if (c < 0) > + break; > + > + switch (c) { > + case 'b': > + flags &= ~DF_HUMAN_UNIT; > + break; > + default: > + usage(cmd_filesystem_df_usage); > + } > + } > + > + if (check_argc_min(argc - optind, 1)) { > + usage(cmd_filesystem_df_usage); > + return 21; > + } > + > + for (i = optind; i < argc ; i++) { > + int r, fd; > + if (more_than_one) > + printf("\n"); > + > + fd = open_file_or_dir(argv[i]); > + if (fd < 0) { > + fprintf(stderr, "ERROR: can't access to '%s'\n", > + argv[1]); > + return 12; > + } > + r = _cmd_disk_free(fd, argv[i], flags); > + close(fd); > + > + if (r) > + return r; > + more_than_one = 1; > + > + } > + > + return 0; > +} > + > diff --git a/cmds-fi-disk_usage.h b/cmds-fi-disk_usage.h > new file mode 100644 > index 0000000..9f68bb3 > --- /dev/null > +++ b/cmds-fi-disk_usage.h > @@ -0,0 +1,25 @@ > +/* > + * Copyright (C) 2007 Oracle. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public > + * License v2 as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License for more details. > + * > + * You should have received a copy of the GNU General Public > + * License along with this program; if not, write to the > + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, > + * Boston, MA 021110-1307, USA. > + */ > + > +#ifndef __CMDS_FI_DISK_USAGE__ > +#define __CMDS_FI_DISK_USAGE__ > + > +extern const char * const cmd_filesystem_df_usage[]; > +int cmd_filesystem_df(int argc, char **argv); > + > +#endif > diff --git a/cmds-filesystem.c b/cmds-filesystem.c > index bdbd2ee..5301dc3 100644 > --- a/cmds-filesystem.c > +++ b/cmds-filesystem.c > @@ -33,6 +33,7 @@ > > #include "commands.h" > #include "btrfslabel.h" > +#include "cmds-fi-disk_usage.h" > > static const char * const filesystem_cmd_group_usage[] = { > "btrfs filesystem [<group>] <command> [<args>]", > @@ -45,128 +46,6 @@ static const char * const cmd_df_usage[] = { > NULL > }; > > -static int cmd_df(int argc, char **argv) > -{ > - struct btrfs_ioctl_space_args *sargs, *sargs_orig; > - u64 count = 0, i; > - int ret; > - int fd; > - int e; > - char *path; > - > - if (check_argc_exact(argc, 2)) > - usage(cmd_df_usage); > - > - path = argv[1]; > - > - fd = open_file_or_dir(path); > - if (fd < 0) { > - fprintf(stderr, "ERROR: can't access to '%s'\n", path); > - return 12; > - } > - > - sargs_orig = sargs = malloc(sizeof(struct btrfs_ioctl_space_args)); > - if (!sargs) > - return -ENOMEM; > - > - sargs->space_slots = 0; > - 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)); > - close(fd); > - free(sargs); > - return ret; > - } > - if (!sargs->total_spaces) { > - close(fd); > - free(sargs); > - return 0; > - } > - > - count = sargs->total_spaces; > - > - sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) + > - (count * sizeof(struct btrfs_ioctl_space_info))); > - if (!sargs) { > - close(fd); > - free(sargs_orig); > - return -ENOMEM; > - } > - > - sargs->space_slots = count; > - 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)); > - close(fd); > - free(sargs); > - return ret; > - } > - > - for (i = 0; i < sargs->total_spaces; i++) { > - char description[80]; > - char *total_bytes; > - char *used_bytes; > - int written = 0; > - u64 flags = sargs->spaces[i].flags; > - > - memset(description, 0, 80); > - > - if (flags & BTRFS_BLOCK_GROUP_DATA) { > - if (flags & BTRFS_BLOCK_GROUP_METADATA) { > - snprintf(description, 14, "%s", > - "Data+Metadata"); > - written += 13; > - } else { > - snprintf(description, 5, "%s", "Data"); > - written += 4; > - } > - } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) { > - snprintf(description, 7, "%s", "System"); > - written += 6; > - } else if (flags & BTRFS_BLOCK_GROUP_METADATA) { > - snprintf(description, 9, "%s", "Metadata"); > - written += 8; > - } > - > - if (flags & BTRFS_BLOCK_GROUP_RAID0) { > - snprintf(description+written, 8, "%s", ", RAID0"); > - written += 7; > - } else if (flags & BTRFS_BLOCK_GROUP_RAID1) { > - snprintf(description+written, 8, "%s", ", RAID1"); > - written += 7; > - } else if (flags & BTRFS_BLOCK_GROUP_DUP) { > - snprintf(description+written, 6, "%s", ", DUP"); > - written += 5; > - } else if (flags & BTRFS_BLOCK_GROUP_RAID10) { > - snprintf(description+written, 9, "%s", ", RAID10"); > - written += 8; > - } else if (flags & BTRFS_BLOCK_GROUP_RAID5) { > - snprintf(description+written, 9, "%s", ", RAID5"); > - written += 7; > - } else if (flags & BTRFS_BLOCK_GROUP_RAID6) { > - snprintf(description+written, 9, "%s", ", RAID6"); > - written += 7; > - } > - > - total_bytes = pretty_sizes(sargs->spaces[i].total_bytes); > - used_bytes = pretty_sizes(sargs->spaces[i].used_bytes); > - printf("%s: total=%s, used=%s\n", description, total_bytes, > - used_bytes); > - } > - close(fd); > - free(sargs); > - > - return 0; > -} > - > static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search) > { > char uuidbuf[37]; > @@ -517,7 +396,7 @@ static int cmd_label(int argc, char **argv) > > const struct cmd_group filesystem_cmd_group = { > filesystem_cmd_group_usage, NULL, { > - { "df", cmd_df, cmd_df_usage, NULL, 0 }, > + { "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 }, > { "show", cmd_show, cmd_show_usage, NULL, 0 }, > { "sync", cmd_sync, cmd_sync_usage, NULL, 0 }, > { "defragment", cmd_defrag, cmd_defrag_usage, NULL, 0 }, > diff --git a/ctree.h b/ctree.h > index 12f8fe3..a029368 100644 > --- a/ctree.h > +++ b/ctree.h > @@ -798,9 +798,22 @@ struct btrfs_csum_item { > #define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4) > #define BTRFS_BLOCK_GROUP_DUP (1ULL << 5) > #define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6) > -#define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7) > -#define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) > +#define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7) > +#define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) > #define BTRFS_BLOCK_GROUP_RESERVED BTRFS_AVAIL_ALLOC_BIT_SINGLE > +#define BTRFS_NR_RAID_TYPES 7 > + > +#define BTRFS_BLOCK_GROUP_TYPE_MASK (BTRFS_BLOCK_GROUP_DATA | \ > + BTRFS_BLOCK_GROUP_SYSTEM | \ > + BTRFS_BLOCK_GROUP_METADATA) > + > +#define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \ > + BTRFS_BLOCK_GROUP_RAID1 | \ > + BTRFS_BLOCK_GROUP_RAID5 | \ > + BTRFS_BLOCK_GROUP_RAID6 | \ > + BTRFS_BLOCK_GROUP_DUP | \ > + BTRFS_BLOCK_GROUP_RAID10) > + > > /* used in struct btrfs_balance_args fields */ > #define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) > diff --git a/utils.c b/utils.c > index f9ee812..029729c 100644 > --- a/utils.c > +++ b/utils.c > @@ -38,6 +38,8 @@ > #include <linux/major.h> > #include <linux/kdev_t.h> > #include <limits.h> > +#include <sys/vfs.h> > + > #include "kerncompat.h" > #include "radix-tree.h" > #include "ctree.h" > @@ -1386,3 +1388,15 @@ int get_fs_info(int fd, char *path, struct > btrfs_ioctl_fs_info_args *fi_args, > > return 0; > } > + > +u64 disk_size(char *path) > +{ > + struct statfs sfs; > + > + if (statfs(path, &sfs) < 0) > + return 0; > + else > + return sfs.f_bsize * sfs.f_blocks; > + > +} > + > diff --git a/utils.h b/utils.h > index bbcaf6a..7974d00 100644 > --- a/utils.h > +++ b/utils.h > @@ -19,6 +19,7 @@ > #ifndef __UTILS__ > #define __UTILS__ > > +#include "kerncompat.h" > #include "ctree.h" > > #define BTRFS_MKFS_SYSTEM_GROUP_SIZE (4 * 1024 * 1024) > @@ -58,4 +59,5 @@ char *__strncpy__null(char *dest, const char *src, size_t > n); > /* Helper to always get proper size of the destination string */ > #define strncpy_null(dest, src) __strncpy__null(dest, src, sizeof(dest)) > > +u64 disk_size(char *path); > #endif > -- > 1.7.10.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html