diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 0e92e5763005..55a7283a9e18 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -3390,6 +3390,183 @@ out: | |||
3390 | return ret; | 3390 | return ret; |
3391 | } | 3391 | } |
3392 | 3392 | ||
3393 | static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg) | ||
3394 | { | ||
3395 | struct btrfs_ioctl_quota_ctl_args *sa; | ||
3396 | struct btrfs_trans_handle *trans = NULL; | ||
3397 | int ret; | ||
3398 | int err; | ||
3399 | |||
3400 | if (!capable(CAP_SYS_ADMIN)) | ||
3401 | return -EPERM; | ||
3402 | |||
3403 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
3404 | return -EROFS; | ||
3405 | |||
3406 | sa = memdup_user(arg, sizeof(*sa)); | ||
3407 | if (IS_ERR(sa)) | ||
3408 | return PTR_ERR(sa); | ||
3409 | |||
3410 | if (sa->cmd != BTRFS_QUOTA_CTL_RESCAN) { | ||
3411 | trans = btrfs_start_transaction(root, 2); | ||
3412 | if (IS_ERR(trans)) { | ||
3413 | ret = PTR_ERR(trans); | ||
3414 | goto out; | ||
3415 | } | ||
3416 | } | ||
3417 | |||
3418 | switch (sa->cmd) { | ||
3419 | case BTRFS_QUOTA_CTL_ENABLE: | ||
3420 | ret = btrfs_quota_enable(trans, root->fs_info); | ||
3421 | break; | ||
3422 | case BTRFS_QUOTA_CTL_DISABLE: | ||
3423 | ret = btrfs_quota_disable(trans, root->fs_info); | ||
3424 | break; | ||
3425 | case BTRFS_QUOTA_CTL_RESCAN: | ||
3426 | ret = btrfs_quota_rescan(root->fs_info); | ||
3427 | break; | ||
3428 | default: | ||
3429 | ret = -EINVAL; | ||
3430 | break; | ||
3431 | } | ||
3432 | |||
3433 | if (copy_to_user(arg, sa, sizeof(*sa))) | ||
3434 | ret = -EFAULT; | ||
3435 | |||
3436 | if (trans) { | ||
3437 | err = btrfs_commit_transaction(trans, root); | ||
3438 | if (err && !ret) | ||
3439 | ret = err; | ||
3440 | } | ||
3441 | |||
3442 | out: | ||
3443 | kfree(sa); | ||
3444 | return ret; | ||
3445 | } | ||
3446 | |||
3447 | static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg) | ||
3448 | { | ||
3449 | struct btrfs_ioctl_qgroup_assign_args *sa; | ||
3450 | struct btrfs_trans_handle *trans; | ||
3451 | int ret; | ||
3452 | int err; | ||
3453 | |||
3454 | if (!capable(CAP_SYS_ADMIN)) | ||
3455 | return -EPERM; | ||
3456 | |||
3457 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
3458 | return -EROFS; | ||
3459 | |||
3460 | sa = memdup_user(arg, sizeof(*sa)); | ||
3461 | if (IS_ERR(sa)) | ||
3462 | return PTR_ERR(sa); | ||
3463 | |||
3464 | trans = btrfs_join_transaction(root); | ||
3465 | if (IS_ERR(trans)) { | ||
3466 | ret = PTR_ERR(trans); | ||
3467 | goto out; | ||
3468 | } | ||
3469 | |||
3470 | /* FIXME: check if the IDs really exist */ | ||
3471 | if (sa->assign) { | ||
3472 | ret = btrfs_add_qgroup_relation(trans, root->fs_info, | ||
3473 | sa->src, sa->dst); | ||
3474 | } else { | ||
3475 | ret = btrfs_del_qgroup_relation(trans, root->fs_info, | ||
3476 | sa->src, sa->dst); | ||
3477 | } | ||
3478 | |||
3479 | err = btrfs_end_transaction(trans, root); | ||
3480 | if (err && !ret) | ||
3481 | ret = err; | ||
3482 | |||
3483 | out: | ||
3484 | kfree(sa); | ||
3485 | return ret; | ||
3486 | } | ||
3487 | |||
3488 | static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg) | ||
3489 | { | ||
3490 | struct btrfs_ioctl_qgroup_create_args *sa; | ||
3491 | struct btrfs_trans_handle *trans; | ||
3492 | int ret; | ||
3493 | int err; | ||
3494 | |||
3495 | if (!capable(CAP_SYS_ADMIN)) | ||
3496 | return -EPERM; | ||
3497 | |||
3498 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
3499 | return -EROFS; | ||
3500 | |||
3501 | sa = memdup_user(arg, sizeof(*sa)); | ||
3502 | if (IS_ERR(sa)) | ||
3503 | return PTR_ERR(sa); | ||
3504 | |||
3505 | trans = btrfs_join_transaction(root); | ||
3506 | if (IS_ERR(trans)) { | ||
3507 | ret = PTR_ERR(trans); | ||
3508 | goto out; | ||
3509 | } | ||
3510 | |||
3511 | /* FIXME: check if the IDs really exist */ | ||
3512 | if (sa->create) { | ||
3513 | ret = btrfs_create_qgroup(trans, root->fs_info, sa->qgroupid, | ||
3514 | NULL); | ||
3515 | } else { | ||
3516 | ret = btrfs_remove_qgroup(trans, root->fs_info, sa->qgroupid); | ||
3517 | } | ||
3518 | |||
3519 | err = btrfs_end_transaction(trans, root); | ||
3520 | if (err && !ret) | ||
3521 | ret = err; | ||
3522 | |||
3523 | out: | ||
3524 | kfree(sa); | ||
3525 | return ret; | ||
3526 | } | ||
3527 | |||
3528 | static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg) | ||
3529 | { | ||
3530 | struct btrfs_ioctl_qgroup_limit_args *sa; | ||
3531 | struct btrfs_trans_handle *trans; | ||
3532 | int ret; | ||
3533 | int err; | ||
3534 | u64 qgroupid; | ||
3535 | |||
3536 | if (!capable(CAP_SYS_ADMIN)) | ||
3537 | return -EPERM; | ||
3538 | |||
3539 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
3540 | return -EROFS; | ||
3541 | |||
3542 | sa = memdup_user(arg, sizeof(*sa)); | ||
3543 | if (IS_ERR(sa)) | ||
3544 | return PTR_ERR(sa); | ||
3545 | |||
3546 | trans = btrfs_join_transaction(root); | ||
3547 | if (IS_ERR(trans)) { | ||
3548 | ret = PTR_ERR(trans); | ||
3549 | goto out; | ||
3550 | } | ||
3551 | |||
3552 | qgroupid = sa->qgroupid; | ||
3553 | if (!qgroupid) { | ||
3554 | /* take the current subvol as qgroup */ | ||
3555 | qgroupid = root->root_key.objectid; | ||
3556 | } | ||
3557 | |||
3558 | /* FIXME: check if the IDs really exist */ | ||
3559 | ret = btrfs_limit_qgroup(trans, root->fs_info, qgroupid, &sa->lim); | ||
3560 | |||
3561 | err = btrfs_end_transaction(trans, root); | ||
3562 | if (err && !ret) | ||
3563 | ret = err; | ||
3564 | |||
3565 | out: | ||
3566 | kfree(sa); | ||
3567 | return ret; | ||
3568 | } | ||
3569 | |||
3393 | long btrfs_ioctl(struct file *file, unsigned int | 3570 | long btrfs_ioctl(struct file *file, unsigned int |
3394 | cmd, unsigned long arg) | 3571 | cmd, unsigned long arg) |
3395 | { | 3572 | { |
@@ -3476,6 +3653,14 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3476 | return btrfs_ioctl_get_dev_stats(root, argp, 0); | 3653 | return btrfs_ioctl_get_dev_stats(root, argp, 0); |
3477 | case BTRFS_IOC_GET_AND_RESET_DEV_STATS: | 3654 | case BTRFS_IOC_GET_AND_RESET_DEV_STATS: |
3478 | return btrfs_ioctl_get_dev_stats(root, argp, 1); | 3655 | return btrfs_ioctl_get_dev_stats(root, argp, 1); |
3656 | case BTRFS_IOC_QUOTA_CTL: | ||
3657 | return btrfs_ioctl_quota_ctl(root, argp); | ||
3658 | case BTRFS_IOC_QGROUP_ASSIGN: | ||
3659 | return btrfs_ioctl_qgroup_assign(root, argp); | ||
3660 | case BTRFS_IOC_QGROUP_CREATE: | ||
3661 | return btrfs_ioctl_qgroup_create(root, argp); | ||
3662 | case BTRFS_IOC_QGROUP_LIMIT: | ||
3663 | return btrfs_ioctl_qgroup_limit(root, argp); | ||
3479 | } | 3664 | } |
3480 | 3665 | ||
3481 | return -ENOTTY; | 3666 | return -ENOTTY; |