aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@fusionio.com>2012-07-25 16:11:38 -0400
committerChris Mason <chris.mason@fusionio.com>2012-07-25 16:11:38 -0400
commitb478b2baa37ac99fc04a30809c780dd5dfd43595 (patch)
treebed7af1466e5b1e0b0501eba18f77c804a864d7d /fs/btrfs/ioctl.c
parent67c9684f48ea9cbc5e9b8a1feb3151800e9dcc22 (diff)
parent6f72c7e20dbaea55f04546de69586c84a3654503 (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.c244
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)
336static noinline int create_subvol(struct btrfs_root *root, 336static 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
485static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, 491static 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)
635static noinline int btrfs_mksubvol(struct path *parent, 645static 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
1377static noinline int btrfs_ioctl_snap_create_transid(struct file *file, 1388static 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 }
1428out_drop_write: 1437out_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;
1487out: 1509out:
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
3427static 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
3476out:
3477 kfree(sa);
3478 return ret;
3479}
3480
3481static 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
3517out:
3518 kfree(sa);
3519 return ret;
3520}
3521
3522static 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
3557out:
3558 kfree(sa);
3559 return ret;
3560}
3561
3562static 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
3599out:
3600 kfree(sa);
3601 return ret;
3602}
3603
3404long btrfs_ioctl(struct file *file, unsigned int 3604long 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;