Commit c5739bba authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse

Btrfs: snapshot progress

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 0f7d52f4
......@@ -227,7 +227,7 @@ struct btrfs_csum_item {
} __attribute__ ((__packed__));
struct btrfs_inode_map_item {
struct btrfs_disk_key key;
u32 refs;
} __attribute__ ((__packed__));
struct crypto_hash;
......@@ -883,6 +883,17 @@ static inline void btrfs_set_file_extent_num_blocks(struct
e->num_blocks = cpu_to_le64(val);
}
static inline u32 btrfs_inode_map_refs(struct btrfs_inode_map_item *m)
{
return le32_to_cpu(m->refs);
}
static inline void btrfs_set_inode_map_refs(struct btrfs_inode_map_item *m,
u32 val)
{
m->refs = cpu_to_le32(val);
}
static inline struct btrfs_root *btrfs_sb(struct super_block *sb)
{
return sb->s_fs_info;
......@@ -925,6 +936,8 @@ static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh)
btrfs_item_offset((leaf)->items + (slot))))
/* extent-item.c */
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_alloc_extent(struct btrfs_trans_handle *trans, struct btrfs_root
......
......@@ -55,12 +55,14 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_dir_flags(dir_item, 0);
btrfs_set_dir_name_len(dir_item, name_len);
name_ptr = (char *)(dir_item + 1);
btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
btrfs_mark_buffer_dirty(path->nodes[0]);
/* FIXME, use some real flag for selecting the extra index */
if (root == root->fs_info->tree_root)
goto out;
btrfs_memcpy(root, path->nodes[0]->b_data, name_ptr, name, name_len);
btrfs_mark_buffer_dirty(path->nodes[0]);
btrfs_release_path(root, path);
btrfs_set_key_type(&key, BTRFS_DIR_INDEX_KEY);
......
......@@ -16,10 +16,6 @@ static int check_tree_block(struct btrfs_root *root, struct buffer_head *buf)
if (buf->b_blocknr != btrfs_header_blocknr(&node->header)) {
BUG();
}
if (root->node && btrfs_header_parentid(&node->header) !=
btrfs_header_parentid(btrfs_buffer_header(root->node))) {
BUG();
}
return 0;
}
......
......@@ -77,6 +77,12 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
return 0;
}
int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
return inc_block_ref(trans, root, root->node->b_blocknr, 1);
}
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct buffer_head *buf)
{
......
#ifndef __IOCTL_
#define __IOCTL_
#include <linux/ioctl.h>
#define BTRFS_IOCTL_MAGIC 0x94
#define BTRFS_VOL_NAME_MAX 255
struct btrfs_ioctl_vol_args {
char name[BTRFS_VOL_NAME_MAX + 1];
};
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args)
#endif
......@@ -83,6 +83,8 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
{
struct btrfs_path *path;
int ret;
u32 refs;
struct btrfs_root_item *ri;
path = btrfs_alloc_path();
BUG_ON(!path);
......@@ -91,7 +93,19 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
if (ret < 0)
goto out;
BUG_ON(ret != 0);
ri = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]),
path->slots[0], struct btrfs_root_item);
refs = btrfs_root_refs(ri);
BUG_ON(refs == 0);
if (refs == 1) {
ret = btrfs_del_item(trans, root, path);
printk("deleting root %Lu %Lu %u\n", key->objectid, key->offset, key->flags);
} else {
btrfs_set_root_refs(ri, refs - 1);
printk("ref now %u root %Lu %Lu %u\n", refs -1, key->objectid, key->offset, key->flags);
mark_buffer_dirty(path->nodes[0]);
}
out:
btrfs_release_path(root, path);
btrfs_free_path(path);
......
......@@ -15,6 +15,7 @@
#include "disk-io.h"
#include "transaction.h"
#include "btrfs_inode.h"
#include "ioctl.h"
void btrfs_fsinfo_release(struct kobject *obj)
{
......@@ -27,6 +28,11 @@ struct kobj_type btrfs_fsinfo_ktype = {
.release = btrfs_fsinfo_release,
};
struct btrfs_iget_args {
u64 ino;
struct btrfs_root *root;
};
decl_subsys(btrfs, &btrfs_fsinfo_ktype, NULL);
#define BTRFS_SUPER_MAGIC 0x9123682E
......@@ -461,6 +467,34 @@ int fixup_tree_root_location(struct btrfs_root *root,
return 0;
}
int btrfs_init_locked_inode(struct inode *inode, void *p)
{
struct btrfs_iget_args *args = p;
inode->i_ino = args->ino;
BTRFS_I(inode)->root = args->root;
return 0;
}
int btrfs_find_actor(struct inode *inode, void *opaque)
{
struct btrfs_iget_args *args = opaque;
return (args->ino == inode->i_ino &&
args->root == BTRFS_I(inode)->root);
}
struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
struct btrfs_root *root)
{
struct inode *inode;
struct btrfs_iget_args args;
args.ino = objectid;
args.root = root;
inode = iget5_locked(s, objectid, btrfs_find_actor,
btrfs_init_locked_inode,
(void *)&args);
return inode;
}
static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
......@@ -486,7 +520,8 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(ret);
if (ret > 0)
return ERR_PTR(-ENOENT);
inode = iget_locked(dir->i_sb, location.objectid);
inode = btrfs_iget_locked(dir->i_sb, location.objectid,
sub_root);
if (!inode)
return ERR_PTR(-EACCES);
if (inode->i_state & I_NEW) {
......@@ -495,7 +530,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
&root->fs_info->fs_roots_radix,
(unsigned long)sub_root,
sub_root);
printk("adding new root for inode %lu\n", inode->i_ino);
printk("adding new root for inode %lu root %p (found %p)\n", inode->i_ino, sub_root, BTRFS_I(inode)->root);
igrab(inode);
sub_root->inode = inode;
}
......@@ -630,7 +665,8 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
btrfs_super_total_blocks(disk_super),
btrfs_super_root_dir(disk_super));
inode = iget_locked(sb, btrfs_super_root_dir(disk_super));
inode = btrfs_iget_locked(sb, btrfs_super_root_dir(disk_super),
tree_root);
bi = BTRFS_I(inode);
bi->location.objectid = inode->i_ino;
bi->location.offset = 0;
......@@ -750,7 +786,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
inode->i_mode = mode;
inode->i_ino = objectid;
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
fill_inode_item(&inode_item, inode);
key->objectid = objectid;
......@@ -1650,6 +1686,95 @@ static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
return retval;
}
static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
{
struct btrfs_trans_handle *trans;
struct btrfs_key key;
struct btrfs_root_item new_root_item;
int ret;
u64 objectid;
mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
BUG_ON(!trans);
ret = btrfs_update_inode(trans, root, root->inode);
BUG_ON(ret);
ret = btrfs_find_free_objectid(trans, root, 0, &objectid);
BUG_ON(ret);
memset(&new_root_item, 0, sizeof(new_root_item));
memcpy(&new_root_item, &root->root_item,
sizeof(new_root_item));
key.objectid = objectid;
key.flags = 0;
key.offset = 0;
btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
ret = btrfs_insert_inode_map(trans, root, objectid, &key);
BUG_ON(ret);
key.objectid = objectid;
key.offset = 1;
key.flags = 0;
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
btrfs_set_root_blocknr(&new_root_item, root->node->b_blocknr);
ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
&new_root_item);
BUG_ON(ret);
printk("adding snapshot name %.*s root %Lu %Lu %u\n", namelen, name, key.objectid, key.offset, key.flags);
/*
* insert the directory item
*/
key.offset = (u64)-1;
ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
name, namelen,
root->fs_info->sb->s_root->d_inode->i_ino,
&key, 0);
BUG_ON(ret);
ret = btrfs_inc_root_ref(trans, root);
BUG_ON(ret);
ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret);
mutex_unlock(&root->fs_info->fs_mutex);
return 0;
}
static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int
cmd, unsigned long arg)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_ioctl_vol_args vol_args;
int ret;
int namelen;
if (!root->ref_cows)
return -EINVAL;
switch (cmd) {
case BTRFS_IOC_SNAP_CREATE:
if (copy_from_user(&vol_args,
(struct btrfs_ioctl_vol_args __user *)arg,
sizeof(vol_args)))
return -EFAULT;
namelen = strlen(vol_args.name);
if (namelen > BTRFS_VOL_NAME_MAX)
return -EINVAL;
ret = create_snapshot(root, vol_args.name, namelen);
WARN_ON(ret);
break;
default:
return -ENOTTY;
}
return 0;
}
static struct kmem_cache *btrfs_inode_cachep;
struct kmem_cache *btrfs_trans_handle_cachep;
struct kmem_cache *btrfs_transaction_cachep;
......@@ -1781,6 +1906,7 @@ static struct file_operations btrfs_dir_file_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = btrfs_readdir,
.ioctl = btrfs_ioctl,
};
static struct address_space_operations btrfs_aops = {
......@@ -1803,6 +1929,7 @@ static struct file_operations btrfs_file_operations = {
.write = btrfs_file_write,
.mmap = generic_file_mmap,
.open = generic_file_open,
.ioctl = btrfs_ioctl,
};
static int __init init_btrfs_fs(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment