Skip to content

Commit

Permalink
Btrfs: Add data=ordered support
Browse files Browse the repository at this point in the history
This forces file data extents down the disk along with the metadata that
references them.  The current implementation is fairly simple, and just
writes out all of the dirty pages in an inode before the commit.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason committed Sep 25, 2008
1 parent e4204de commit dc17ff8
Show file tree
Hide file tree
Showing 13 changed files with 387 additions and 28 deletions.
2 changes: 1 addition & 1 deletion fs/btrfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ obj-m := btrfs.o
btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
hash.o file-item.o inode-item.o inode-map.o disk-io.o \
transaction.o bit-radix.o inode.o file.o tree-defrag.o \
extent_map.o sysfs.o struct-funcs.o xattr.o acl.o
extent_map.o sysfs.o struct-funcs.o xattr.o acl.o ordered-data.o

#btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
# root-tree.o dir-item.o hash.o file-item.o inode-item.o \
Expand Down
1 change: 1 addition & 0 deletions fs/btrfs/btrfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ struct btrfs_inode {
struct extent_map_tree extent_tree;
struct inode vfs_inode;

u64 ordered_trans;
/*
* transid of the trans_handle that last modified this inode
*/
Expand Down
6 changes: 5 additions & 1 deletion fs/btrfs/ctree.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,9 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct extent_buffer **cow_ret)
{
u64 search_start;
u64 header_trans;
int ret;

if (trans->transaction != root->fs_info->running_transaction) {
printk(KERN_CRIT "trans %Lu running %Lu\n", trans->transid,
root->fs_info->running_transaction->transid);
Expand All @@ -232,7 +234,9 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
root->fs_info->generation);
WARN_ON(1);
}
if (btrfs_header_generation(buf) == trans->transid) {

header_trans = btrfs_header_generation(buf);
if (header_trans == trans->transid) {
*cow_ret = buf;
return 0;
}
Expand Down
7 changes: 4 additions & 3 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
* Boston, MA 021110-1307, USA.
*/

#ifndef __BTRFS__
#define __BTRFS__
#ifndef __BTRFS_CTREE__
#define __BTRFS_CTREE__

#include <linux/version.h>
#include <linux/mm.h>
Expand Down Expand Up @@ -363,7 +363,6 @@ struct btrfs_root {
struct inode *inode;
struct kobject root_kobj;
struct completion kobj_unregister;
struct rw_semaphore snap_sem;
u64 objectid;
u64 last_trans;

Expand Down Expand Up @@ -1142,6 +1141,8 @@ void btrfs_destroy_cachep(void);
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
struct btrfs_root *root);
struct inode *btrfs_ilookup(struct super_block *s, u64 objectid,
u64 root_objectid);
int btrfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to);
struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
Expand Down
16 changes: 15 additions & 1 deletion fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,6 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
memset(&root->root_kobj, 0, sizeof(root->root_kobj));
init_completion(&root->kobj_unregister);
init_rwsem(&root->snap_sem);
root->defrag_running = 0;
root->defrag_level = 0;
root->root_key.objectid = objectid;
Expand Down Expand Up @@ -498,6 +497,21 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
return root;
}

struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
u64 root_objectid)
{
struct btrfs_root *root;

if (root_objectid == BTRFS_ROOT_TREE_OBJECTID)
return fs_info->tree_root;
if (root_objectid == BTRFS_EXTENT_TREE_OBJECTID)
return fs_info->extent_root;

root = radix_tree_lookup(&fs_info->fs_roots_radix,
(unsigned long)root_objectid);
return root;
}

struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
struct btrfs_key *location)
{
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/disk-io.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
u64 bytenr, u32 blocksize);
struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
u64 root_objectid);
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *location,
const char *name, int namelen);
Expand Down
4 changes: 3 additions & 1 deletion fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,9 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
if (btrfs_buffer_uptodate(buf)) {
u64 transid =
root->fs_info->running_transaction->transid;
if (btrfs_header_generation(buf) == transid) {
u64 header_transid =
btrfs_header_generation(buf);
if (header_transid == transid) {
free_extent_buffer(buf);
return 1;
}
Expand Down
5 changes: 2 additions & 3 deletions fs/btrfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "disk-io.h"
#include "transaction.h"
#include "btrfs_inode.h"
#include "ordered-data.h"
#include "ioctl.h"
#include "print-tree.h"

Expand Down Expand Up @@ -329,6 +330,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
root->fs_info->delalloc_bytes += (end_of_last_block + 1 -
start_pos) - existing_delalloc;
spin_unlock(&root->fs_info->delalloc_lock);
btrfs_add_ordered_inode(inode);
} else {
u64 aligned_end;
/* step one, delete the existing extents in this range */
Expand Down Expand Up @@ -724,8 +726,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,

pages = kmalloc(nrptrs * sizeof(struct page *), GFP_KERNEL);

down_read(&BTRFS_I(inode)->root->snap_sem);

mutex_lock(&inode->i_mutex);
first_index = pos >> PAGE_CACHE_SHIFT;
last_index = (pos + count) >> PAGE_CACHE_SHIFT;
Expand Down Expand Up @@ -804,7 +804,6 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
}
out:
mutex_unlock(&inode->i_mutex);
up_read(&BTRFS_I(inode)->root->snap_sem);

out_nolock:
kfree(pages);
Expand Down
46 changes: 30 additions & 16 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
alloc_hint = ins.objectid + ins.offset;
start += cur_alloc_size;
}
btrfs_add_ordered_inode(inode);
out:
btrfs_end_transaction(trans, root);
return ret;
Expand Down Expand Up @@ -367,8 +368,8 @@ void btrfs_read_locked_inode(struct inode *inode)
path = btrfs_alloc_path();
BUG_ON(!path);
mutex_lock(&root->fs_info->fs_mutex);

memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));

ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
if (ret)
goto make_bad;
Expand Down Expand Up @@ -898,7 +899,6 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
if ((offset & (blocksize - 1)) == 0)
goto out;

down_read(&root->snap_sem);
ret = -ENOMEM;
page = grab_cache_page(mapping, index);
if (!page)
Expand All @@ -917,7 +917,6 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)

unlock_page(page);
page_cache_release(page);
up_read(&BTRFS_I(inode)->root->snap_sem);
out:
return ret;
}
Expand Down Expand Up @@ -1146,6 +1145,19 @@ static int btrfs_find_actor(struct inode *inode, void *opaque)
args->root == BTRFS_I(inode)->root);
}

struct inode *btrfs_ilookup(struct super_block *s, u64 objectid,
u64 root_objectid)
{
struct btrfs_iget_args args;
args.ino = objectid;
args.root = btrfs_lookup_fs_root(btrfs_sb(s)->fs_info, root_objectid);

if (!args.root)
return NULL;

return ilookup5(s, objectid, btrfs_find_actor, (void *)&args);
}

struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid,
struct btrfs_root *root)
{
Expand Down Expand Up @@ -1336,7 +1348,6 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir)

d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)];
btrfs_dir_item_key_to_cpu(leaf, di, &location);

over = filldir(dirent, name_ptr, name_len,
found_key.offset,
location.objectid,
Expand Down Expand Up @@ -2054,7 +2065,6 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)

ret = -EINVAL;

down_read(&BTRFS_I(inode)->root->snap_sem);
lock_page(page);
wait_on_page_writeback(page);
size = i_size_read(inode);
Expand All @@ -2075,7 +2085,6 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
ret = btrfs_cow_one_page(inode, page, end);

out_unlock:
up_read(&BTRFS_I(inode)->root->snap_sem);
unlock_page(page);
out:
return ret;
Expand Down Expand Up @@ -2118,7 +2127,7 @@ static int noinline create_subvol(struct btrfs_root *root, char *name,
struct btrfs_root_item root_item;
struct btrfs_inode_item *inode_item;
struct extent_buffer *leaf;
struct btrfs_root *new_root;
struct btrfs_root *new_root = root;
struct inode *inode;
struct inode *dir;
int ret;
Expand Down Expand Up @@ -2230,7 +2239,7 @@ static int noinline create_subvol(struct btrfs_root *root, char *name,
goto fail;
fail:
nr = trans->blocks_used;
err = btrfs_commit_transaction(trans, root);
err = btrfs_commit_transaction(trans, new_root);
if (err && !ret)
ret = err;
fail_commit:
Expand All @@ -2253,17 +2262,16 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
if (!root->ref_cows)
return -EINVAL;

down_write(&root->snap_sem);
freeze_bdev(root->fs_info->sb->s_bdev);
thaw_bdev(root->fs_info->sb->s_bdev, root->fs_info->sb);

mutex_lock(&root->fs_info->fs_mutex);
ret = btrfs_check_free_space(root, 1, 0);
if (ret)
goto fail_unlock;

trans = btrfs_start_transaction(root, 1);
BUG_ON(!trans);
err = btrfs_commit_transaction(trans, root);

trans = btrfs_start_transaction(root, 1);

ret = btrfs_update_inode(trans, root, root->inode);
if (ret)
Expand All @@ -2272,9 +2280,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
ret = btrfs_find_free_objectid(trans, root->fs_info->tree_root,
0, &objectid);
if (ret)
goto fail;

memcpy(&new_root_item, &root->root_item,
goto fail; memcpy(&new_root_item, &root->root_item,
sizeof(new_root_item));

key.objectid = objectid;
Expand All @@ -2285,12 +2291,20 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
btrfs_cow_block(trans, root, root->node, NULL, 0, &tmp);
free_extent_buffer(tmp);

/* write the ordered inodes to force all delayed allocations to
* be filled. Once this is done, we can copy the root
*/
mutex_lock(&root->fs_info->trans_mutex);
btrfs_write_ordered_inodes(trans, root);
mutex_unlock(&root->fs_info->trans_mutex);

btrfs_copy_root(trans, root, root->node, &tmp, objectid);

btrfs_set_root_bytenr(&new_root_item, tmp->start);
btrfs_set_root_level(&new_root_item, btrfs_header_level(tmp));
ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
&new_root_item);
printk("new root %Lu node %Lu\n", objectid, tmp->start);
free_extent_buffer(tmp);
if (ret)
goto fail;
Expand Down Expand Up @@ -2321,7 +2335,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
ret = err;
fail_unlock:
mutex_unlock(&root->fs_info->fs_mutex);
up_write(&root->snap_sem);
btrfs_btree_balance_dirty(root, nr);
return ret;
}
Expand Down Expand Up @@ -2608,6 +2621,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
if (!ei)
return NULL;
ei->last_trans = 0;
ei->ordered_trans = 0;
return &ei->vfs_inode;
}

Expand Down
Loading

0 comments on commit dc17ff8

Please sign in to comment.