diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-10 16:58:11 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-10 16:58:11 -0400 |
commit | 2619ba1f0ff9540a9d84683310a1e350b5efde3d (patch) | |
tree | b027c1c51630d215fd40be34a72f7bc308b34652 /fs/btrfs/super.c | |
parent | 2932f3ec94ff0212313b8187064f93bcb76ce411 (diff) |
Btrfs: subvolumes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 178 |
1 files changed, 152 insertions, 26 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index b93d790e7484..84abdde4e301 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -495,10 +495,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
495 | return ERR_PTR(-EACCES); | 495 | return ERR_PTR(-EACCES); |
496 | if (inode->i_state & I_NEW) { | 496 | if (inode->i_state & I_NEW) { |
497 | if (sub_root != root) { | 497 | if (sub_root != root) { |
498 | ret = radix_tree_insert( | ||
499 | &root->fs_info->fs_roots_radix, | ||
500 | (unsigned long)sub_root, | ||
501 | sub_root); | ||
502 | printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_root, BTRFS_I(inode)->root); | 498 | printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_root, BTRFS_I(inode)->root); |
503 | igrab(inode); | 499 | igrab(inode); |
504 | sub_root->inode = inode; | 500 | sub_root->inode = inode; |
@@ -723,22 +719,19 @@ static int btrfs_write_inode(struct inode *inode, int wait) | |||
723 | } | 719 | } |
724 | 720 | ||
725 | static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | 721 | static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, |
726 | struct inode *dir, int mode) | 722 | struct btrfs_root *root, |
723 | u64 objectid, int mode) | ||
727 | { | 724 | { |
728 | struct inode *inode; | 725 | struct inode *inode; |
729 | struct btrfs_inode_item inode_item; | 726 | struct btrfs_inode_item inode_item; |
730 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
731 | struct btrfs_key *location; | 727 | struct btrfs_key *location; |
732 | int ret; | 728 | int ret; |
733 | u64 objectid; | ||
734 | 729 | ||
735 | inode = new_inode(dir->i_sb); | 730 | inode = new_inode(root->fs_info->sb); |
736 | if (!inode) | 731 | if (!inode) |
737 | return ERR_PTR(-ENOMEM); | 732 | return ERR_PTR(-ENOMEM); |
738 | 733 | ||
739 | BTRFS_I(inode)->root = BTRFS_I(dir)->root; | 734 | BTRFS_I(inode)->root = root; |
740 | ret = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); | ||
741 | BUG_ON(ret); | ||
742 | 735 | ||
743 | inode->i_uid = current->fsuid; | 736 | inode->i_uid = current->fsuid; |
744 | inode->i_gid = current->fsgid; | 737 | inode->i_gid = current->fsgid; |
@@ -804,10 +797,18 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, | |||
804 | struct inode *inode; | 797 | struct inode *inode; |
805 | int err; | 798 | int err; |
806 | int drop_inode = 0; | 799 | int drop_inode = 0; |
800 | u64 objectid; | ||
807 | 801 | ||
808 | mutex_lock(&root->fs_info->fs_mutex); | 802 | mutex_lock(&root->fs_info->fs_mutex); |
809 | trans = btrfs_start_transaction(root, 1); | 803 | trans = btrfs_start_transaction(root, 1); |
810 | inode = btrfs_new_inode(trans, dir, mode); | 804 | |
805 | err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); | ||
806 | if (err) { | ||
807 | err = -ENOSPC; | ||
808 | goto out_unlock; | ||
809 | } | ||
810 | |||
811 | inode = btrfs_new_inode(trans, root, objectid, mode); | ||
811 | err = PTR_ERR(inode); | 812 | err = PTR_ERR(inode); |
812 | if (IS_ERR(inode)) | 813 | if (IS_ERR(inode)) |
813 | goto out_unlock; | 814 | goto out_unlock; |
@@ -833,9 +834,9 @@ out_unlock: | |||
833 | } | 834 | } |
834 | 835 | ||
835 | static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, | 836 | static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, |
836 | struct inode *inode, struct inode *dir) | 837 | struct btrfs_root *root, |
838 | u64 objectid, u64 dirid) | ||
837 | { | 839 | { |
838 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
839 | int ret; | 840 | int ret; |
840 | char buf[2]; | 841 | char buf[2]; |
841 | struct btrfs_key key; | 842 | struct btrfs_key key; |
@@ -843,22 +844,20 @@ static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, | |||
843 | buf[0] = '.'; | 844 | buf[0] = '.'; |
844 | buf[1] = '.'; | 845 | buf[1] = '.'; |
845 | 846 | ||
846 | key.objectid = inode->i_ino; | 847 | key.objectid = objectid; |
847 | key.offset = 0; | 848 | key.offset = 0; |
848 | key.flags = 0; | 849 | key.flags = 0; |
849 | btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); | 850 | btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); |
850 | 851 | ||
851 | ret = btrfs_insert_dir_item(trans, root, buf, 1, inode->i_ino, | 852 | ret = btrfs_insert_dir_item(trans, root, buf, 1, objectid, |
852 | &key, 1); | 853 | &key, 1); |
853 | if (ret) | 854 | if (ret) |
854 | goto error; | 855 | goto error; |
855 | key.objectid = dir->i_ino; | 856 | key.objectid = dirid; |
856 | ret = btrfs_insert_dir_item(trans, root, buf, 2, inode->i_ino, | 857 | ret = btrfs_insert_dir_item(trans, root, buf, 2, objectid, |
857 | &key, 1); | 858 | &key, 1); |
858 | if (ret) | 859 | if (ret) |
859 | goto error; | 860 | goto error; |
860 | inode->i_size = 6; | ||
861 | ret = btrfs_update_inode(trans, root, inode); | ||
862 | error: | 861 | error: |
863 | return ret; | 862 | return ret; |
864 | } | 863 | } |
@@ -870,6 +869,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
870 | struct btrfs_root *root = BTRFS_I(dir)->root; | 869 | struct btrfs_root *root = BTRFS_I(dir)->root; |
871 | int err = 0; | 870 | int err = 0; |
872 | int drop_on_err = 0; | 871 | int drop_on_err = 0; |
872 | u64 objectid; | ||
873 | 873 | ||
874 | mutex_lock(&root->fs_info->fs_mutex); | 874 | mutex_lock(&root->fs_info->fs_mutex); |
875 | trans = btrfs_start_transaction(root, 1); | 875 | trans = btrfs_start_transaction(root, 1); |
@@ -877,7 +877,14 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
877 | err = PTR_ERR(trans); | 877 | err = PTR_ERR(trans); |
878 | goto out_unlock; | 878 | goto out_unlock; |
879 | } | 879 | } |
880 | inode = btrfs_new_inode(trans, dir, S_IFDIR | mode); | 880 | |
881 | err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); | ||
882 | if (err) { | ||
883 | err = -ENOSPC; | ||
884 | goto out_unlock; | ||
885 | } | ||
886 | |||
887 | inode = btrfs_new_inode(trans, root, objectid, S_IFDIR | mode); | ||
881 | if (IS_ERR(inode)) { | 888 | if (IS_ERR(inode)) { |
882 | err = PTR_ERR(inode); | 889 | err = PTR_ERR(inode); |
883 | goto out_fail; | 890 | goto out_fail; |
@@ -886,7 +893,12 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
886 | inode->i_op = &btrfs_dir_inode_operations; | 893 | inode->i_op = &btrfs_dir_inode_operations; |
887 | inode->i_fop = &btrfs_dir_file_operations; | 894 | inode->i_fop = &btrfs_dir_file_operations; |
888 | 895 | ||
889 | err = btrfs_make_empty_dir(trans, inode, dir); | 896 | err = btrfs_make_empty_dir(trans, root, inode->i_ino, dir->i_ino); |
897 | if (err) | ||
898 | goto out_fail; | ||
899 | |||
900 | inode->i_size = 6; | ||
901 | err = btrfs_update_inode(trans, root, inode); | ||
890 | if (err) | 902 | if (err) |
891 | goto out_fail; | 903 | goto out_fail; |
892 | err = btrfs_add_link(trans, dentry, inode); | 904 | err = btrfs_add_link(trans, dentry, inode); |
@@ -1666,6 +1678,102 @@ static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1666 | return retval; | 1678 | return retval; |
1667 | } | 1679 | } |
1668 | 1680 | ||
1681 | static int create_subvol(struct btrfs_root *root, char *name, int namelen) | ||
1682 | { | ||
1683 | struct btrfs_trans_handle *trans; | ||
1684 | struct btrfs_key key; | ||
1685 | struct btrfs_root_item root_item; | ||
1686 | struct btrfs_inode_item *inode_item; | ||
1687 | struct buffer_head *subvol; | ||
1688 | struct btrfs_leaf *leaf; | ||
1689 | struct btrfs_root *new_root; | ||
1690 | struct inode *inode; | ||
1691 | int ret; | ||
1692 | u64 objectid; | ||
1693 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; | ||
1694 | |||
1695 | mutex_lock(&root->fs_info->fs_mutex); | ||
1696 | trans = btrfs_start_transaction(root, 1); | ||
1697 | BUG_ON(!trans); | ||
1698 | |||
1699 | subvol = btrfs_alloc_free_block(trans, root); | ||
1700 | leaf = btrfs_buffer_leaf(subvol); | ||
1701 | btrfs_set_header_nritems(&leaf->header, 0); | ||
1702 | btrfs_set_header_level(&leaf->header, 0); | ||
1703 | btrfs_set_header_blocknr(&leaf->header, subvol->b_blocknr); | ||
1704 | btrfs_set_header_generation(&leaf->header, trans->transid); | ||
1705 | memcpy(leaf->header.fsid, root->fs_info->disk_super->fsid, | ||
1706 | sizeof(leaf->header.fsid)); | ||
1707 | |||
1708 | inode_item = &root_item.inode; | ||
1709 | memset(inode_item, 0, sizeof(*inode_item)); | ||
1710 | btrfs_set_inode_generation(inode_item, 1); | ||
1711 | btrfs_set_inode_size(inode_item, 3); | ||
1712 | btrfs_set_inode_nlink(inode_item, 1); | ||
1713 | btrfs_set_inode_nblocks(inode_item, 1); | ||
1714 | btrfs_set_inode_mode(inode_item, S_IFDIR | 0755); | ||
1715 | |||
1716 | btrfs_set_root_blocknr(&root_item, subvol->b_blocknr); | ||
1717 | btrfs_set_root_refs(&root_item, 1); | ||
1718 | |||
1719 | mark_buffer_dirty(subvol); | ||
1720 | brelse(subvol); | ||
1721 | subvol = NULL; | ||
1722 | |||
1723 | ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root, | ||
1724 | 0, &objectid); | ||
1725 | BUG_ON(ret); | ||
1726 | |||
1727 | btrfs_set_root_dirid(&root_item, new_dirid); | ||
1728 | |||
1729 | key.objectid = objectid; | ||
1730 | key.offset = 1; | ||
1731 | key.flags = 0; | ||
1732 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | ||
1733 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
1734 | &root_item); | ||
1735 | BUG_ON(ret); | ||
1736 | |||
1737 | /* | ||
1738 | * insert the directory item | ||
1739 | */ | ||
1740 | key.offset = (u64)-1; | ||
1741 | ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, | ||
1742 | name, namelen, | ||
1743 | root->fs_info->sb->s_root->d_inode->i_ino, | ||
1744 | &key, 0); | ||
1745 | BUG_ON(ret); | ||
1746 | |||
1747 | ret = btrfs_commit_transaction(trans, root); | ||
1748 | BUG_ON(ret); | ||
1749 | |||
1750 | new_root = btrfs_read_fs_root(root->fs_info, &key); | ||
1751 | BUG_ON(!new_root); | ||
1752 | |||
1753 | trans = btrfs_start_transaction(new_root, 1); | ||
1754 | BUG_ON(!trans); | ||
1755 | |||
1756 | inode = btrfs_new_inode(trans, new_root, new_dirid, S_IFDIR | 0700); | ||
1757 | inode->i_op = &btrfs_dir_inode_operations; | ||
1758 | inode->i_fop = &btrfs_dir_file_operations; | ||
1759 | |||
1760 | ret = btrfs_make_empty_dir(trans, new_root, new_dirid, new_dirid); | ||
1761 | BUG_ON(ret); | ||
1762 | |||
1763 | inode->i_nlink = 1; | ||
1764 | inode->i_size = 6; | ||
1765 | ret = btrfs_update_inode(trans, new_root, inode); | ||
1766 | BUG_ON(ret); | ||
1767 | |||
1768 | ret = btrfs_commit_transaction(trans, new_root); | ||
1769 | BUG_ON(ret); | ||
1770 | |||
1771 | iput(inode); | ||
1772 | |||
1773 | mutex_unlock(&root->fs_info->fs_mutex); | ||
1774 | return 0; | ||
1775 | } | ||
1776 | |||
1669 | static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | 1777 | static int create_snapshot(struct btrfs_root *root, char *name, int namelen) |
1670 | { | 1778 | { |
1671 | struct btrfs_trans_handle *trans; | 1779 | struct btrfs_trans_handle *trans; |
@@ -1674,6 +1782,9 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
1674 | int ret; | 1782 | int ret; |
1675 | u64 objectid; | 1783 | u64 objectid; |
1676 | 1784 | ||
1785 | if (!root->ref_cows) | ||
1786 | return -EINVAL; | ||
1787 | |||
1677 | mutex_lock(&root->fs_info->fs_mutex); | 1788 | mutex_lock(&root->fs_info->fs_mutex); |
1678 | trans = btrfs_start_transaction(root, 1); | 1789 | trans = btrfs_start_transaction(root, 1); |
1679 | BUG_ON(!trans); | 1790 | BUG_ON(!trans); |
@@ -1685,7 +1796,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
1685 | 0, &objectid); | 1796 | 0, &objectid); |
1686 | BUG_ON(ret); | 1797 | BUG_ON(ret); |
1687 | 1798 | ||
1688 | memset(&new_root_item, 0, sizeof(new_root_item)); | ||
1689 | memcpy(&new_root_item, &root->root_item, | 1799 | memcpy(&new_root_item, &root->root_item, |
1690 | sizeof(new_root_item)); | 1800 | sizeof(new_root_item)); |
1691 | 1801 | ||
@@ -1728,9 +1838,9 @@ static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int | |||
1728 | struct btrfs_ioctl_vol_args vol_args; | 1838 | struct btrfs_ioctl_vol_args vol_args; |
1729 | int ret; | 1839 | int ret; |
1730 | int namelen; | 1840 | int namelen; |
1841 | struct btrfs_path *path; | ||
1842 | u64 root_dirid; | ||
1731 | 1843 | ||
1732 | if (!root->ref_cows) | ||
1733 | return -EINVAL; | ||
1734 | switch (cmd) { | 1844 | switch (cmd) { |
1735 | case BTRFS_IOC_SNAP_CREATE: | 1845 | case BTRFS_IOC_SNAP_CREATE: |
1736 | if (copy_from_user(&vol_args, | 1846 | if (copy_from_user(&vol_args, |
@@ -1740,7 +1850,23 @@ static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int | |||
1740 | namelen = strlen(vol_args.name); | 1850 | namelen = strlen(vol_args.name); |
1741 | if (namelen > BTRFS_VOL_NAME_MAX) | 1851 | if (namelen > BTRFS_VOL_NAME_MAX) |
1742 | return -EINVAL; | 1852 | return -EINVAL; |
1743 | ret = create_snapshot(root, vol_args.name, namelen); | 1853 | path = btrfs_alloc_path(); |
1854 | if (!path) | ||
1855 | return -ENOMEM; | ||
1856 | root_dirid = btrfs_root_dirid( | ||
1857 | &root->fs_info->tree_root->root_item); | ||
1858 | mutex_lock(&root->fs_info->fs_mutex); | ||
1859 | ret = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, | ||
1860 | path, root_dirid, | ||
1861 | vol_args.name, namelen, 0); | ||
1862 | mutex_unlock(&root->fs_info->fs_mutex); | ||
1863 | if (ret == 0) | ||
1864 | return -EEXIST; | ||
1865 | |||
1866 | if (root == root->fs_info->tree_root) | ||
1867 | ret = create_subvol(root, vol_args.name, namelen); | ||
1868 | else | ||
1869 | ret = create_snapshot(root, vol_args.name, namelen); | ||
1744 | WARN_ON(ret); | 1870 | WARN_ON(ret); |
1745 | break; | 1871 | break; |
1746 | default: | 1872 | default: |