aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-04-10 16:58:11 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-04-10 16:58:11 -0400
commit2619ba1f0ff9540a9d84683310a1e350b5efde3d (patch)
treeb027c1c51630d215fd40be34a72f7bc308b34652 /fs
parent2932f3ec94ff0212313b8187064f93bcb76ce411 (diff)
Btrfs: subvolumes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/TODO1
-rw-r--r--fs/btrfs/disk-io.c38
-rw-r--r--fs/btrfs/super.c178
-rw-r--r--fs/btrfs/transaction.c8
4 files changed, 182 insertions, 43 deletions
diff --git a/fs/btrfs/TODO b/fs/btrfs/TODO
index 73d4b842a316..4cd11a1b4b32 100644
--- a/fs/btrfs/TODO
+++ b/fs/btrfs/TODO
@@ -8,6 +8,7 @@
8* Check compat and incompat flags on the inode 8* Check compat and incompat flags on the inode
9* Add virtual filesystems, mountable snapshots 9* Add virtual filesystems, mountable snapshots
10* Get rid of struct ctree_path, limiting tree levels held at one time 10* Get rid of struct ctree_path, limiting tree levels held at one time
11* EEXIST for dirs instead of hash overflow
11* Release 12* Release
12* Do real tree locking 13* Do real tree locking
13* Add extent mirroring (backup copies of blocks) 14* Add extent mirroring (backup copies of blocks)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 760fdc9a7664..ff69162829b3 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -301,6 +301,12 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
301 int ret = 0; 301 int ret = 0;
302 302
303printk("read_fs_root looking for %Lu %Lu %u\n", location->objectid, location->offset, location->flags); 303printk("read_fs_root looking for %Lu %Lu %u\n", location->objectid, location->offset, location->flags);
304 root = radix_tree_lookup(&fs_info->fs_roots_radix,
305 (unsigned long)location->objectid);
306 if (root) {
307printk("found %p in cache\n", root);
308 return root;
309 }
304 root = kmalloc(sizeof(*root), GFP_NOFS); 310 root = kmalloc(sizeof(*root), GFP_NOFS);
305 if (!root) { 311 if (!root) {
306printk("failed1\n"); 312printk("failed1\n");
@@ -349,7 +355,8 @@ out:
349insert: 355insert:
350printk("inserting %p\n", root); 356printk("inserting %p\n", root);
351 root->ref_cows = 1; 357 root->ref_cows = 1;
352 ret = radix_tree_insert(&fs_info->fs_roots_radix, (unsigned long)root, 358 ret = radix_tree_insert(&fs_info->fs_roots_radix,
359 (unsigned long)root->root_key.objectid,
353 root); 360 root);
354 if (ret) { 361 if (ret) {
355printk("radix_tree_insert gives us %d\n", ret); 362printk("radix_tree_insert gives us %d\n", ret);
@@ -460,6 +467,20 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
460 return 0; 467 return 0;
461} 468}
462 469
470static int free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
471{
472 radix_tree_delete(&fs_info->fs_roots_radix,
473 (unsigned long)root->root_key.objectid);
474 if (root->inode)
475 iput(root->inode);
476 if (root->node)
477 brelse(root->node);
478 if (root->commit_root)
479 brelse(root->commit_root);
480 kfree(root);
481 return 0;
482}
483
463int del_fs_roots(struct btrfs_fs_info *fs_info) 484int del_fs_roots(struct btrfs_fs_info *fs_info)
464{ 485{
465 int ret; 486 int ret;
@@ -472,19 +493,8 @@ int del_fs_roots(struct btrfs_fs_info *fs_info)
472 ARRAY_SIZE(gang)); 493 ARRAY_SIZE(gang));
473 if (!ret) 494 if (!ret)
474 break; 495 break;
475 for (i = 0; i < ret; i++) { 496 for (i = 0; i < ret; i++)
476 radix_tree_delete(&fs_info->fs_roots_radix, 497 free_fs_root(fs_info, gang[i]);
477 (unsigned long)gang[i]);
478 if (gang[i]->inode)
479 iput(gang[i]->inode);
480 else
481 printk("no inode for root %p\n", gang[i]);
482 if (gang[i]->node)
483 brelse(gang[i]->node);
484 if (gang[i]->commit_root)
485 brelse(gang[i]->commit_root);
486 kfree(gang[i]);
487 }
488 } 498 }
489 return 0; 499 return 0;
490} 500}
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);
502printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_root, BTRFS_I(inode)->root); 498printk("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
725static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, 721static 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
835static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, 836static 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);
862error: 861error:
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
1681static 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
1669static int create_snapshot(struct btrfs_root *root, char *name, int namelen) 1777static 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:
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index f64c1729b0e1..e15a072407bf 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -64,7 +64,8 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
64 if (root != root->fs_info->tree_root && root->last_trans < 64 if (root != root->fs_info->tree_root && root->last_trans <
65 running_trans_id) { 65 running_trans_id) {
66 radix_tree_tag_set(&root->fs_info->fs_roots_radix, 66 radix_tree_tag_set(&root->fs_info->fs_roots_radix,
67 (unsigned long)root, BTRFS_ROOT_TRANS_TAG); 67 (unsigned long)root->root_key.objectid,
68 BTRFS_ROOT_TRANS_TAG);
68 root->commit_root = root->node; 69 root->commit_root = root->node;
69 get_bh(root->node); 70 get_bh(root->node);
70 } 71 }
@@ -171,8 +172,9 @@ int add_dirty_roots(struct btrfs_trans_handle *trans,
171 break; 172 break;
172 for (i = 0; i < ret; i++) { 173 for (i = 0; i < ret; i++) {
173 root = gang[i]; 174 root = gang[i];
174 radix_tree_tag_clear(radix, (unsigned long)root, 175 radix_tree_tag_clear(radix,
175 BTRFS_ROOT_TRANS_TAG); 176 (unsigned long)root->root_key.objectid,
177 BTRFS_ROOT_TRANS_TAG);
176 if (root->commit_root == root->node) { 178 if (root->commit_root == root->node) {
177 WARN_ON(root->node->b_blocknr != 179 WARN_ON(root->node->b_blocknr !=
178 btrfs_root_blocknr(&root->root_item)); 180 btrfs_root_blocknr(&root->root_item));