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 /fs/btrfs/super.c | |
parent | 0f7d52f4431c530b4f39c524448c688bb7754de5 (diff) |
Btrfs: snapshot progress
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 135 |
1 files changed, 131 insertions, 4 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3c9236ca889..bbe5cabcb42 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) |