diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index c6044733198d..7875a75315d0 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1579,6 +1579,79 @@ out: | |||
1579 | return ret; | 1579 | return ret; |
1580 | } | 1580 | } |
1581 | 1581 | ||
1582 | static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | ||
1583 | { | ||
1584 | struct inode *inode = fdentry(file)->d_inode; | ||
1585 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1586 | struct btrfs_root *new_root; | ||
1587 | struct btrfs_dir_item *di; | ||
1588 | struct btrfs_trans_handle *trans; | ||
1589 | struct btrfs_path *path; | ||
1590 | struct btrfs_key location; | ||
1591 | struct btrfs_disk_key disk_key; | ||
1592 | struct btrfs_super_block *disk_super; | ||
1593 | u64 features; | ||
1594 | u64 objectid = 0; | ||
1595 | u64 dir_id; | ||
1596 | |||
1597 | if (!capable(CAP_SYS_ADMIN)) | ||
1598 | return -EPERM; | ||
1599 | |||
1600 | if (copy_from_user(&objectid, argp, sizeof(objectid))) | ||
1601 | return -EFAULT; | ||
1602 | |||
1603 | if (!objectid) | ||
1604 | objectid = root->root_key.objectid; | ||
1605 | |||
1606 | location.objectid = objectid; | ||
1607 | location.type = BTRFS_ROOT_ITEM_KEY; | ||
1608 | location.offset = (u64)-1; | ||
1609 | |||
1610 | new_root = btrfs_read_fs_root_no_name(root->fs_info, &location); | ||
1611 | if (IS_ERR(new_root)) | ||
1612 | return PTR_ERR(new_root); | ||
1613 | |||
1614 | if (btrfs_root_refs(&new_root->root_item) == 0) | ||
1615 | return -ENOENT; | ||
1616 | |||
1617 | path = btrfs_alloc_path(); | ||
1618 | if (!path) | ||
1619 | return -ENOMEM; | ||
1620 | path->leave_spinning = 1; | ||
1621 | |||
1622 | trans = btrfs_start_transaction(root, 1); | ||
1623 | if (!trans) { | ||
1624 | btrfs_free_path(path); | ||
1625 | return -ENOMEM; | ||
1626 | } | ||
1627 | |||
1628 | dir_id = btrfs_super_root_dir(&root->fs_info->super_copy); | ||
1629 | di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path, | ||
1630 | dir_id, "default", 7, 1); | ||
1631 | if (!di) { | ||
1632 | btrfs_free_path(path); | ||
1633 | btrfs_end_transaction(trans, root); | ||
1634 | printk(KERN_ERR "Umm, you don't have the default dir item, " | ||
1635 | "this isn't going to work\n"); | ||
1636 | return -ENOENT; | ||
1637 | } | ||
1638 | |||
1639 | btrfs_cpu_key_to_disk(&disk_key, &new_root->root_key); | ||
1640 | btrfs_set_dir_item_key(path->nodes[0], di, &disk_key); | ||
1641 | btrfs_mark_buffer_dirty(path->nodes[0]); | ||
1642 | btrfs_free_path(path); | ||
1643 | |||
1644 | disk_super = &root->fs_info->super_copy; | ||
1645 | features = btrfs_super_incompat_flags(disk_super); | ||
1646 | if (!(features & BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)) { | ||
1647 | features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL; | ||
1648 | btrfs_set_super_incompat_flags(disk_super, features); | ||
1649 | } | ||
1650 | btrfs_end_transaction(trans, root); | ||
1651 | |||
1652 | return 0; | ||
1653 | } | ||
1654 | |||
1582 | /* | 1655 | /* |
1583 | * there are many ways the trans_start and trans_end ioctls can lead | 1656 | * there are many ways the trans_start and trans_end ioctls can lead |
1584 | * to deadlocks. They should only be used by applications that | 1657 | * to deadlocks. They should only be used by applications that |
@@ -1625,6 +1698,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
1625 | return btrfs_ioctl_snap_create(file, argp, 1); | 1698 | return btrfs_ioctl_snap_create(file, argp, 1); |
1626 | case BTRFS_IOC_SNAP_DESTROY: | 1699 | case BTRFS_IOC_SNAP_DESTROY: |
1627 | return btrfs_ioctl_snap_destroy(file, argp); | 1700 | return btrfs_ioctl_snap_destroy(file, argp); |
1701 | case BTRFS_IOC_DEFAULT_SUBVOL: | ||
1702 | return btrfs_ioctl_default_subvol(file, argp); | ||
1628 | case BTRFS_IOC_DEFRAG: | 1703 | case BTRFS_IOC_DEFRAG: |
1629 | return btrfs_ioctl_defrag(file); | 1704 | return btrfs_ioctl_defrag(file); |
1630 | case BTRFS_IOC_RESIZE: | 1705 | case BTRFS_IOC_RESIZE: |