diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-10 09:27:04 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-10 09:27:04 -0400 |
commit | c5739bba5260a59cebd20a51a55080592c8d3b07 (patch) | |
tree | ff33f7acddcfc60e7395209ff949bb9d90afda32 | |
parent | 0f7d52f4431c530b4f39c524448c688bb7754de5 (diff) |
Btrfs: snapshot progress
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.h | 15 | ||||
-rw-r--r-- | fs/btrfs/dir-item.c | 6 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 4 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 6 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 13 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 16 | ||||
-rw-r--r-- | fs/btrfs/super.c | 135 |
7 files changed, 183 insertions, 12 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 5460030c9e6a..2cbcaaeac9e5 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -227,7 +227,7 @@ struct btrfs_csum_item { | |||
227 | } __attribute__ ((__packed__)); | 227 | } __attribute__ ((__packed__)); |
228 | 228 | ||
229 | struct btrfs_inode_map_item { | 229 | struct btrfs_inode_map_item { |
230 | struct btrfs_disk_key key; | 230 | u32 refs; |
231 | } __attribute__ ((__packed__)); | 231 | } __attribute__ ((__packed__)); |
232 | 232 | ||
233 | struct crypto_hash; | 233 | struct crypto_hash; |
@@ -883,6 +883,17 @@ static inline void btrfs_set_file_extent_num_blocks(struct | |||
883 | e->num_blocks = cpu_to_le64(val); | 883 | e->num_blocks = cpu_to_le64(val); |
884 | } | 884 | } |
885 | 885 | ||
886 | static inline u32 btrfs_inode_map_refs(struct btrfs_inode_map_item *m) | ||
887 | { | ||
888 | return le32_to_cpu(m->refs); | ||
889 | } | ||
890 | |||
891 | static inline void btrfs_set_inode_map_refs(struct btrfs_inode_map_item *m, | ||
892 | u32 val) | ||
893 | { | ||
894 | m->refs = cpu_to_le32(val); | ||
895 | } | ||
896 | |||
886 | static inline struct btrfs_root *btrfs_sb(struct super_block *sb) | 897 | static inline struct btrfs_root *btrfs_sb(struct super_block *sb) |
887 | { | 898 | { |
888 | return sb->s_fs_info; | 899 | return sb->s_fs_info; |
@@ -925,6 +936,8 @@ static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh) | |||
925 | btrfs_item_offset((leaf)->items + (slot)))) | 936 | btrfs_item_offset((leaf)->items + (slot)))) |
926 | 937 | ||
927 | /* extent-item.c */ | 938 | /* extent-item.c */ |
939 | int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, | ||
940 | struct btrfs_root *root); | ||
928 | struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | 941 | struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, |
929 | struct btrfs_root *root); | 942 | struct btrfs_root *root); |
930 | int btrfs_alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root | 943 | int btrfs_alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root |
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 7aed9f015b55..0ba46bc0da9a 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c | |||
@@ -55,12 +55,14 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
55 | btrfs_set_dir_flags(dir_item, 0); | 55 | btrfs_set_dir_flags(dir_item, 0); |
56 | btrfs_set_dir_name_len(dir_item, name_len); | 56 | btrfs_set_dir_name_len(dir_item, name_len); |
57 | name_ptr = (char *)(dir_item + 1); | 57 | name_ptr = (char *)(dir_item + 1); |
58 | |||
59 | btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len); | ||
60 | btrfs_mark_buffer_dirty(path->nodes[0]); | ||
61 | |||
58 | /* FIXME, use some real flag for selecting the extra index */ | 62 | /* FIXME, use some real flag for selecting the extra index */ |
59 | if (root == root->fs_info->tree_root) | 63 | if (root == root->fs_info->tree_root) |
60 | goto out; | 64 | goto out; |
61 | 65 | ||
62 | btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len); | ||
63 | btrfs_mark_buffer_dirty(path->nodes[0]); | ||
64 | btrfs_release_path(root, path); | 66 | btrfs_release_path(root, path); |
65 | 67 | ||
66 | btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); | 68 | btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index b557bdd1e26a..6b097ede80b1 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -16,10 +16,6 @@ static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf) | |||
16 | if (buf->b_blocknr != btrfs_header_blocknr(&node->header)) { | 16 | if (buf->b_blocknr != btrfs_header_blocknr(&node->header)) { |
17 | BUG(); | 17 | BUG(); |
18 | } | 18 | } |
19 | if (root->node && btrfs_header_parentid(&node->header) != | ||
20 | btrfs_header_parentid(btrfs_buffer_header(root->node))) { | ||
21 | BUG(); | ||
22 | } | ||
23 | return 0; | 19 | return 0; |
24 | } | 20 | } |
25 | 21 | ||
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7c21f63f1b93..efc604eea0b0 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -77,6 +77,12 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root | |||
77 | return 0; | 77 | return 0; |
78 | } | 78 | } |
79 | 79 | ||
80 | int btrfs_inc_root_ref(struct btrfs_trans_handle *trans, | ||
81 | struct btrfs_root *root) | ||
82 | { | ||
83 | return inc_block_ref(trans, root, root->node->b_blocknr, 1); | ||
84 | } | ||
85 | |||
80 | int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 86 | int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
81 | struct buffer_head *buf) | 87 | struct buffer_head *buf) |
82 | { | 88 | { |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h new file mode 100644 index 000000000000..201fb3270723 --- /dev/null +++ b/fs/btrfs/ioctl.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef __IOCTL_ | ||
2 | #define __IOCTL_ | ||
3 | #include <linux/ioctl.h> | ||
4 | |||
5 | #define BTRFS_IOCTL_MAGIC 0x94 | ||
6 | #define BTRFS_VOL_NAME_MAX 255 | ||
7 | struct btrfs_ioctl_vol_args { | ||
8 | char name[BTRFS_VOL_NAME_MAX + 1]; | ||
9 | }; | ||
10 | |||
11 | #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ | ||
12 | struct btrfs_ioctl_vol_args) | ||
13 | #endif | ||
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index ddc1c13a5352..72be9836932f 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -83,6 +83,8 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
83 | { | 83 | { |
84 | struct btrfs_path *path; | 84 | struct btrfs_path *path; |
85 | int ret; | 85 | int ret; |
86 | u32 refs; | ||
87 | struct btrfs_root_item *ri; | ||
86 | 88 | ||
87 | path = btrfs_alloc_path(); | 89 | path = btrfs_alloc_path(); |
88 | BUG_ON(!path); | 90 | BUG_ON(!path); |
@@ -91,7 +93,19 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
91 | if (ret < 0) | 93 | if (ret < 0) |
92 | goto out; | 94 | goto out; |
93 | BUG_ON(ret != 0); | 95 | BUG_ON(ret != 0); |
94 | ret = btrfs_del_item(trans, root, path); | 96 | ri = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), |
97 | path->slots[0], struct btrfs_root_item); | ||
98 | |||
99 | refs = btrfs_root_refs(ri); | ||
100 | BUG_ON(refs == 0); | ||
101 | if (refs == 1) { | ||
102 | ret = btrfs_del_item(trans, root, path); | ||
103 | printk("deleting root %Lu %Lu %u\n", key->objectid, key->offset, key->flags); | ||
104 | } else { | ||
105 | btrfs_set_root_refs(ri, refs - 1); | ||
106 | printk("ref now %u root %Lu %Lu %u\n", refs -1, key->objectid, key->offset, key->flags); | ||
107 | mark_buffer_dirty(path->nodes[0]); | ||
108 | } | ||
95 | out: | 109 | out: |
96 | btrfs_release_path(root, path); | 110 | btrfs_release_path(root, path); |
97 | btrfs_free_path(path); | 111 | btrfs_free_path(path); |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3c9236ca889c..bbe5cabcb42e 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "disk-io.h" | 15 | #include "disk-io.h" |
16 | #include "transaction.h" | 16 | #include "transaction.h" |
17 | #include "btrfs_inode.h" | 17 | #include "btrfs_inode.h" |
18 | #include "ioctl.h" | ||
18 | 19 | ||
19 | void btrfs_fsinfo_release(struct kobject *obj) | 20 | void btrfs_fsinfo_release(struct kobject *obj) |
20 | { | 21 | { |
@@ -27,6 +28,11 @@ struct kobj_type btrfs_fsinfo_ktype = { | |||
27 | .release = btrfs_fsinfo_release, | 28 | .release = btrfs_fsinfo_release, |
28 | }; | 29 | }; |
29 | 30 | ||
31 | struct btrfs_iget_args { | ||
32 | u64 ino; | ||
33 | struct btrfs_root *root; | ||
34 | }; | ||
35 | |||
30 | decl_subsys(btrfs, &btrfs_fsinfo_ktype, NULL); | 36 | decl_subsys(btrfs, &btrfs_fsinfo_ktype, NULL); |
31 | 37 | ||
32 | #define BTRFS_SUPER_MAGIC 0x9123682E | 38 | #define BTRFS_SUPER_MAGIC 0x9123682E |
@@ -461,6 +467,34 @@ int fixup_tree_root_location(struct btrfs_root *root, | |||
461 | return 0; | 467 | return 0; |
462 | } | 468 | } |
463 | 469 | ||
470 | int btrfs_init_locked_inode(struct inode *inode, void *p) | ||
471 | { | ||
472 | struct btrfs_iget_args *args = p; | ||
473 | inode->i_ino = args->ino; | ||
474 | BTRFS_I(inode)->root = args->root; | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | int btrfs_find_actor(struct inode *inode, void *opaque) | ||
479 | { | ||
480 | struct btrfs_iget_args *args = opaque; | ||
481 | return (args->ino == inode->i_ino && | ||
482 | args->root == BTRFS_I(inode)->root); | ||
483 | } | ||
484 | |||
485 | struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, | ||
486 | struct btrfs_root *root) | ||
487 | { | ||
488 | struct inode *inode; | ||
489 | struct btrfs_iget_args args; | ||
490 | args.ino = objectid; | ||
491 | args.root = root; | ||
492 | |||
493 | inode = iget5_locked(s, objectid, btrfs_find_actor, | ||
494 | btrfs_init_locked_inode, | ||
495 | (void *)&args); | ||
496 | return inode; | ||
497 | } | ||
464 | 498 | ||
465 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | 499 | static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, |
466 | struct nameidata *nd) | 500 | struct nameidata *nd) |
@@ -486,7 +520,8 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
486 | return ERR_PTR(ret); | 520 | return ERR_PTR(ret); |
487 | if (ret > 0) | 521 | if (ret > 0) |
488 | return ERR_PTR(-ENOENT); | 522 | return ERR_PTR(-ENOENT); |
489 | inode = iget_locked(dir->i_sb, location.objectid); | 523 | inode = btrfs_iget_locked(dir->i_sb, location.objectid, |
524 | sub_root); | ||
490 | if (!inode) | 525 | if (!inode) |
491 | return ERR_PTR(-EACCES); | 526 | return ERR_PTR(-EACCES); |
492 | if (inode->i_state & I_NEW) { | 527 | if (inode->i_state & I_NEW) { |
@@ -495,7 +530,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
495 | &root->fs_info->fs_roots_radix, | 530 | &root->fs_info->fs_roots_radix, |
496 | (unsigned long)sub_root, | 531 | (unsigned long)sub_root, |
497 | sub_root); | 532 | sub_root); |
498 | printk("adding new root for inode %lu\n", inode->i_ino); | 533 | printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_root, BTRFS_I(inode)->root); |
499 | igrab(inode); | 534 | igrab(inode); |
500 | sub_root->inode = inode; | 535 | sub_root->inode = inode; |
501 | } | 536 | } |
@@ -630,7 +665,8 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | |||
630 | btrfs_super_total_blocks(disk_super), | 665 | btrfs_super_total_blocks(disk_super), |
631 | btrfs_super_root_dir(disk_super)); | 666 | btrfs_super_root_dir(disk_super)); |
632 | 667 | ||
633 | inode = iget_locked(sb, btrfs_super_root_dir(disk_super)); | 668 | inode = btrfs_iget_locked(sb, btrfs_super_root_dir(disk_super), |
669 | tree_root); | ||
634 | bi = BTRFS_I(inode); | 670 | bi = BTRFS_I(inode); |
635 | bi->location.objectid = inode->i_ino; | 671 | bi->location.objectid = inode->i_ino; |
636 | bi->location.offset = 0; | 672 | bi->location.offset = 0; |
@@ -750,7 +786,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
750 | inode->i_mode = mode; | 786 | inode->i_mode = mode; |
751 | inode->i_ino = objectid; | 787 | inode->i_ino = objectid; |
752 | inode->i_blocks = 0; | 788 | inode->i_blocks = 0; |
753 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; | 789 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
754 | fill_inode_item(&inode_item, inode); | 790 | fill_inode_item(&inode_item, inode); |
755 | 791 | ||
756 | key->objectid = objectid; | 792 | key->objectid = objectid; |
@@ -1650,6 +1686,95 @@ static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1650 | return retval; | 1686 | return retval; |
1651 | } | 1687 | } |
1652 | 1688 | ||
1689 | static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | ||
1690 | { | ||
1691 | struct btrfs_trans_handle *trans; | ||
1692 | struct btrfs_key key; | ||
1693 | struct btrfs_root_item new_root_item; | ||
1694 | int ret; | ||
1695 | u64 objectid; | ||
1696 | |||
1697 | mutex_lock(&root->fs_info->fs_mutex); | ||
1698 | trans = btrfs_start_transaction(root, 1); | ||
1699 | BUG_ON(!trans); | ||
1700 | |||
1701 | ret = btrfs_update_inode(trans, root, root->inode); | ||
1702 | BUG_ON(ret); | ||
1703 | |||
1704 | ret = btrfs_find_free_objectid(trans, root, 0, &objectid); | ||
1705 | BUG_ON(ret); | ||
1706 | |||
1707 | memset(&new_root_item, 0, sizeof(new_root_item)); | ||
1708 | memcpy(&new_root_item, &root->root_item, | ||
1709 | sizeof(new_root_item)); | ||
1710 | |||
1711 | key.objectid = objectid; | ||
1712 | key.flags = 0; | ||
1713 | key.offset = 0; | ||
1714 | btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY); | ||
1715 | ret = btrfs_insert_inode_map(trans, root, objectid, &key); | ||
1716 | BUG_ON(ret); | ||
1717 | |||
1718 | key.objectid = objectid; | ||
1719 | key.offset = 1; | ||
1720 | key.flags = 0; | ||
1721 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | ||
1722 | btrfs_set_root_blocknr(&new_root_item, root->node->b_blocknr); | ||
1723 | |||
1724 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, | ||
1725 | &new_root_item); | ||
1726 | BUG_ON(ret); | ||
1727 | |||
1728 | printk("adding snapshot name %.*s root %Lu %Lu %u\n", namelen, name, key.objectid, key.offset, key.flags); | ||
1729 | |||
1730 | /* | ||
1731 | * insert the directory item | ||
1732 | */ | ||
1733 | key.offset = (u64)-1; | ||
1734 | ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root, | ||
1735 | name, namelen, | ||
1736 | root->fs_info->sb->s_root->d_inode->i_ino, | ||
1737 | &key, 0); | ||
1738 | |||
1739 | BUG_ON(ret); | ||
1740 | |||
1741 | ret = btrfs_inc_root_ref(trans, root); | ||
1742 | BUG_ON(ret); | ||
1743 | |||
1744 | ret = btrfs_commit_transaction(trans, root); | ||
1745 | BUG_ON(ret); | ||
1746 | mutex_unlock(&root->fs_info->fs_mutex); | ||
1747 | return 0; | ||
1748 | } | ||
1749 | |||
1750 | static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int | ||
1751 | cmd, unsigned long arg) | ||
1752 | { | ||
1753 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1754 | struct btrfs_ioctl_vol_args vol_args; | ||
1755 | int ret; | ||
1756 | int namelen; | ||
1757 | |||
1758 | if (!root->ref_cows) | ||
1759 | return -EINVAL; | ||
1760 | switch (cmd) { | ||
1761 | case BTRFS_IOC_SNAP_CREATE: | ||
1762 | if (copy_from_user(&vol_args, | ||
1763 | (struct btrfs_ioctl_vol_args __user *)arg, | ||
1764 | sizeof(vol_args))) | ||
1765 | return -EFAULT; | ||
1766 | namelen = strlen(vol_args.name); | ||
1767 | if (namelen > BTRFS_VOL_NAME_MAX) | ||
1768 | return -EINVAL; | ||
1769 | ret = create_snapshot(root, vol_args.name, namelen); | ||
1770 | WARN_ON(ret); | ||
1771 | break; | ||
1772 | default: | ||
1773 | return -ENOTTY; | ||
1774 | } | ||
1775 | return 0; | ||
1776 | } | ||
1777 | |||
1653 | static struct kmem_cache *btrfs_inode_cachep; | 1778 | static struct kmem_cache *btrfs_inode_cachep; |
1654 | struct kmem_cache *btrfs_trans_handle_cachep; | 1779 | struct kmem_cache *btrfs_trans_handle_cachep; |
1655 | struct kmem_cache *btrfs_transaction_cachep; | 1780 | struct kmem_cache *btrfs_transaction_cachep; |
@@ -1781,6 +1906,7 @@ static struct file_operations btrfs_dir_file_operations = { | |||
1781 | .llseek = generic_file_llseek, | 1906 | .llseek = generic_file_llseek, |
1782 | .read = generic_read_dir, | 1907 | .read = generic_read_dir, |
1783 | .readdir = btrfs_readdir, | 1908 | .readdir = btrfs_readdir, |
1909 | .ioctl = btrfs_ioctl, | ||
1784 | }; | 1910 | }; |
1785 | 1911 | ||
1786 | static struct address_space_operations btrfs_aops = { | 1912 | static struct address_space_operations btrfs_aops = { |
@@ -1803,6 +1929,7 @@ static struct file_operations btrfs_file_operations = { | |||
1803 | .write = btrfs_file_write, | 1929 | .write = btrfs_file_write, |
1804 | .mmap = generic_file_mmap, | 1930 | .mmap = generic_file_mmap, |
1805 | .open = generic_file_open, | 1931 | .open = generic_file_open, |
1932 | .ioctl = btrfs_ioctl, | ||
1806 | }; | 1933 | }; |
1807 | 1934 | ||
1808 | static int __init init_btrfs_fs(void) | 1935 | static int __init init_btrfs_fs(void) |