Commit e02119d5 authored by Chris Mason's avatar Chris Mason

Btrfs: Add a write ahead tree log to optimize synchronous operations

File syncs and directory syncs are optimized by copying their
items into a special (copy-on-write) log tree.  There is one log tree per
subvolume and the btrfs super block points to a tree of log tree roots.

After a crash, items are copied out of the log tree and back into the
subvolume.  See tree-log.c for all the details.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent a1b32a59
...@@ -7,8 +7,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ ...@@ -7,8 +7,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
transaction.o bit-radix.o inode.o file.o tree-defrag.o \ transaction.o bit-radix.o inode.o file.o tree-defrag.o \
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
ref-cache.o acl.o export.o ref-cache.o export.o tree-log.o acl.o
else else
# Normal Makefile # Normal Makefile
......
...@@ -33,6 +33,7 @@ struct btrfs_inode { ...@@ -33,6 +33,7 @@ struct btrfs_inode {
struct extent_io_tree io_failure_tree; struct extent_io_tree io_failure_tree;
struct mutex csum_mutex; struct mutex csum_mutex;
struct mutex extent_mutex; struct mutex extent_mutex;
struct mutex log_mutex;
struct inode vfs_inode; struct inode vfs_inode;
struct btrfs_ordered_inode_tree ordered_tree; struct btrfs_ordered_inode_tree ordered_tree;
...@@ -44,10 +45,17 @@ struct btrfs_inode { ...@@ -44,10 +45,17 @@ struct btrfs_inode {
struct list_head delalloc_inodes; struct list_head delalloc_inodes;
/* full 64 bit generation number */
u64 generation;
/* /*
* transid of the trans_handle that last modified this inode * transid of the trans_handle that last modified this inode
*/ */
u64 last_trans; u64 last_trans;
/*
* transid that last logged this inode
*/
u64 logged_trans;
u64 delalloc_bytes; u64 delalloc_bytes;
u64 disk_i_size; u64 disk_i_size;
u32 flags; u32 flags;
......
...@@ -22,6 +22,21 @@ static inline struct dentry *d_obtain_alias(struct inode *inode) ...@@ -22,6 +22,21 @@ static inline struct dentry *d_obtain_alias(struct inode *inode)
} }
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
static inline void btrfs_drop_nlink(struct inode *inode)
{
inode->i_nlink--;
}
static inline void btrfs_inc_nlink(struct inode *inode)
{
inode->i_nlink++;
}
#else
# define btrfs_drop_nlink(inode) drop_nlink(inode)
# define btrfs_inc_nlink(inode) inc_nlink(inode)
#endif
/* /*
* Even if AppArmor isn't enabled, it still has different prototypes. * Even if AppArmor isn't enabled, it still has different prototypes.
* Add more distro/version pairs here to declare which has AppArmor applied. * Add more distro/version pairs here to declare which has AppArmor applied.
......
...@@ -60,7 +60,7 @@ void btrfs_free_path(struct btrfs_path *p) ...@@ -60,7 +60,7 @@ void btrfs_free_path(struct btrfs_path *p)
kmem_cache_free(btrfs_path_cachep, p); kmem_cache_free(btrfs_path_cachep, p);
} }
void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) void noinline btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
{ {
int i; int i;
...@@ -176,7 +176,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, ...@@ -176,7 +176,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
int __btrfs_cow_block(struct btrfs_trans_handle *trans, int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_buffer *buf, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot, struct extent_buffer *parent, int parent_slot,
...@@ -294,7 +294,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -294,7 +294,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
int btrfs_cow_block(struct btrfs_trans_handle *trans, int noinline btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf, struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot, struct extent_buffer *parent, int parent_slot,
struct extent_buffer **cow_ret, u64 prealloc_dest) struct extent_buffer **cow_ret, u64 prealloc_dest)
...@@ -677,9 +677,10 @@ static int noinline check_block(struct btrfs_root *root, ...@@ -677,9 +677,10 @@ static int noinline check_block(struct btrfs_root *root,
* *
* slot may point to max if the key is bigger than all of the keys * slot may point to max if the key is bigger than all of the keys
*/ */
static int generic_bin_search(struct extent_buffer *eb, unsigned long p, static noinline int generic_bin_search(struct extent_buffer *eb,
int item_size, struct btrfs_key *key, unsigned long p,
int max, int *slot) int item_size, struct btrfs_key *key,
int max, int *slot)
{ {
int low = 0; int low = 0;
int high = max; int high = max;
...@@ -765,7 +766,7 @@ static int bin_search(struct extent_buffer *eb, struct btrfs_key *key, ...@@ -765,7 +766,7 @@ static int bin_search(struct extent_buffer *eb, struct btrfs_key *key,
return -1; return -1;
} }
static struct extent_buffer *read_node_slot(struct btrfs_root *root, static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
struct extent_buffer *parent, int slot) struct extent_buffer *parent, int slot)
{ {
int level = btrfs_header_level(parent); int level = btrfs_header_level(parent);
...@@ -781,7 +782,7 @@ static struct extent_buffer *read_node_slot(struct btrfs_root *root, ...@@ -781,7 +782,7 @@ static struct extent_buffer *read_node_slot(struct btrfs_root *root,
btrfs_node_ptr_generation(parent, slot)); btrfs_node_ptr_generation(parent, slot));
} }
static int balance_level(struct btrfs_trans_handle *trans, static noinline int balance_level(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, int level) struct btrfs_path *path, int level)
{ {
...@@ -1128,8 +1129,9 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -1128,8 +1129,9 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
/* /*
* readahead one full node of leaves * readahead one full node of leaves
*/ */
static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, static noinline void reada_for_search(struct btrfs_root *root,
int level, int slot, u64 objectid) struct btrfs_path *path,
int level, int slot, u64 objectid)
{ {
struct extent_buffer *node; struct extent_buffer *node;
struct btrfs_disk_key disk_key; struct btrfs_disk_key disk_key;
...@@ -1201,7 +1203,8 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, ...@@ -1201,7 +1203,8 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
} }
} }
static void unlock_up(struct btrfs_path *path, int level, int lowest_unlock) static noinline void unlock_up(struct btrfs_path *path, int level,
int lowest_unlock)
{ {
int i; int i;
int skip_level = level; int skip_level = level;
...@@ -1759,8 +1762,9 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1759,8 +1762,9 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
* *
* returns 0 on success and < 0 on failure * returns 0 on success and < 0 on failure
*/ */
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root static noinline int split_node(struct btrfs_trans_handle *trans,
*root, struct btrfs_path *path, int level) struct btrfs_root *root,
struct btrfs_path *path, int level)
{ {
u64 root_gen; u64 root_gen;
struct extent_buffer *c; struct extent_buffer *c;
...@@ -1874,7 +1878,8 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr) ...@@ -1874,7 +1878,8 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr)
* the start of the leaf data. IOW, how much room * the start of the leaf data. IOW, how much room
* the leaf has left for both items and data * the leaf has left for both items and data
*/ */
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf) int noinline btrfs_leaf_free_space(struct btrfs_root *root,
struct extent_buffer *leaf)
{ {
int nritems = btrfs_header_nritems(leaf); int nritems = btrfs_header_nritems(leaf);
int ret; int ret;
...@@ -2283,9 +2288,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -2283,9 +2288,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
* *
* returns 0 if all went well and < 0 on failure. * returns 0 if all went well and < 0 on failure.
*/ */
static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root static noinline int split_leaf(struct btrfs_trans_handle *trans,
*root, struct btrfs_key *ins_key, struct btrfs_root *root,
struct btrfs_path *path, int data_size, int extend) struct btrfs_key *ins_key,
struct btrfs_path *path, int data_size,
int extend)
{ {
u64 root_gen; u64 root_gen;
struct extent_buffer *l; struct extent_buffer *l;
...@@ -3079,6 +3086,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) ...@@ -3079,6 +3086,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
* was nothing in the tree that matched the search criteria. * was nothing in the tree that matched the search criteria.
*/ */
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
struct btrfs_key *max_key,
struct btrfs_path *path, int cache_only, struct btrfs_path *path, int cache_only,
u64 min_trans) u64 min_trans)
{ {
...@@ -3093,6 +3101,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, ...@@ -3093,6 +3101,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
again: again:
cur = btrfs_lock_root_node(root); cur = btrfs_lock_root_node(root);
level = btrfs_header_level(cur); level = btrfs_header_level(cur);
WARN_ON(path->nodes[level]);
path->nodes[level] = cur; path->nodes[level] = cur;
path->locks[level] = 1; path->locks[level] = 1;
...@@ -3107,6 +3116,8 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, ...@@ -3107,6 +3116,8 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
/* at level = 0, we're done, setup the path and exit */ /* at level = 0, we're done, setup the path and exit */
if (level == 0) { if (level == 0) {
if (slot >= nritems)
goto find_next_key;
ret = 0; ret = 0;
path->slots[level] = slot; path->slots[level] = slot;
btrfs_item_key_to_cpu(cur, &found_key, slot); btrfs_item_key_to_cpu(cur, &found_key, slot);
...@@ -3123,6 +3134,8 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, ...@@ -3123,6 +3134,8 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
u64 blockptr; u64 blockptr;
u64 gen; u64 gen;
struct extent_buffer *tmp; struct extent_buffer *tmp;
struct btrfs_disk_key disk_key;
blockptr = btrfs_node_blockptr(cur, slot); blockptr = btrfs_node_blockptr(cur, slot);
gen = btrfs_node_ptr_generation(cur, slot); gen = btrfs_node_ptr_generation(cur, slot);
if (gen < min_trans) { if (gen < min_trans) {
...@@ -3132,6 +3145,14 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, ...@@ -3132,6 +3145,14 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
if (!cache_only) if (!cache_only)
break; break;
if (max_key) {
btrfs_node_key(cur, &disk_key, slot);
if (comp_keys(&disk_key, max_key) >= 0) {
ret = 1;
goto out;
}
}
tmp = btrfs_find_tree_block(root, blockptr, tmp = btrfs_find_tree_block(root, blockptr,
btrfs_level_size(root, level - 1)); btrfs_level_size(root, level - 1));
...@@ -3143,14 +3164,16 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, ...@@ -3143,14 +3164,16 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
free_extent_buffer(tmp); free_extent_buffer(tmp);
slot++; slot++;
} }
find_next_key:
/* /*
* we didn't find a candidate key in this node, walk forward * we didn't find a candidate key in this node, walk forward
* and find another one * and find another one
*/ */
if (slot >= nritems) { if (slot >= nritems) {
ret = btrfs_find_next_key(root, path, min_key, level, path->slots[level] = slot;
sret = btrfs_find_next_key(root, path, min_key, level,
cache_only, min_trans); cache_only, min_trans);
if (ret == 0) { if (sret == 0) {
btrfs_release_path(root, path); btrfs_release_path(root, path);
goto again; goto again;
} else { } else {
...@@ -3351,6 +3374,7 @@ int btrfs_previous_item(struct btrfs_root *root, ...@@ -3351,6 +3374,7 @@ int btrfs_previous_item(struct btrfs_root *root,
{ {
struct btrfs_key found_key; struct btrfs_key found_key;
struct extent_buffer *leaf; struct extent_buffer *leaf;
u32 nritems;
int ret; int ret;
while(1) { while(1) {
...@@ -3362,9 +3386,20 @@ int btrfs_previous_item(struct btrfs_root *root, ...@@ -3362,9 +3386,20 @@ int btrfs_previous_item(struct btrfs_root *root,
path->slots[0]--; path->slots[0]--;
} }
leaf = path->nodes[0]; leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
if (nritems == 0)
return 1;
if (path->slots[0] == nritems)
path->slots[0]--;
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
if (found_key.type == type) if (found_key.type == type)
return 0; return 0;
if (found_key.objectid < min_objectid)
break;
if (found_key.objectid == min_objectid &&
found_key.type < type)
break;
} }
return 1; return 1;
} }
...@@ -77,6 +77,10 @@ struct btrfs_ordered_sum; ...@@ -77,6 +77,10 @@ struct btrfs_ordered_sum;
/* orhpan objectid for tracking unlinked/truncated files */ /* orhpan objectid for tracking unlinked/truncated files */
#define BTRFS_ORPHAN_OBJECTID -5ULL #define BTRFS_ORPHAN_OBJECTID -5ULL
/* does write ahead logging to speed up fsyncs */
#define BTRFS_TREE_LOG_OBJECTID -6ULL
#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL
/* /*
* All files have objectids higher than this. * All files have objectids higher than this.
*/ */
...@@ -276,6 +280,7 @@ struct btrfs_super_block { ...@@ -276,6 +280,7 @@ struct btrfs_super_block {
__le64 generation; __le64 generation;
__le64 root; __le64 root;
__le64 chunk_root; __le64 chunk_root;
__le64 log_root;
__le64 total_bytes; __le64 total_bytes;
__le64 bytes_used; __le64 bytes_used;
__le64 root_dir_objectid; __le64 root_dir_objectid;
...@@ -287,6 +292,7 @@ struct btrfs_super_block { ...@@ -287,6 +292,7 @@ struct btrfs_super_block {
__le32 sys_chunk_array_size; __le32 sys_chunk_array_size;
u8 root_level; u8 root_level;
u8 chunk_root_level; u8 chunk_root_level;
u8 log_root_level;
struct btrfs_dev_item dev_item; struct btrfs_dev_item dev_item;
char label[BTRFS_LABEL_SIZE]; char label[BTRFS_LABEL_SIZE];
u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
...@@ -392,7 +398,10 @@ struct btrfs_timespec { ...@@ -392,7 +398,10 @@ struct btrfs_timespec {
* make a new item type * make a new item type
*/ */
struct btrfs_inode_item { struct btrfs_inode_item {
/* nfs style generation number */
__le64 generation; __le64 generation;
/* transid that last touched this inode */
__le64 transid;
__le64 size; __le64 size;
__le64 nblocks; __le64 nblocks;
__le64 block_group; __le64 block_group;
...@@ -409,8 +418,13 @@ struct btrfs_inode_item { ...@@ -409,8 +418,13 @@ struct btrfs_inode_item {
struct btrfs_timespec otime; struct btrfs_timespec otime;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
struct btrfs_dir_log_item {
__le64 end;
} __attribute__ ((__packed__));
struct btrfs_dir_item { struct btrfs_dir_item {
struct btrfs_disk_key location; struct btrfs_disk_key location;
__le64 transid;
__le16 data_len; __le16 data_len;
__le16 name_len; __le16 name_len;
u8 type; u8 type;
...@@ -505,6 +519,9 @@ struct btrfs_fs_info { ...@@ -505,6 +519,9 @@ struct btrfs_fs_info {
struct btrfs_root *tree_root; struct btrfs_root *tree_root;
struct btrfs_root *chunk_root; struct btrfs_root *chunk_root;
struct btrfs_root *dev_root; struct btrfs_root *dev_root;
/* the log root tree is a directory of all the other log roots */
struct btrfs_root *log_root_tree;
struct radix_tree_root fs_roots_radix; struct radix_tree_root fs_roots_radix;
struct extent_io_tree free_space_cache; struct extent_io_tree free_space_cache;
...@@ -518,6 +535,7 @@ struct btrfs_fs_info { ...@@ -518,6 +535,7 @@ struct btrfs_fs_info {
u64 generation; u64 generation;
u64 last_trans_committed; u64 last_trans_committed;
u64 last_trans_new_blockgroup;
u64 open_ioctl_trans; u64 open_ioctl_trans;
unsigned long mount_opt; unsigned long mount_opt;
u64 max_extent; u64 max_extent;
...@@ -527,6 +545,9 @@ struct btrfs_fs_info { ...@@ -527,6 +545,9 @@ struct btrfs_fs_info {
wait_queue_head_t transaction_throttle; wait_queue_head_t transaction_throttle;
wait_queue_head_t transaction_wait; wait_queue_head_t transaction_wait;
wait_queue_head_t async_submit_wait; wait_queue_head_t async_submit_wait;
wait_queue_head_t tree_log_wait;
struct btrfs_super_block super_copy; struct btrfs_super_block super_copy;
struct btrfs_super_block super_for_commit; struct btrfs_super_block super_for_commit;
struct block_device *__bdev; struct block_device *__bdev;
...@@ -535,6 +556,7 @@ struct btrfs_fs_info { ...@@ -535,6 +556,7 @@ struct btrfs_fs_info {
struct backing_dev_info bdi; struct backing_dev_info bdi;
spinlock_t hash_lock; spinlock_t hash_lock;
struct mutex trans_mutex; struct mutex trans_mutex;
struct mutex tree_log_mutex;
struct mutex transaction_kthread_mutex; struct mutex transaction_kthread_mutex;
struct mutex cleaner_mutex; struct mutex cleaner_mutex;
struct mutex alloc_mutex; struct mutex alloc_mutex;
...@@ -544,8 +566,13 @@ struct btrfs_fs_info { ...@@ -544,8 +566,13 @@ struct btrfs_fs_info {
struct list_head trans_list; struct list_head trans_list;
struct list_head hashers; struct list_head hashers;
struct list_head dead_roots; struct list_head dead_roots;
atomic_t nr_async_submits; atomic_t nr_async_submits;
atomic_t nr_async_bios; atomic_t nr_async_bios;
atomic_t tree_log_writers;
atomic_t tree_log_commit;
unsigned long tree_log_batch;
u64 tree_log_transid;
/* /*
* this is used by the balancing code to wait for all the pending * this is used by the balancing code to wait for all the pending
...@@ -583,6 +610,7 @@ struct btrfs_fs_info { ...@@ -583,6 +610,7 @@ struct btrfs_fs_info {
struct completion kobj_unregister; struct completion kobj_unregister;
int do_barriers; int do_barriers;
int closing; int closing;
int log_root_recovering;
atomic_t throttles; atomic_t throttles;
atomic_t throttle_gen; atomic_t throttle_gen;
...@@ -596,6 +624,7 @@ struct btrfs_fs_info { ...@@ -596,6 +624,7 @@ struct btrfs_fs_info {
u64 delalloc_bytes; u64 delalloc_bytes;
u64 last_alloc; u64 last_alloc;
u64 last_data_alloc; u64 last_data_alloc;
u64 last_log_alloc;
spinlock_t ref_cache_lock; spinlock_t ref_cache_lock;
u64 total_ref_cache_size; u64 total_ref_cache_size;
...@@ -632,6 +661,7 @@ struct btrfs_root { ...@@ -632,6 +661,7 @@ struct btrfs_root {
struct btrfs_leaf_ref_tree *ref_tree; struct btrfs_leaf_ref_tree *ref_tree;
struct btrfs_leaf_ref_tree ref_tree_struct; struct btrfs_leaf_ref_tree ref_tree_struct;
struct btrfs_dirty_root *dirty_root; struct btrfs_dirty_root *dirty_root;
struct btrfs_root *log_root;
struct btrfs_root_item root_item; struct btrfs_root_item root_item;
struct btrfs_key root_key; struct btrfs_key root_key;
...@@ -640,6 +670,7 @@ struct btrfs_root { ...@@ -640,6 +670,7 @@ struct btrfs_root {
struct kobject root_kobj; struct kobject root_kobj;
struct completion kobj_unregister; struct completion kobj_unregister;
struct mutex objectid_mutex; struct mutex objectid_mutex;
struct mutex log_mutex;
u64 objectid; u64 objectid;
u64 last_trans; u64 last_trans;
...@@ -692,6 +723,8 @@ struct btrfs_root { ...@@ -692,6 +723,8 @@ struct btrfs_root {
* dir items are the name -> inode pointers in a directory. There is one * dir items are the name -> inode pointers in a directory. There is one
* for every name in a directory. * for every name in a directory.
*/ */
#define BTRFS_DIR_LOG_ITEM_KEY 14
#define BTRFS_DIR_LOG_INDEX_KEY 15
#define BTRFS_DIR_ITEM_KEY 16 #define BTRFS_DIR_ITEM_KEY 16
#define BTRFS_DIR_INDEX_KEY 17 #define BTRFS_DIR_INDEX_KEY 17
/* /*
...@@ -703,7 +736,8 @@ struct btrfs_root { ...@@ -703,7 +736,8 @@ struct btrfs_root {
*/ */
#define BTRFS_CSUM_ITEM_KEY 19 #define BTRFS_CSUM_ITEM_KEY 19
/* reserve 20-31 for other file stuff */
/* reserve 21-31 for other file/dir stuff */
/* /*
* root items point to tree roots. There are typically in the root * root items point to tree roots. There are typically in the root
...@@ -938,6 +972,7 @@ BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64); ...@@ -938,6 +972,7 @@ BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);
/* struct btrfs_inode_item */ /* struct btrfs_inode_item */
BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64); BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64);
BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64);
BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64); BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64);
BTRFS_SETGET_FUNCS(inode_nblocks, struct btrfs_inode_item, nblocks, 64); BTRFS_SETGET_FUNCS(inode_nblocks, struct btrfs_inode_item, nblocks, 64);
BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64); BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64);
...@@ -1126,10 +1161,13 @@ static inline void btrfs_set_item_key(struct extent_buffer *eb, ...@@ -1126,10 +1161,13 @@ static inline void btrfs_set_item_key(struct extent_buffer *eb,
write_eb_member(eb, item, struct btrfs_item, key, disk_key); write_eb_member(eb, item, struct btrfs_item, key, disk_key);
} }
BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64);
/* struct btrfs_dir_item */ /* struct btrfs_dir_item */
BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16); BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8); BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16); BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
static inline void btrfs_dir_item_key(struct extent_buffer *eb, static inline void btrfs_dir_item_key(struct extent_buffer *eb,
struct btrfs_dir_item *item, struct btrfs_dir_item *item,
...@@ -1301,7 +1339,11 @@ BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block, ...@@ -1301,7 +1339,11 @@ BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,
BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block, BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block,
chunk_root, 64); chunk_root, 64);
BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block, BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block,
chunk_root_level, 64); chunk_root_level, 8);
BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block,
log_root, 64);
BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block,
log_root_level, 8);
BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block, BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block,
total_bytes, 64); total_bytes, 64);
BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block, BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block,
...@@ -1405,6 +1447,12 @@ static inline struct dentry *fdentry(struct file *file) { ...@@ -1405,6 +1447,12 @@ static inline struct dentry *fdentry(struct file *file) {
} }
/* extent-tree.c */ /* extent-tree.c */
int btrfs_lookup_extent(struct btrfs_root *root, struct btrfs_path *path,
u64 start, u64 len);
int btrfs_update_pinned_extents(struct btrfs_root *root,
u64 bytenr, u64 num, int pin);
int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *leaf);
int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans, int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_key *key, u64 bytenr); struct btrfs_key *key, u64 bytenr);
...@@ -1448,6 +1496,11 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans, ...@@ -1448,6 +1496,11 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
u64 root_objectid, u64 ref_generation, u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset, u64 owner, u64 owner_offset,
struct btrfs_key *ins); struct btrfs_key *ins);
int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset,
struct btrfs_key *ins);
int btrfs_reserve_extent(struct btrfs_trans_handle *trans, int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 num_bytes, u64 min_alloc_size, u64 num_bytes, u64 min_alloc_size,
...@@ -1488,9 +1541,9 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, ...@@ -1488,9 +1541,9 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
struct btrfs_key *key, int lowest_level, struct btrfs_key *key, int lowest_level,
int cache_only, u64 min_trans); int cache_only, u64 min_trans);
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
struct btrfs_key *max_key,
struct btrfs_path *path, int cache_only, struct btrfs_path *path, int cache_only,
u64 min_trans); u64 min_trans);
int btrfs_cow_block(struct btrfs_trans_handle *trans, int btrfs_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf, struct btrfs_root *root, struct extent_buffer *buf,
struct extent_buffer *parent, int parent_slot, struct extent_buffer *parent, int parent_slot,
...@@ -1656,6 +1709,18 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, ...@@ -1656,6 +1709,18 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
#define PageChecked PageFsMisc #define PageChecked PageFsMisc
#endif #endif
int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *dir, struct inode *inode,
const char *name, int name_len);
int btrfs_add_link(struct btrfs_trans_handle *trans,
struct inode *parent_inode, struct inode *inode,
const char *name, int name_len, int add_backref, u64 index);
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct inode *inode, u64 new_size,
u32 min_type);
int btrfs_start_delalloc_inodes(struct btrfs_root *root); int btrfs_start_delalloc_inodes(struct btrfs_root *root);
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end); int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end);
int btrfs_writepages(struct address_space *mapping, int btrfs_writepages(struct address_space *mapping,
...@@ -1715,6 +1780,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans, ...@@ -1715,6 +1780,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/* file.c */ /* file.c */
int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync);
int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end); int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end);
int btrfs_check_file(struct btrfs_root *root, struct inode *inode); int btrfs_check_file(struct btrfs_root *root, struct inode *inode);
extern struct file_operations btrfs_file_operations; extern struct file_operations btrfs_file_operations;
......
...@@ -96,6 +96,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, ...@@ -96,6 +96,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
btrfs_set_dir_item_key(leaf, dir_item, &disk_key); btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
btrfs_set_dir_name_len(leaf, dir_item, name_len); btrfs_set_dir_name_len(leaf, dir_item, name_len);
btrfs_set_dir_transid(leaf, dir_item, trans->transid);
btrfs_set_dir_data_len(leaf, dir_item, data_len); btrfs_set_dir_data_len(leaf, dir_item, data_len);
name_ptr = (unsigned long)(dir_item + 1); name_ptr = (unsigned long)(dir_item + 1);
data_ptr = (unsigned long)((char *)name_ptr + name_len); data_ptr = (unsigned long)((char *)name_ptr + name_len);
...@@ -142,6 +143,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -142,6 +143,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_dir_type(leaf, dir_item, type); btrfs_set_dir_type(leaf, dir_item, type);
btrfs_set_dir_data_len(leaf, dir_item, 0); btrfs_set_dir_data_len(leaf, dir_item, 0);
btrfs_set_dir_name_len(leaf, dir_item, name_len); btrfs_set_dir_name_len(leaf, dir_item, name_len);
btrfs_set_dir_transid(leaf, dir_item, trans->transid);
name_ptr = (unsigned long)(dir_item + 1); name_ptr = (unsigned long)(dir_item + 1);
write_extent_buffer(leaf, name, name_ptr, name_len); write_extent_buffer(leaf, name, name_ptr, name_len);
...@@ -169,6 +171,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -169,6 +171,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_dir_type(leaf, dir_item, type); btrfs_set_dir_type(leaf, dir_item, type);
btrfs_set_dir_data_len(leaf, dir_item, 0); btrfs_set_dir_data_len(leaf, dir_item, 0);
btrfs_set_dir_name_len(leaf, dir_item, name_len); btrfs_set_dir_name_len(leaf, dir_item, name_len);
btrfs_set_dir_transid(leaf, dir_item, trans->transid);
name_ptr = (unsigned long)(dir_item + 1); name_ptr = (unsigned long)(dir_item + 1);
write_extent_buffer(leaf, name, name_ptr, name_len); write_extent_buffer(leaf, name, name_ptr, name_len);
btrfs_mark_buffer_dirty(leaf); btrfs_mark_buffer_dirty(leaf);
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "async-thread.h" #include "async-thread.h"
#include "locking.h" #include "locking.h"
#include "ref-cache.h" #include "ref-cache.h"
#include "tree-log.h"
#if 0 #if 0
static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
...@@ -694,6 +695,18 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, ...@@ -694,6 +695,18 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
} }
int btrfs_write_tree_block(struct extent_buffer *buf)
{
return btrfs_fdatawrite_range(buf->first_page->mapping, buf->start,
buf->start + buf->len - 1, WB_SYNC_NONE);
}
int btrfs_wait_tree_block_writeback(struct extent_buffer *buf)
{
return btrfs_wait_on_page_writeback_range(buf->first_page->mapping,
buf->start, buf->start + buf->len -1);
}
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize, u64 parent_transid) u32 blocksize, u64 parent_transid)
{ {
...@@ -732,15 +745,6 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -732,15 +745,6 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
return 0; return 0;
} }
int wait_on_tree_block_writeback(struct btrfs_root *root,
struct extent_buffer *buf)
{
struct inode *btree_inode = root->fs_info->btree_inode;
wait_on_extent_buffer_writeback(&BTRFS_I(btree_inode)->io_tree,
buf);
return 0;
}
static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
u32 stripesize, struct btrfs_root *root, u32 stripesize, struct btrfs_root *root,
struct btrfs_fs_info *fs_info, struct btrfs_fs_info *fs_info,
...@@ -771,6 +775,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, ...@@ -771,6 +775,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
spin_lock_init(&root->node_lock); spin_lock_init(&root->node_lock);
spin_lock_init(&root->list_lock); spin_lock_init(&root->list_lock);
mutex_init(&root->objectid_mutex); mutex_init(&root->objectid_mutex);
mutex_init(&root->log_mutex);
btrfs_leaf_ref_tree_init(&root->ref_tree_struct); btrfs_leaf_ref_tree_init(&root->ref_tree_struct);
root->ref_tree = &root->ref_tree_struct; root->ref_tree = &root->ref_tree_struct;
...@@ -809,11 +814,74 @@ static int find_and_setup_root(struct btrfs_root *tree_root, ...@@ -809,11 +814,74 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
return 0; return 0;
} }
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_key *location) struct btrfs_fs_info *fs_info)
{
struct extent_buffer *eb;
int ret;
if (!fs_info->log_root_tree)
return 0;
eb = fs_info->log_root_tree->node;
WARN_ON(btrfs_header_level(eb) != 0);
WARN_ON(btrfs_header_nritems(eb) != 0);
ret = btrfs_free_extent(trans, fs_info->tree_root,
eb->start, eb->len,
BTRFS_TREE_LOG_OBJECTID, 0, 0, 0, 1);
BUG_ON(ret);
free_extent_buffer(eb);
kfree(fs_info->log_root_tree);
fs_info->log_root_tree = NULL;
return 0;
}
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info)
{ {
struct btrfs_root *root; struct btrfs_root *root;
struct btrfs_root *tree_root = fs_info->tree_root; struct btrfs_root *tree_root = fs_info->tree_root;
root = kzalloc(sizeof(*root), GFP_NOFS);
if (!root)
return -ENOMEM;
__setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize,
root, fs_info, BTRFS_TREE_LOG_OBJECTID);
root->root_key.objectid = BTRFS_TREE_LOG_OBJECTID;
root->root_key.type = BTRFS_ROOT_ITEM_KEY;
root->root_key.offset = BTRFS_TREE_LOG_OBJECTID;
root->ref_cows = 0;
root->node = btrfs_alloc_free_block(trans, root, root->leafsize,
BTRFS_TREE_LOG_OBJECTID,
0, 0, 0, 0, 0);
btrfs_set_header_nritems(root->node, 0);
btrfs_set_header_level(root->node, 0);
btrfs_set_header_bytenr(root->node, root->node->start);
btrfs_set_header_generation(root->node, trans->transid);
btrfs_set_header_owner(root->node, BTRFS_TREE_LOG_OBJECTID);
write_extent_buffer(root->node, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(root->node),
BTRFS_FSID_SIZE);
btrfs_mark_buffer_dirty(root->node);
btrfs_tree_unlock(root->node);
fs_info->log_root_tree = root;
return 0;
}
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
struct btrfs_key *location)
{
struct btrfs_root *root;
struct btrfs_fs_info *fs_info = tree_root->fs_info;
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *l; struct extent_buffer *l;
u64 highest_inode; u64 highest_inode;
...@@ -863,11 +931,13 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, ...@@ -863,11 +931,13 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
blocksize, 0); blocksize, 0);
BUG_ON(!root->node); BUG_ON(!root->node);
insert: insert:
root->ref_cows = 1; if (location->objectid != BTRFS_TREE_LOG_OBJECTID) {
ret = btrfs_find_highest_inode(root, &highest_inode); root->ref_cows = 1;
if (ret == 0) { ret = btrfs_find_highest_inode(root, &highest_inode);
root->highest_inode = highest_inode; if (ret == 0) {
root->last_inode_alloc = highest_inode; root->highest_inode = highest_inode;
root->last_inode_alloc = highest_inode;
}
} }
return root; return root;
} }
...@@ -907,7 +977,7 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -907,7 +977,7 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
if (root) if (root)
return root; return root;
root = btrfs_read_fs_root_no_radix(fs_info, location); root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location);
if (IS_ERR(root)) if (IS_ERR(root))
return root; return root;
ret = radix_tree_insert(&fs_info->fs_roots_radix, ret = radix_tree_insert(&fs_info->fs_roots_radix,
...@@ -1250,16 +1320,18 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1250,16 +1320,18 @@ struct btrfs_root *open_ctree(struct super_block *sb,
u32 blocksize; u32 blocksize;
u32 stripesize; u32 stripesize;
struct buffer_head *bh; struct buffer_head *bh;
struct btrfs_root *extent_root = kmalloc(sizeof(struct btrfs_root), struct btrfs_root *extent_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS); GFP_NOFS);
struct btrfs_root *tree_root = kmalloc(sizeof(struct btrfs_root), struct btrfs_root *tree_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS); GFP_NOFS);
struct btrfs_fs_info *fs_info = kzalloc(sizeof(*fs_info), struct btrfs_fs_info *fs_info = kzalloc(sizeof(*fs_info),
GFP_NOFS); GFP_NOFS);
struct btrfs_root *chunk_root = kmalloc(sizeof(struct btrfs_root), struct btrfs_root *chunk_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS); GFP_NOFS);
struct btrfs_root *dev_root = kmalloc(sizeof(struct btrfs_root), struct btrfs_root *dev_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS); GFP_NOFS);
struct btrfs_root *log_tree_root;
int ret; int ret;
int err = -EINVAL; int err = -EINVAL;
...@@ -1343,6 +1415,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1343,6 +1415,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
mutex_init(&fs_info->trans_mutex); mutex_init(&fs_info->trans_mutex);
mutex_init(&fs_info->tree_log_mutex);
mutex_init(&fs_info->drop_mutex); mutex_init(&fs_info->drop_mutex);
mutex_init(&fs_info->alloc_mutex); mutex_init(&fs_info->alloc_mutex);
mutex_init(&fs_info->chunk_mutex); mutex_init(&fs_info->chunk_mutex);
...@@ -1352,6 +1425,10 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1352,6 +1425,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
init_waitqueue_head(&fs_info->transaction_throttle); init_waitqueue_head(&fs_info->transaction_throttle);
init_waitqueue_head(&fs_info->transaction_wait); init_waitqueue_head(&fs_info->transaction_wait);
init_waitqueue_head(&fs_info->async_submit_wait); init_waitqueue_head(&fs_info->async_submit_wait);
init_waitqueue_head(&fs_info->tree_log_wait);
atomic_set(&fs_info->tree_log_commit, 0);
atomic_set(&fs_info->tree_log_writers, 0);
fs_info->tree_log_transid = 0;
#if 0 #if 0
ret = add_hasher(fs_info, "crc32c"); ret = add_hasher(fs_info, "crc32c");
...@@ -1532,7 +1609,26 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1532,7 +1609,26 @@ struct btrfs_root *open_ctree(struct super_block *sb,
if (!fs_info->transaction_kthread) if (!fs_info->transaction_kthread)
goto fail_cleaner; goto fail_cleaner;
if (btrfs_super_log_root(disk_super) != 0) {
u32 blocksize;
u64 bytenr = btrfs_super_log_root(disk_super);
blocksize =
btrfs_level_size(tree_root,
btrfs_super_log_root_level(disk_super));
log_tree_root = kzalloc(sizeof(struct btrfs_root),
GFP_NOFS);
__setup_root(nodesize, leafsize, sectorsize, stripesize,
log_tree_root, fs_info, BTRFS_TREE_LOG_OBJECTID);
log_tree_root->node = read_tree_block(tree_root, bytenr,
blocksize, 0);
ret = btrfs_recover_log_trees(log_tree_root);
BUG_ON(ret);
}
fs_info->last_trans_committed = btrfs_super_generation(disk_super);
return tree_root; return tree_root;
fail_cleaner: fail_cleaner:
......
...@@ -45,7 +45,7 @@ struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, ...@@ -45,7 +45,7 @@ struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *location, struct btrfs_key *location,
const char *name, int namelen); const char *name, int namelen);
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
struct btrfs_key *location); struct btrfs_key *location);
struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
struct btrfs_key *location); struct btrfs_key *location);
...@@ -74,4 +74,10 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, ...@@ -74,4 +74,10 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
extent_submit_bio_hook_t *submit_bio_hook); extent_submit_bio_hook_t *submit_bio_hook);
int btrfs_congested_async(struct btrfs_fs_info *info, int iodone); int btrfs_congested_async(struct btrfs_fs_info *info, int iodone);
unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info); unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info);
int btrfs_write_tree_block(struct extent_buffer *buf);
int btrfs_wait_tree_block_writeback(struct extent_buffer *buf);
int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
#endif #endif
...@@ -496,6 +496,23 @@ static int match_extent_ref(struct extent_buffer *leaf, ...@@ -496,6 +496,23 @@ static int match_extent_ref(struct extent_buffer *leaf,
return ret == 0; return ret == 0;
} }
/* simple helper to search for an existing extent at a given offset */
int btrfs_lookup_extent(struct btrfs_root *root, struct btrfs_path *path,
u64 start, u64 len)
{
int ret;
struct btrfs_key key;
maybe_lock_mutex(root);
key.objectid = start;
key.offset = len;
btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, path,
0, 0);
maybe_unlock_mutex(root);
return ret;
}
static int noinline lookup_extent_backref(struct btrfs_trans_handle *trans, static int noinline lookup_extent_backref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_path *path, u64 bytenr, struct btrfs_path *path, u64 bytenr,
...@@ -1409,7 +1426,7 @@ static u64 first_logical_byte(struct btrfs_root *root, u64 search_start) ...@@ -1409,7 +1426,7 @@ static u64 first_logical_byte(struct btrfs_root *root, u64 search_start)
} }
static int update_pinned_extents(struct btrfs_root *root, int btrfs_update_pinned_extents(struct btrfs_root *root,
u64 bytenr, u64 num, int pin) u64 bytenr, u64 num, int pin)
{ {
u64 len; u64 len;
...@@ -1492,7 +1509,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, ...@@ -1492,7 +1509,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
EXTENT_DIRTY); EXTENT_DIRTY);
if (ret) if (ret)
break; break;
update_pinned_extents(root, start, end + 1 - start, 0); btrfs_update_pinned_extents(root, start, end + 1 - start, 0);
clear_extent_dirty(unpin, start, end, GFP_NOFS); clear_extent_dirty(unpin, start, end, GFP_NOFS);
set_extent_dirty(free_space_cache, start, end, GFP_NOFS); set_extent_dirty(free_space_cache, start, end, GFP_NOFS);
if (need_resched()) { if (need_resched()) {
...@@ -1538,14 +1555,11 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, ...@@ -1538,14 +1555,11 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED, clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED,
GFP_NOFS); GFP_NOFS);
eb = btrfs_find_tree_block(extent_root, ins.objectid, eb = btrfs_find_create_tree_block(extent_root, ins.objectid,
ins.offset); ins.offset);
if (!btrfs_buffer_uptodate(eb, trans->transid)) { if (!btrfs_buffer_uptodate(eb, trans->transid))
mutex_unlock(&extent_root->fs_info->alloc_mutex);
btrfs_read_buffer(eb, trans->transid); btrfs_read_buffer(eb, trans->transid);
mutex_lock(&extent_root->fs_info->alloc_mutex);
}
btrfs_tree_lock(eb); btrfs_tree_lock(eb);
level = btrfs_header_level(eb); level = btrfs_header_level(eb);
...@@ -1585,13 +1599,20 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes, ...@@ -1585,13 +1599,20 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
struct extent_buffer *buf; struct extent_buffer *buf;
buf = btrfs_find_tree_block(root, bytenr, num_bytes); buf = btrfs_find_tree_block(root, bytenr, num_bytes);
if (buf) { if (buf) {
/* we can reuse a block if it hasn't been written
* and it is from this transaction. We can't
* reuse anything from the tree log root because
* it has tiny sub-transactions.
*/
if (btrfs_buffer_uptodate(buf, 0) && if (btrfs_buffer_uptodate(buf, 0) &&
btrfs_try_tree_lock(buf)) { btrfs_try_tree_lock(buf)) {
u64 transid = u64 transid =
root->fs_info->running_transaction->transid; root->fs_info->running_transaction->transid;
u64 header_transid = u64 header_transid =
btrfs_header_generation(buf); btrfs_header_generation(buf);
if (header_transid == transid && if (btrfs_header_owner(buf) !=
BTRFS_TREE_LOG_OBJECTID &&
header_transid == transid &&
!btrfs_header_flag(buf, !btrfs_header_flag(buf,
BTRFS_HEADER_FLAG_WRITTEN)) { BTRFS_HEADER_FLAG_WRITTEN)) {
clean_tree_block(NULL, root, buf); clean_tree_block(NULL, root, buf);
...@@ -1603,7 +1624,7 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes, ...@@ -1603,7 +1624,7 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
} }
free_extent_buffer(buf); free_extent_buffer(buf);
} }
update_pinned_extents(root, bytenr, num_bytes, 1); btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
} else { } else {
set_extent_bits(&root->fs_info->pending_del, set_extent_bits(&root->fs_info->pending_del,
bytenr, bytenr + num_bytes - 1, bytenr, bytenr + num_bytes - 1,
...@@ -1801,7 +1822,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct ...@@ -1801,7 +1822,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
GFP_NOFS); GFP_NOFS);
if (!test_range_bit(&extent_root->fs_info->extent_ins, if (!test_range_bit(&extent_root->fs_info->extent_ins,
start, end, EXTENT_LOCKED, 0)) { start, end, EXTENT_LOCKED, 0)) {
update_pinned_extents(extent_root, start, btrfs_update_pinned_extents(extent_root, start,
end + 1 - start, 1); end + 1 - start, 1);
ret = __free_extent(trans, extent_root, ret = __free_extent(trans, extent_root,
start, end + 1 - start, start, end + 1 - start,
...@@ -1919,6 +1940,12 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans, ...@@ -1919,6 +1940,12 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD)) { if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD)) {
last_ptr = &root->fs_info->last_data_alloc; last_ptr = &root->fs_info->last_data_alloc;
} }
if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) {
last_ptr = &root->fs_info->last_log_alloc;
if (!last_ptr == 0 && root->fs_info->last_alloc) {
*last_ptr = root->fs_info->last_alloc + empty_cluster;
}
}
if (last_ptr) { if (last_ptr) {
if (*last_ptr) if (*last_ptr)
...@@ -2268,6 +2295,35 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans, ...@@ -2268,6 +2295,35 @@ int btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
maybe_unlock_mutex(root); maybe_unlock_mutex(root);
return ret; return ret;
} }
/*
* this is used by the tree logging recovery code. It records that
* an extent has been allocated and makes sure to clear the free
* space cache bits as well
*/
int btrfs_alloc_logged_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
u64 root_objectid, u64 ref_generation,
u64 owner, u64 owner_offset,
struct btrfs_key *ins)
{
int ret;
struct btrfs_block_group_cache *block_group;
maybe_lock_mutex(root);
block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
cache_block_group(root, block_group);
clear_extent_dirty(&root->fs_info->free_space_cache,
ins->objectid, ins->objectid + ins->offset - 1,
GFP_NOFS);
ret = __btrfs_alloc_reserved_extent(trans, root, root_objectid,
ref_generation, owner,
owner_offset, ins);
maybe_unlock_mutex(root);
return ret;
}
/* /*
* finds a free extent and does all the dirty work required for allocation * finds a free extent and does all the dirty work required for allocation
* returns the key for the extent through ins, and a tree buffer for * returns the key for the extent through ins, and a tree buffer for
...@@ -2350,9 +2406,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ...@@ -2350,9 +2406,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
return buf; return buf;
} }
static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans, int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root, struct extent_buffer *leaf)
struct extent_buffer *leaf)
{ {
u64 leaf_owner; u64 leaf_owner;
u64 leaf_generation; u64 leaf_generation;
...@@ -2402,9 +2457,9 @@ static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans, ...@@ -2402,9 +2457,9 @@ static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans, static int noinline cache_drop_leaf_ref(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_leaf_ref *ref) struct btrfs_leaf_ref *ref)
{ {
int i; int i;
int ret; int ret;
...@@ -2512,7 +2567,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans, ...@@ -2512,7 +2567,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
btrfs_header_nritems(cur)) btrfs_header_nritems(cur))
break; break;
if (*level == 0) { if (*level == 0) {
ret = drop_leaf_ref_no_cache(trans, root, cur); ret = btrfs_drop_leaf_ref(trans, root, cur);
BUG_ON(ret); BUG_ON(ret);
break; break;
} }
...@@ -2552,7 +2607,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans, ...@@ -2552,7 +2607,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
btrfs_node_key_to_cpu(cur, &key, path->slots[*level]); btrfs_node_key_to_cpu(cur, &key, path->slots[*level]);
ref = btrfs_lookup_leaf_ref(root, bytenr); ref = btrfs_lookup_leaf_ref(root, bytenr);
if (ref) { if (ref) {
ret = drop_leaf_ref(trans, root, ref); ret = cache_drop_leaf_ref(trans, root, ref);
BUG_ON(ret); BUG_ON(ret);
btrfs_remove_leaf_ref(root, ref); btrfs_remove_leaf_ref(root, ref);
btrfs_free_leaf_ref(root, ref); btrfs_free_leaf_ref(root, ref);
...@@ -3628,6 +3683,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, ...@@ -3628,6 +3683,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
extent_root = root->fs_info->extent_root; extent_root = root->fs_info->extent_root;
block_group_cache = &root->fs_info->block_group_cache; block_group_cache = &root->fs_info->block_group_cache;
root->fs_info->last_trans_new_blockgroup = trans->transid;
cache = kzalloc(sizeof(*cache), GFP_NOFS); cache = kzalloc(sizeof(*cache), GFP_NOFS);
BUG_ON(!cache); BUG_ON(!cache);
cache->key.objectid = chunk_offset; cache->key.objectid = chunk_offset;
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
#include "btrfs_inode.h" #include "btrfs_inode.h"
#include "ioctl.h" #include "ioctl.h"
#include "print-tree.h" #include "print-tree.h"
#include "tree-log.h"
#include "locking.h"
#include "compat.h" #include "compat.h"
...@@ -988,10 +990,27 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, ...@@ -988,10 +990,27 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
*ppos = pos; *ppos = pos;
if (num_written > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { if (num_written > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
err = sync_page_range(inode, inode->i_mapping, struct btrfs_trans_handle *trans;
start_pos, num_written);
err = btrfs_fdatawrite_range(inode->i_mapping, start_pos,
start_pos + num_written -1,
WB_SYNC_NONE);
if (err < 0)
num_written = err;
err = btrfs_wait_on_page_writeback_range(inode->i_mapping,
start_pos, start_pos + num_written - 1);
if (err < 0) if (err < 0)
num_written = err; num_written = err;
trans = btrfs_start_transaction(root, 1);
ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
if (ret == 0) {
btrfs_sync_log(trans, root);
btrfs_end_transaction(trans, root);
} else {
btrfs_commit_transaction(trans, root);
}
} else if (num_written > 0 && (file->f_flags & O_DIRECT)) { } else if (num_written > 0 && (file->f_flags & O_DIRECT)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
do_sync_file_range(file, start_pos, do_sync_file_range(file, start_pos,
...@@ -1019,8 +1038,7 @@ int btrfs_release_file(struct inode * inode, struct file * filp) ...@@ -1019,8 +1038,7 @@ int btrfs_release_file(struct inode * inode, struct file * filp)
return 0; return 0;
} }
static int btrfs_sync_file(struct file *file, int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
struct dentry *dentry, int datasync)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
...@@ -1043,6 +1061,8 @@ static int btrfs_sync_file(struct file *file, ...@@ -1043,6 +1061,8 @@ static int btrfs_sync_file(struct file *file,
} }
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
filemap_fdatawait(inode->i_mapping);
/* /*
* ok we haven't committed the transaction yet, lets do a commit * ok we haven't committed the transaction yet, lets do a commit
*/ */
...@@ -1054,7 +1074,16 @@ static int btrfs_sync_file(struct file *file, ...@@ -1054,7 +1074,16 @@ static int btrfs_sync_file(struct file *file,
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
ret = btrfs_commit_transaction(trans, root);
ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
if (ret < 0)
goto out;
if (ret > 0) {
ret = btrfs_commit_transaction(trans, root);
} else {
btrfs_sync_log(trans, root);
ret = btrfs_end_transaction(trans, root);
}
out: out:
return ret > 0 ? EIO : ret; return ret > 0 ? EIO : ret;
} }
......
This diff is collapsed.
...@@ -202,8 +202,9 @@ int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid, ...@@ -202,8 +202,9 @@ int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid,
memcpy(&found_key, &key, sizeof(key)); memcpy(&found_key, &key, sizeof(key));
key.offset++; key.offset++;
btrfs_release_path(root, path); btrfs_release_path(root, path);
dead_root = btrfs_read_fs_root_no_radix(root->fs_info, dead_root =
&found_key); btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
&found_key);
if (IS_ERR(dead_root)) { if (IS_ERR(dead_root)) {
ret = PTR_ERR(dead_root); ret = PTR_ERR(dead_root);
goto err; goto err;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "transaction.h" #include "transaction.h"
#include "locking.h" #include "locking.h"
#include "ref-cache.h" #include "ref-cache.h"
#include "tree-log.h"
static int total_trans = 0; static int total_trans = 0;
extern struct kmem_cache *btrfs_trans_handle_cachep; extern struct kmem_cache *btrfs_trans_handle_cachep;
...@@ -57,6 +58,7 @@ static noinline int join_transaction(struct btrfs_root *root) ...@@ -57,6 +58,7 @@ static noinline int join_transaction(struct btrfs_root *root)
root->fs_info->generation++; root->fs_info->generation++;
root->fs_info->last_alloc = 0; root->fs_info->last_alloc = 0;
root->fs_info->last_data_alloc = 0; root->fs_info->last_data_alloc = 0;
root->fs_info->last_log_alloc = 0;
cur_trans->num_writers = 1; cur_trans->num_writers = 1;
cur_trans->num_joined = 0; cur_trans->num_joined = 0;
cur_trans->transid = root->fs_info->generation; cur_trans->transid = root->fs_info->generation;
...@@ -83,7 +85,7 @@ static noinline int join_transaction(struct btrfs_root *root) ...@@ -83,7 +85,7 @@ static noinline int join_transaction(struct btrfs_root *root)
return 0; return 0;
} }
static noinline int record_root_in_trans(struct btrfs_root *root) noinline int btrfs_record_root_in_trans(struct btrfs_root *root)
{ {
struct btrfs_dirty_root *dirty; struct btrfs_dirty_root *dirty;
u64 running_trans_id = root->fs_info->running_transaction->transid; u64 running_trans_id = root->fs_info->running_transaction->transid;
...@@ -151,7 +153,7 @@ static void wait_current_trans(struct btrfs_root *root) ...@@ -151,7 +153,7 @@ static void wait_current_trans(struct btrfs_root *root)
} }
} }
struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
int num_blocks, int wait) int num_blocks, int wait)
{ {
struct btrfs_trans_handle *h = struct btrfs_trans_handle *h =
...@@ -164,7 +166,7 @@ struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, ...@@ -164,7 +166,7 @@ struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
ret = join_transaction(root); ret = join_transaction(root);
BUG_ON(ret); BUG_ON(ret);
record_root_in_trans(root); btrfs_record_root_in_trans(root);
h->transid = root->fs_info->running_transaction->transid; h->transid = root->fs_info->running_transaction->transid;
h->transaction = root->fs_info->running_transaction; h->transaction = root->fs_info->running_transaction;
h->blocks_reserved = num_blocks; h->blocks_reserved = num_blocks;
...@@ -456,6 +458,8 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, ...@@ -456,6 +458,8 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
BUG_ON(!root->ref_tree); BUG_ON(!root->ref_tree);
dirty = root->dirty_root; dirty = root->dirty_root;
btrfs_free_log(trans, root);
if (root->commit_root == root->node) { if (root->commit_root == root->node) {
WARN_ON(root->node->start != WARN_ON(root->node->start !=
btrfs_root_bytenr(&root->root_item)); btrfs_root_bytenr(&root->root_item));
...@@ -600,7 +604,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, ...@@ -600,7 +604,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
num_bytes -= btrfs_root_used(&dirty->root->root_item); num_bytes -= btrfs_root_used(&dirty->root->root_item);
bytes_used = btrfs_root_used(&root->root_item); bytes_used = btrfs_root_used(&root->root_item);
if (num_bytes) { if (num_bytes) {
record_root_in_trans(root); btrfs_record_root_in_trans(root);
btrfs_set_root_used(&root->root_item, btrfs_set_root_used(&root->root_item,
bytes_used - num_bytes); bytes_used - num_bytes);
} }
...@@ -745,7 +749,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -745,7 +749,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
int ret; int ret;
INIT_LIST_HEAD(&dirty_fs_roots); INIT_LIST_HEAD(&dirty_fs_roots);
mutex_lock(&root->fs_info->trans_mutex); mutex_lock(&root->fs_info->trans_mutex);
if (trans->transaction->in_commit) { if (trans->transaction->in_commit) {
cur_trans = trans->transaction; cur_trans = trans->transaction;
...@@ -821,10 +824,30 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -821,10 +824,30 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
WARN_ON(cur_trans != trans->transaction); WARN_ON(cur_trans != trans->transaction);
/* btrfs_commit_tree_roots is responsible for getting the
* various roots consistent with each other. Every pointer
* in the tree of tree roots has to point to the most up to date
* root for every subvolume and other tree. So, we have to keep
* the tree logging code from jumping in and changing any
* of the trees.
*
* At this point in the commit, there can't be any tree-log
* writers, but a little lower down we drop the trans mutex
* and let new people in. By holding the tree_log_mutex
* from now until after the super is written, we avoid races
* with the tree-log code.
*/
mutex_lock(&root->fs_info->tree_log_mutex);
ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix, ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix,
&dirty_fs_roots); &dirty_fs_roots);
BUG_ON(ret); BUG_ON(ret);
/* add_dirty_roots gets rid of all the tree log roots, it is now
* safe to free the root of tree log roots
*/
btrfs_free_log_root_tree(trans, root->fs_info);
ret = btrfs_commit_tree_roots(trans, root); ret = btrfs_commit_tree_roots(trans, root);
BUG_ON(ret); BUG_ON(ret);
...@@ -843,6 +866,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -843,6 +866,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
chunk_root->node->start); chunk_root->node->start);
btrfs_set_super_chunk_root_level(&root->fs_info->super_copy, btrfs_set_super_chunk_root_level(&root->fs_info->super_copy,
btrfs_header_level(chunk_root->node)); btrfs_header_level(chunk_root->node));
if (!root->fs_info->log_root_recovering) {
btrfs_set_super_log_root(&root->fs_info->super_copy, 0);
btrfs_set_super_log_root_level(&root->fs_info->super_copy, 0);
}
memcpy(&root->fs_info->super_for_commit, &root->fs_info->super_copy, memcpy(&root->fs_info->super_for_commit, &root->fs_info->super_copy,
sizeof(root->fs_info->super_copy)); sizeof(root->fs_info->super_copy));
...@@ -857,6 +886,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -857,6 +886,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
BUG_ON(ret); BUG_ON(ret);
write_ctree_super(trans, root); write_ctree_super(trans, root);
/*
* the super is written, we can safely allow the tree-loggers
* to go about their business
*/
mutex_unlock(&root->fs_info->tree_log_mutex);
btrfs_finish_extent_commit(trans, root, pinned_copy); btrfs_finish_extent_commit(trans, root, pinned_copy);
mutex_lock(&root->fs_info->trans_mutex); mutex_lock(&root->fs_info->trans_mutex);
......
...@@ -98,4 +98,5 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -98,4 +98,5 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
void btrfs_throttle(struct btrfs_root *root); void btrfs_throttle(struct btrfs_root *root);
int btrfs_record_root_in_trans(struct btrfs_root *root);
#endif #endif
...@@ -81,12 +81,12 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, ...@@ -81,12 +81,12 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
memcpy(&key, &root->defrag_progress, sizeof(key)); memcpy(&key, &root->defrag_progress, sizeof(key));
} }
path->lowest_level = 1;
path->keep_locks = 1; path->keep_locks = 1;
if (cache_only) if (cache_only)
min_trans = root->defrag_trans_start; min_trans = root->defrag_trans_start;
ret = btrfs_search_forward(root, &key, path, cache_only, min_trans); ret = btrfs_search_forward(root, &key, NULL, path,
cache_only, min_trans);
if (ret < 0) if (ret < 0)
goto out; goto out;
if (ret > 0) { if (ret > 0) {
......
This diff is collapsed.
/*
* Copyright (C) 2008 Oracle. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#ifndef __TREE_LOG_
#define __TREE_LOG_
int btrfs_sync_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
int btrfs_log_dentry(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct dentry *dentry);
int btrfs_recover_log_trees(struct btrfs_root *tree_root);
int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct dentry *dentry);
int btrfs_log_inode(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode,
int inode_only);
int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
struct inode *dir, u64 index);
int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
const char *name, int name_len,
struct inode *inode, u64 dirid);
#endif
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