diff options
author | Chris Mason <chris.mason@fusionio.com> | 2012-07-25 16:11:38 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-07-25 16:11:38 -0400 |
commit | b478b2baa37ac99fc04a30809c780dd5dfd43595 (patch) | |
tree | bed7af1466e5b1e0b0501eba18f77c804a864d7d /fs/btrfs/ioctl.c | |
parent | 67c9684f48ea9cbc5e9b8a1feb3151800e9dcc22 (diff) | |
parent | 6f72c7e20dbaea55f04546de69586c84a3654503 (diff) |
Merge branch 'qgroup' of git://git.jan-o-sch.net/btrfs-unstable into for-linus
Conflicts:
fs/btrfs/ioctl.c
fs/btrfs/ioctl.h
fs/btrfs/transaction.c
fs/btrfs/transaction.h
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 244 |
1 files changed, 227 insertions, 17 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 17facea6a51c..e54b663fd3aa 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -336,7 +336,8 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | |||
336 | static noinline int create_subvol(struct btrfs_root *root, | 336 | static noinline int create_subvol(struct btrfs_root *root, |
337 | struct dentry *dentry, | 337 | struct dentry *dentry, |
338 | char *name, int namelen, | 338 | char *name, int namelen, |
339 | u64 *async_transid) | 339 | u64 *async_transid, |
340 | struct btrfs_qgroup_inherit **inherit) | ||
340 | { | 341 | { |
341 | struct btrfs_trans_handle *trans; | 342 | struct btrfs_trans_handle *trans; |
342 | struct btrfs_key key; | 343 | struct btrfs_key key; |
@@ -368,6 +369,11 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
368 | if (IS_ERR(trans)) | 369 | if (IS_ERR(trans)) |
369 | return PTR_ERR(trans); | 370 | return PTR_ERR(trans); |
370 | 371 | ||
372 | ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, | ||
373 | inherit ? *inherit : NULL); | ||
374 | if (ret) | ||
375 | goto fail; | ||
376 | |||
371 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, | 377 | leaf = btrfs_alloc_free_block(trans, root, root->leafsize, |
372 | 0, objectid, NULL, 0, 0, 0); | 378 | 0, objectid, NULL, 0, 0, 0); |
373 | if (IS_ERR(leaf)) { | 379 | if (IS_ERR(leaf)) { |
@@ -484,7 +490,7 @@ fail: | |||
484 | 490 | ||
485 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | 491 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, |
486 | char *name, int namelen, u64 *async_transid, | 492 | char *name, int namelen, u64 *async_transid, |
487 | bool readonly) | 493 | bool readonly, struct btrfs_qgroup_inherit **inherit) |
488 | { | 494 | { |
489 | struct inode *inode; | 495 | struct inode *inode; |
490 | struct btrfs_pending_snapshot *pending_snapshot; | 496 | struct btrfs_pending_snapshot *pending_snapshot; |
@@ -502,6 +508,10 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
502 | pending_snapshot->dentry = dentry; | 508 | pending_snapshot->dentry = dentry; |
503 | pending_snapshot->root = root; | 509 | pending_snapshot->root = root; |
504 | pending_snapshot->readonly = readonly; | 510 | pending_snapshot->readonly = readonly; |
511 | if (inherit) { | ||
512 | pending_snapshot->inherit = *inherit; | ||
513 | *inherit = NULL; /* take responsibility to free it */ | ||
514 | } | ||
505 | 515 | ||
506 | trans = btrfs_start_transaction(root->fs_info->extent_root, 5); | 516 | trans = btrfs_start_transaction(root->fs_info->extent_root, 5); |
507 | if (IS_ERR(trans)) { | 517 | if (IS_ERR(trans)) { |
@@ -635,7 +645,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | |||
635 | static noinline int btrfs_mksubvol(struct path *parent, | 645 | static noinline int btrfs_mksubvol(struct path *parent, |
636 | char *name, int namelen, | 646 | char *name, int namelen, |
637 | struct btrfs_root *snap_src, | 647 | struct btrfs_root *snap_src, |
638 | u64 *async_transid, bool readonly) | 648 | u64 *async_transid, bool readonly, |
649 | struct btrfs_qgroup_inherit **inherit) | ||
639 | { | 650 | { |
640 | struct inode *dir = parent->dentry->d_inode; | 651 | struct inode *dir = parent->dentry->d_inode; |
641 | struct dentry *dentry; | 652 | struct dentry *dentry; |
@@ -662,11 +673,11 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
662 | goto out_up_read; | 673 | goto out_up_read; |
663 | 674 | ||
664 | if (snap_src) { | 675 | if (snap_src) { |
665 | error = create_snapshot(snap_src, dentry, | 676 | error = create_snapshot(snap_src, dentry, name, namelen, |
666 | name, namelen, async_transid, readonly); | 677 | async_transid, readonly, inherit); |
667 | } else { | 678 | } else { |
668 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 679 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
669 | name, namelen, async_transid); | 680 | name, namelen, async_transid, inherit); |
670 | } | 681 | } |
671 | if (!error) | 682 | if (!error) |
672 | fsnotify_mkdir(dir, dentry); | 683 | fsnotify_mkdir(dir, dentry); |
@@ -1375,11 +1386,9 @@ out: | |||
1375 | } | 1386 | } |
1376 | 1387 | ||
1377 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | 1388 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, |
1378 | char *name, | 1389 | char *name, unsigned long fd, int subvol, |
1379 | unsigned long fd, | 1390 | u64 *transid, bool readonly, |
1380 | int subvol, | 1391 | struct btrfs_qgroup_inherit **inherit) |
1381 | u64 *transid, | ||
1382 | bool readonly) | ||
1383 | { | 1392 | { |
1384 | struct file *src_file; | 1393 | struct file *src_file; |
1385 | int namelen; | 1394 | int namelen; |
@@ -1403,7 +1412,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
1403 | 1412 | ||
1404 | if (subvol) { | 1413 | if (subvol) { |
1405 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 1414 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
1406 | NULL, transid, readonly); | 1415 | NULL, transid, readonly, inherit); |
1407 | } else { | 1416 | } else { |
1408 | struct inode *src_inode; | 1417 | struct inode *src_inode; |
1409 | src_file = fget(fd); | 1418 | src_file = fget(fd); |
@@ -1422,7 +1431,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
1422 | } | 1431 | } |
1423 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 1432 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
1424 | BTRFS_I(src_inode)->root, | 1433 | BTRFS_I(src_inode)->root, |
1425 | transid, readonly); | 1434 | transid, readonly, inherit); |
1426 | fput(src_file); | 1435 | fput(src_file); |
1427 | } | 1436 | } |
1428 | out_drop_write: | 1437 | out_drop_write: |
@@ -1444,7 +1453,7 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
1444 | 1453 | ||
1445 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | 1454 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
1446 | vol_args->fd, subvol, | 1455 | vol_args->fd, subvol, |
1447 | NULL, false); | 1456 | NULL, false, NULL); |
1448 | 1457 | ||
1449 | kfree(vol_args); | 1458 | kfree(vol_args); |
1450 | return ret; | 1459 | return ret; |
@@ -1458,6 +1467,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
1458 | u64 transid = 0; | 1467 | u64 transid = 0; |
1459 | u64 *ptr = NULL; | 1468 | u64 *ptr = NULL; |
1460 | bool readonly = false; | 1469 | bool readonly = false; |
1470 | struct btrfs_qgroup_inherit *inherit = NULL; | ||
1461 | 1471 | ||
1462 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 1472 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
1463 | if (IS_ERR(vol_args)) | 1473 | if (IS_ERR(vol_args)) |
@@ -1465,7 +1475,8 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
1465 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | 1475 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; |
1466 | 1476 | ||
1467 | if (vol_args->flags & | 1477 | if (vol_args->flags & |
1468 | ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) { | 1478 | ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY | |
1479 | BTRFS_SUBVOL_QGROUP_INHERIT)) { | ||
1469 | ret = -EOPNOTSUPP; | 1480 | ret = -EOPNOTSUPP; |
1470 | goto out; | 1481 | goto out; |
1471 | } | 1482 | } |
@@ -1474,10 +1485,21 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
1474 | ptr = &transid; | 1485 | ptr = &transid; |
1475 | if (vol_args->flags & BTRFS_SUBVOL_RDONLY) | 1486 | if (vol_args->flags & BTRFS_SUBVOL_RDONLY) |
1476 | readonly = true; | 1487 | readonly = true; |
1488 | if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) { | ||
1489 | if (vol_args->size > PAGE_CACHE_SIZE) { | ||
1490 | ret = -EINVAL; | ||
1491 | goto out; | ||
1492 | } | ||
1493 | inherit = memdup_user(vol_args->qgroup_inherit, vol_args->size); | ||
1494 | if (IS_ERR(inherit)) { | ||
1495 | ret = PTR_ERR(inherit); | ||
1496 | goto out; | ||
1497 | } | ||
1498 | } | ||
1477 | 1499 | ||
1478 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | 1500 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
1479 | vol_args->fd, subvol, | 1501 | vol_args->fd, subvol, ptr, |
1480 | ptr, readonly); | 1502 | readonly, &inherit); |
1481 | 1503 | ||
1482 | if (ret == 0 && ptr && | 1504 | if (ret == 0 && ptr && |
1483 | copy_to_user(arg + | 1505 | copy_to_user(arg + |
@@ -1486,6 +1508,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
1486 | ret = -EFAULT; | 1508 | ret = -EFAULT; |
1487 | out: | 1509 | out: |
1488 | kfree(vol_args); | 1510 | kfree(vol_args); |
1511 | kfree(inherit); | ||
1489 | return ret; | 1512 | return ret; |
1490 | } | 1513 | } |
1491 | 1514 | ||
@@ -3401,6 +3424,183 @@ out: | |||
3401 | return ret; | 3424 | return ret; |
3402 | } | 3425 | } |
3403 | 3426 | ||
3427 | static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg) | ||
3428 | { | ||
3429 | struct btrfs_ioctl_quota_ctl_args *sa; | ||
3430 | struct btrfs_trans_handle *trans = NULL; | ||
3431 | int ret; | ||
3432 | int err; | ||
3433 | |||
3434 | if (!capable(CAP_SYS_ADMIN)) | ||
3435 | return -EPERM; | ||
3436 | |||
3437 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
3438 | return -EROFS; | ||
3439 | |||
3440 | sa = memdup_user(arg, sizeof(*sa)); | ||
3441 | if (IS_ERR(sa)) | ||
3442 | return PTR_ERR(sa); | ||
3443 | |||
3444 | if (sa->cmd != BTRFS_QUOTA_CTL_RESCAN) { | ||
3445 | trans = btrfs_start_transaction(root, 2); | ||
3446 | if (IS_ERR(trans)) { | ||
3447 | ret = PTR_ERR(trans); | ||
3448 | goto out; | ||
3449 | } | ||
3450 | } | ||
3451 | |||
3452 | switch (sa->cmd) { | ||
3453 | case BTRFS_QUOTA_CTL_ENABLE: | ||
3454 | ret = btrfs_quota_enable(trans, root->fs_info); | ||
3455 | break; | ||
3456 | case BTRFS_QUOTA_CTL_DISABLE: | ||
3457 | ret = btrfs_quota_disable(trans, root->fs_info); | ||
3458 | break; | ||
3459 | case BTRFS_QUOTA_CTL_RESCAN: | ||
3460 | ret = btrfs_quota_rescan(root->fs_info); | ||
3461 | break; | ||
3462 | default: | ||
3463 | ret = -EINVAL; | ||
3464 | break; | ||
3465 | } | ||
3466 | |||
3467 | if (copy_to_user(arg, sa, sizeof(*sa))) | ||
3468 | ret = -EFAULT; | ||
3469 | |||
3470 | if (trans) { | ||
3471 | err = btrfs_commit_transaction(trans, root); | ||
3472 | if (err && !ret) | ||
3473 | ret = err; | ||
3474 | } | ||
3475 | |||
3476 | out: | ||
3477 | kfree(sa); | ||
3478 | return ret; | ||
3479 | } | ||
3480 | |||
3481 | static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg) | ||
3482 | { | ||
3483 | struct btrfs_ioctl_qgroup_assign_args *sa; | ||
3484 | struct btrfs_trans_handle *trans; | ||
3485 | int ret; | ||
3486 | int err; | ||
3487 | |||
3488 | if (!capable(CAP_SYS_ADMIN)) | ||
3489 | return -EPERM; | ||
3490 | |||
3491 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
3492 | return -EROFS; | ||
3493 | |||
3494 | sa = memdup_user(arg, sizeof(*sa)); | ||
3495 | if (IS_ERR(sa)) | ||
3496 | return PTR_ERR(sa); | ||
3497 | |||
3498 | trans = btrfs_join_transaction(root); | ||
3499 | if (IS_ERR(trans)) { | ||
3500 | ret = PTR_ERR(trans); | ||
3501 | goto out; | ||
3502 | } | ||
3503 | |||
3504 | /* FIXME: check if the IDs really exist */ | ||
3505 | if (sa->assign) { | ||
3506 | ret = btrfs_add_qgroup_relation(trans, root->fs_info, | ||
3507 | sa->src, sa->dst); | ||
3508 | } else { | ||
3509 | ret = btrfs_del_qgroup_relation(trans, root->fs_info, | ||
3510 | sa->src, sa->dst); | ||
3511 | } | ||
3512 | |||
3513 | err = btrfs_end_transaction(trans, root); | ||
3514 | if (err && !ret) | ||
3515 | ret = err; | ||
3516 | |||
3517 | out: | ||
3518 | kfree(sa); | ||
3519 | return ret; | ||
3520 | } | ||
3521 | |||
3522 | static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg) | ||
3523 | { | ||
3524 | struct btrfs_ioctl_qgroup_create_args *sa; | ||
3525 | struct btrfs_trans_handle *trans; | ||
3526 | int ret; | ||
3527 | int err; | ||
3528 | |||
3529 | if (!capable(CAP_SYS_ADMIN)) | ||
3530 | return -EPERM; | ||
3531 | |||
3532 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
3533 | return -EROFS; | ||
3534 | |||
3535 | sa = memdup_user(arg, sizeof(*sa)); | ||
3536 | if (IS_ERR(sa)) | ||
3537 | return PTR_ERR(sa); | ||
3538 | |||
3539 | trans = btrfs_join_transaction(root); | ||
3540 | if (IS_ERR(trans)) { | ||
3541 | ret = PTR_ERR(trans); | ||
3542 | goto out; | ||
3543 | } | ||
3544 | |||
3545 | /* FIXME: check if the IDs really exist */ | ||
3546 | if (sa->create) { | ||
3547 | ret = btrfs_create_qgroup(trans, root->fs_info, sa->qgroupid, | ||
3548 | NULL); | ||
3549 | } else { | ||
3550 | ret = btrfs_remove_qgroup(trans, root->fs_info, sa->qgroupid); | ||
3551 | } | ||
3552 | |||
3553 | err = btrfs_end_transaction(trans, root); | ||
3554 | if (err && !ret) | ||
3555 | ret = err; | ||
3556 | |||
3557 | out: | ||
3558 | kfree(sa); | ||
3559 | return ret; | ||
3560 | } | ||
3561 | |||
3562 | static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg) | ||
3563 | { | ||
3564 | struct btrfs_ioctl_qgroup_limit_args *sa; | ||
3565 | struct btrfs_trans_handle *trans; | ||
3566 | int ret; | ||
3567 | int err; | ||
3568 | u64 qgroupid; | ||
3569 | |||
3570 | if (!capable(CAP_SYS_ADMIN)) | ||
3571 | return -EPERM; | ||
3572 | |||
3573 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
3574 | return -EROFS; | ||
3575 | |||
3576 | sa = memdup_user(arg, sizeof(*sa)); | ||
3577 | if (IS_ERR(sa)) | ||
3578 | return PTR_ERR(sa); | ||
3579 | |||
3580 | trans = btrfs_join_transaction(root); | ||
3581 | if (IS_ERR(trans)) { | ||
3582 | ret = PTR_ERR(trans); | ||
3583 | goto out; | ||
3584 | } | ||
3585 | |||
3586 | qgroupid = sa->qgroupid; | ||
3587 | if (!qgroupid) { | ||
3588 | /* take the current subvol as qgroup */ | ||
3589 | qgroupid = root->root_key.objectid; | ||
3590 | } | ||
3591 | |||
3592 | /* FIXME: check if the IDs really exist */ | ||
3593 | ret = btrfs_limit_qgroup(trans, root->fs_info, qgroupid, &sa->lim); | ||
3594 | |||
3595 | err = btrfs_end_transaction(trans, root); | ||
3596 | if (err && !ret) | ||
3597 | ret = err; | ||
3598 | |||
3599 | out: | ||
3600 | kfree(sa); | ||
3601 | return ret; | ||
3602 | } | ||
3603 | |||
3404 | long btrfs_ioctl(struct file *file, unsigned int | 3604 | long btrfs_ioctl(struct file *file, unsigned int |
3405 | cmd, unsigned long arg) | 3605 | cmd, unsigned long arg) |
3406 | { | 3606 | { |
@@ -3422,6 +3622,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3422 | return btrfs_ioctl_snap_create_v2(file, argp, 0); | 3622 | return btrfs_ioctl_snap_create_v2(file, argp, 0); |
3423 | case BTRFS_IOC_SUBVOL_CREATE: | 3623 | case BTRFS_IOC_SUBVOL_CREATE: |
3424 | return btrfs_ioctl_snap_create(file, argp, 1); | 3624 | return btrfs_ioctl_snap_create(file, argp, 1); |
3625 | case BTRFS_IOC_SUBVOL_CREATE_V2: | ||
3626 | return btrfs_ioctl_snap_create_v2(file, argp, 1); | ||
3425 | case BTRFS_IOC_SNAP_DESTROY: | 3627 | case BTRFS_IOC_SNAP_DESTROY: |
3426 | return btrfs_ioctl_snap_destroy(file, argp); | 3628 | return btrfs_ioctl_snap_destroy(file, argp); |
3427 | case BTRFS_IOC_SUBVOL_GETFLAGS: | 3629 | case BTRFS_IOC_SUBVOL_GETFLAGS: |
@@ -3485,6 +3687,14 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3485 | return btrfs_ioctl_balance_progress(root, argp); | 3687 | return btrfs_ioctl_balance_progress(root, argp); |
3486 | case BTRFS_IOC_GET_DEV_STATS: | 3688 | case BTRFS_IOC_GET_DEV_STATS: |
3487 | return btrfs_ioctl_get_dev_stats(root, argp); | 3689 | return btrfs_ioctl_get_dev_stats(root, argp); |
3690 | case BTRFS_IOC_QUOTA_CTL: | ||
3691 | return btrfs_ioctl_quota_ctl(root, argp); | ||
3692 | case BTRFS_IOC_QGROUP_ASSIGN: | ||
3693 | return btrfs_ioctl_qgroup_assign(root, argp); | ||
3694 | case BTRFS_IOC_QGROUP_CREATE: | ||
3695 | return btrfs_ioctl_qgroup_create(root, argp); | ||
3696 | case BTRFS_IOC_QGROUP_LIMIT: | ||
3697 | return btrfs_ioctl_qgroup_limit(root, argp); | ||
3488 | } | 3698 | } |
3489 | 3699 | ||
3490 | return -ENOTTY; | 3700 | return -ENOTTY; |