Commit bf5fc093 authored by Josef Bacik's avatar Josef Bacik

Btrfs: fix the df ioctl to report raid types

The new ENOSPC stuff broke the df ioctl since we no longer create seperate space
info's for each RAID type.  So instead, loop through each space info's raid
lists so we can get the right RAID information which will allow the df ioctl to
tell us RAID types again.  Thanks,
Signed-off-by: default avatarJosef Bacik <josef@redhat.com>
parent a1f76506
...@@ -1879,6 +1879,22 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) ...@@ -1879,6 +1879,22 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
return 0; return 0;
} }
static void get_block_group_info(struct list_head *groups_list,
struct btrfs_ioctl_space_info *space)
{
struct btrfs_block_group_cache *block_group;
space->total_bytes = 0;
space->used_bytes = 0;
space->flags = 0;
list_for_each_entry(block_group, groups_list, list) {
space->flags = block_group->flags;
space->total_bytes += block_group->key.offset;
space->used_bytes +=
btrfs_block_group_used(&block_group->item);
}
}
long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
{ {
struct btrfs_ioctl_space_args space_args; struct btrfs_ioctl_space_args space_args;
...@@ -1887,27 +1903,56 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) ...@@ -1887,27 +1903,56 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
struct btrfs_ioctl_space_info *dest_orig; struct btrfs_ioctl_space_info *dest_orig;
struct btrfs_ioctl_space_info *user_dest; struct btrfs_ioctl_space_info *user_dest;
struct btrfs_space_info *info; struct btrfs_space_info *info;
u64 types[] = {BTRFS_BLOCK_GROUP_DATA,
BTRFS_BLOCK_GROUP_SYSTEM,
BTRFS_BLOCK_GROUP_METADATA,
BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA};
int num_types = 4;
int alloc_size; int alloc_size;
int ret = 0; int ret = 0;
int slot_count = 0; int slot_count = 0;
int i, c;
if (copy_from_user(&space_args, if (copy_from_user(&space_args,
(struct btrfs_ioctl_space_args __user *)arg, (struct btrfs_ioctl_space_args __user *)arg,
sizeof(space_args))) sizeof(space_args)))
return -EFAULT; return -EFAULT;
/* first we count slots */ for (i = 0; i < num_types; i++) {
struct btrfs_space_info *tmp;
info = NULL;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(info, &root->fs_info->space_info, list) list_for_each_entry_rcu(tmp, &root->fs_info->space_info,
slot_count++; list) {
if (tmp->flags == types[i]) {
info = tmp;
break;
}
}
rcu_read_unlock(); rcu_read_unlock();
if (!info)
continue;
down_read(&info->groups_sem);
for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) {
if (!list_empty(&info->block_groups[c]))
slot_count++;
}
up_read(&info->groups_sem);
}
/* space_slots == 0 means they are asking for a count */ /* space_slots == 0 means they are asking for a count */
if (space_args.space_slots == 0) { if (space_args.space_slots == 0) {
space_args.total_spaces = slot_count; space_args.total_spaces = slot_count;
goto out; goto out;
} }
slot_count = min_t(int, space_args.space_slots, slot_count);
alloc_size = sizeof(*dest) * slot_count; alloc_size = sizeof(*dest) * slot_count;
/* we generally have at most 6 or so space infos, one for each raid /* we generally have at most 6 or so space infos, one for each raid
* level. So, a whole page should be more than enough for everyone * level. So, a whole page should be more than enough for everyone
*/ */
...@@ -1921,27 +1966,34 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) ...@@ -1921,27 +1966,34 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
dest_orig = dest; dest_orig = dest;
/* now we have a buffer to copy into */ /* now we have a buffer to copy into */
rcu_read_lock(); for (i = 0; i < num_types; i++) {
list_for_each_entry_rcu(info, &root->fs_info->space_info, list) { struct btrfs_space_info *tmp;
/* make sure we don't copy more than we allocated
* in our buffer
*/
if (slot_count == 0)
break;
slot_count--;
/* make sure userland has enough room in their buffer */ info = NULL;
if (space_args.total_spaces >= space_args.space_slots) rcu_read_lock();
list_for_each_entry_rcu(tmp, &root->fs_info->space_info,
list) {
if (tmp->flags == types[i]) {
info = tmp;
break; break;
}
}
rcu_read_unlock();
space.flags = info->flags; if (!info)
space.total_bytes = info->total_bytes; continue;
space.used_bytes = info->bytes_used; down_read(&info->groups_sem);
for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) {
if (!list_empty(&info->block_groups[c])) {
get_block_group_info(&info->block_groups[c],
&space);
memcpy(dest, &space, sizeof(space)); memcpy(dest, &space, sizeof(space));
dest++; dest++;
space_args.total_spaces++; space_args.total_spaces++;
} }
rcu_read_unlock(); }
up_read(&info->groups_sem);
}
user_dest = (struct btrfs_ioctl_space_info *) user_dest = (struct btrfs_ioctl_space_info *)
(arg + sizeof(struct btrfs_ioctl_space_args)); (arg + sizeof(struct btrfs_ioctl_space_args));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment