Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 188234
b: refs/heads/master
c: 7fde62b
h: refs/heads/master
v: v3
  • Loading branch information
Chris Mason committed Mar 16, 2010
1 parent e988986 commit 0014289
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ce769a2904bf5a9110ef534a7702397e38e2b3e9
refs/heads/master: 7fde62bffb576d384ea49a3aed3403d5609ee5bc
57 changes: 46 additions & 11 deletions trunk/fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1848,39 +1848,74 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
struct btrfs_ioctl_space_args space_args;
struct btrfs_ioctl_space_info space;
struct btrfs_ioctl_space_info *dest;
struct btrfs_ioctl_space_info *dest_orig;
struct btrfs_ioctl_space_info *user_dest;
struct btrfs_space_info *info;
int alloc_size;
int ret = 0;
int slot_count = 0;

if (copy_from_user(&space_args,
(struct btrfs_ioctl_space_args __user *)arg,
sizeof(space_args)))
return -EFAULT;

/* first we count slots */
rcu_read_lock();
list_for_each_entry_rcu(info, &root->fs_info->space_info, list)
slot_count++;
rcu_read_unlock();

/* space_slots == 0 means they are asking for a count */
if (space_args.space_slots == 0) {
space_args.total_spaces = slot_count;
goto out;
}
alloc_size = sizeof(*dest) * slot_count;
/* 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
*/
if (alloc_size > PAGE_CACHE_SIZE)
return -ENOMEM;

space_args.total_spaces = 0;
dest = (struct btrfs_ioctl_space_info *)
(arg + sizeof(struct btrfs_ioctl_space_args));
dest = kmalloc(alloc_size, GFP_NOFS);
if (!dest)
return -ENOMEM;
dest_orig = dest;

/* now we have a buffer to copy into */
rcu_read_lock();
list_for_each_entry_rcu(info, &root->fs_info->space_info, list) {
if (!space_args.space_slots) {
space_args.total_spaces++;
continue;
}
/* 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 */
if (space_args.total_spaces >= space_args.space_slots)
break;

space.flags = info->flags;
space.total_bytes = info->total_bytes;
space.used_bytes = info->bytes_used;
if (copy_to_user(dest, &space, sizeof(space))) {
ret = -EFAULT;
break;
}
memcpy(dest, &space, sizeof(space));
dest++;
space_args.total_spaces++;
}
rcu_read_unlock();

if (copy_to_user(arg, &space_args, sizeof(space_args)))
user_dest = (struct btrfs_ioctl_space_info *)
(arg + sizeof(struct btrfs_ioctl_space_args));

if (copy_to_user(user_dest, dest_orig, alloc_size))
ret = -EFAULT;

kfree(dest_orig);
out:
if (ret == 0 && copy_to_user(arg, &space_args, sizeof(space_args)))
ret = -EFAULT;

return ret;
Expand Down

0 comments on commit 0014289

Please sign in to comment.