aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c75
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
1582static 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: