aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h15
-rw-r--r--fs/btrfs/dir-item.c6
-rw-r--r--fs/btrfs/disk-io.c4
-rw-r--r--fs/btrfs/extent-tree.c6
-rw-r--r--fs/btrfs/ioctl.h13
-rw-r--r--fs/btrfs/root-tree.c16
-rw-r--r--fs/btrfs/super.c135
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
229struct btrfs_inode_map_item { 229struct btrfs_inode_map_item {
230 struct btrfs_disk_key key; 230 u32 refs;
231} __attribute__ ((__packed__)); 231} __attribute__ ((__packed__));
232 232
233struct crypto_hash; 233struct 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
886static inline u32 btrfs_inode_map_refs(struct btrfs_inode_map_item *m)
887{
888 return le32_to_cpu(m->refs);
889}
890
891static 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
886static inline struct btrfs_root *btrfs_sb(struct super_block *sb) 897static 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 */
939int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
940 struct btrfs_root *root);
928struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, 941struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
929 struct btrfs_root *root); 942 struct btrfs_root *root);
930int btrfs_alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root 943int 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
80int 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
80int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, 86int 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
7struct 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);
103printk("deleting root %Lu %Lu %u\n", key->objectid, key->offset, key->flags);
104 } else {
105 btrfs_set_root_refs(ri, refs - 1);
106printk("ref now %u root %Lu %Lu %u\n", refs -1, key->objectid, key->offset, key->flags);
107 mark_buffer_dirty(path->nodes[0]);
108 }
95out: 109out:
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
19void btrfs_fsinfo_release(struct kobject *obj) 20void 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
31struct btrfs_iget_args {
32 u64 ino;
33 struct btrfs_root *root;
34};
35
30decl_subsys(btrfs, &btrfs_fsinfo_ktype, NULL); 36decl_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
470int 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
478int 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
485struct 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
465static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, 499static 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);
498printk("adding new root for inode %lu\n", inode->i_ino); 533printk("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
1689static 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
1728printk("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
1750static 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
1653static struct kmem_cache *btrfs_inode_cachep; 1778static struct kmem_cache *btrfs_inode_cachep;
1654struct kmem_cache *btrfs_trans_handle_cachep; 1779struct kmem_cache *btrfs_trans_handle_cachep;
1655struct kmem_cache *btrfs_transaction_cachep; 1780struct 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
1786static struct address_space_operations btrfs_aops = { 1912static 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
1808static int __init init_btrfs_fs(void) 1935static int __init init_btrfs_fs(void)