Skip to content

Commit e02119d

Browse files
committed
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: Chris Mason <chris.mason@oracle.com>
1 parent a1b32a5 commit e02119d

17 files changed

+3408
-205
lines changed

fs/btrfs/Makefile

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
77
transaction.o bit-radix.o inode.o file.o tree-defrag.o \
88
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
99
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
10-
ref-cache.o acl.o export.o
11-
10+
ref-cache.o export.o tree-log.o acl.o
1211
else
1312

1413
# Normal Makefile

fs/btrfs/btrfs_inode.h

+8
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct btrfs_inode {
3333
struct extent_io_tree io_failure_tree;
3434
struct mutex csum_mutex;
3535
struct mutex extent_mutex;
36+
struct mutex log_mutex;
3637
struct inode vfs_inode;
3738
struct btrfs_ordered_inode_tree ordered_tree;
3839

@@ -44,10 +45,17 @@ struct btrfs_inode {
4445

4546
struct list_head delalloc_inodes;
4647

48+
/* full 64 bit generation number */
49+
u64 generation;
50+
4751
/*
4852
* transid of the trans_handle that last modified this inode
4953
*/
5054
u64 last_trans;
55+
/*
56+
* transid that last logged this inode
57+
*/
58+
u64 logged_trans;
5159
u64 delalloc_bytes;
5260
u64 disk_i_size;
5361
u32 flags;

fs/btrfs/compat.h

+15
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ static inline struct dentry *d_obtain_alias(struct inode *inode)
2222
}
2323
#endif
2424

25+
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18)
26+
static inline void btrfs_drop_nlink(struct inode *inode)
27+
{
28+
inode->i_nlink--;
29+
}
30+
31+
static inline void btrfs_inc_nlink(struct inode *inode)
32+
{
33+
inode->i_nlink++;
34+
}
35+
#else
36+
# define btrfs_drop_nlink(inode) drop_nlink(inode)
37+
# define btrfs_inc_nlink(inode) inc_nlink(inode)
38+
#endif
39+
2540
/*
2641
* Even if AppArmor isn't enabled, it still has different prototypes.
2742
* Add more distro/version pairs here to declare which has AppArmor applied.

fs/btrfs/ctree.c

+54-19
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void btrfs_free_path(struct btrfs_path *p)
6060
kmem_cache_free(btrfs_path_cachep, p);
6161
}
6262

63-
void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
63+
void noinline btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
6464
{
6565
int i;
6666

@@ -176,7 +176,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
176176
return 0;
177177
}
178178

179-
int __btrfs_cow_block(struct btrfs_trans_handle *trans,
179+
int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans,
180180
struct btrfs_root *root,
181181
struct extent_buffer *buf,
182182
struct extent_buffer *parent, int parent_slot,
@@ -294,7 +294,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
294294
return 0;
295295
}
296296

297-
int btrfs_cow_block(struct btrfs_trans_handle *trans,
297+
int noinline btrfs_cow_block(struct btrfs_trans_handle *trans,
298298
struct btrfs_root *root, struct extent_buffer *buf,
299299
struct extent_buffer *parent, int parent_slot,
300300
struct extent_buffer **cow_ret, u64 prealloc_dest)
@@ -677,9 +677,10 @@ static int noinline check_block(struct btrfs_root *root,
677677
*
678678
* slot may point to max if the key is bigger than all of the keys
679679
*/
680-
static int generic_bin_search(struct extent_buffer *eb, unsigned long p,
681-
int item_size, struct btrfs_key *key,
682-
int max, int *slot)
680+
static noinline int generic_bin_search(struct extent_buffer *eb,
681+
unsigned long p,
682+
int item_size, struct btrfs_key *key,
683+
int max, int *slot)
683684
{
684685
int low = 0;
685686
int high = max;
@@ -765,7 +766,7 @@ static int bin_search(struct extent_buffer *eb, struct btrfs_key *key,
765766
return -1;
766767
}
767768

768-
static struct extent_buffer *read_node_slot(struct btrfs_root *root,
769+
static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root,
769770
struct extent_buffer *parent, int slot)
770771
{
771772
int level = btrfs_header_level(parent);
@@ -781,7 +782,7 @@ static struct extent_buffer *read_node_slot(struct btrfs_root *root,
781782
btrfs_node_ptr_generation(parent, slot));
782783
}
783784

784-
static int balance_level(struct btrfs_trans_handle *trans,
785+
static noinline int balance_level(struct btrfs_trans_handle *trans,
785786
struct btrfs_root *root,
786787
struct btrfs_path *path, int level)
787788
{
@@ -1128,8 +1129,9 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans,
11281129
/*
11291130
* readahead one full node of leaves
11301131
*/
1131-
static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
1132-
int level, int slot, u64 objectid)
1132+
static noinline void reada_for_search(struct btrfs_root *root,
1133+
struct btrfs_path *path,
1134+
int level, int slot, u64 objectid)
11331135
{
11341136
struct extent_buffer *node;
11351137
struct btrfs_disk_key disk_key;
@@ -1201,7 +1203,8 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
12011203
}
12021204
}
12031205

1204-
static void unlock_up(struct btrfs_path *path, int level, int lowest_unlock)
1206+
static noinline void unlock_up(struct btrfs_path *path, int level,
1207+
int lowest_unlock)
12051208
{
12061209
int i;
12071210
int skip_level = level;
@@ -1759,8 +1762,9 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
17591762
*
17601763
* returns 0 on success and < 0 on failure
17611764
*/
1762-
static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
1763-
*root, struct btrfs_path *path, int level)
1765+
static noinline int split_node(struct btrfs_trans_handle *trans,
1766+
struct btrfs_root *root,
1767+
struct btrfs_path *path, int level)
17641768
{
17651769
u64 root_gen;
17661770
struct extent_buffer *c;
@@ -1874,7 +1878,8 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr)
18741878
* the start of the leaf data. IOW, how much room
18751879
* the leaf has left for both items and data
18761880
*/
1877-
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf)
1881+
int noinline btrfs_leaf_free_space(struct btrfs_root *root,
1882+
struct extent_buffer *leaf)
18781883
{
18791884
int nritems = btrfs_header_nritems(leaf);
18801885
int ret;
@@ -2283,9 +2288,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
22832288
*
22842289
* returns 0 if all went well and < 0 on failure.
22852290
*/
2286-
static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
2287-
*root, struct btrfs_key *ins_key,
2288-
struct btrfs_path *path, int data_size, int extend)
2291+
static noinline int split_leaf(struct btrfs_trans_handle *trans,
2292+
struct btrfs_root *root,
2293+
struct btrfs_key *ins_key,
2294+
struct btrfs_path *path, int data_size,
2295+
int extend)
22892296
{
22902297
u64 root_gen;
22912298
struct extent_buffer *l;
@@ -3079,6 +3086,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
30793086
* was nothing in the tree that matched the search criteria.
30803087
*/
30813088
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
3089+
struct btrfs_key *max_key,
30823090
struct btrfs_path *path, int cache_only,
30833091
u64 min_trans)
30843092
{
@@ -3093,6 +3101,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
30933101
again:
30943102
cur = btrfs_lock_root_node(root);
30953103
level = btrfs_header_level(cur);
3104+
WARN_ON(path->nodes[level]);
30963105
path->nodes[level] = cur;
30973106
path->locks[level] = 1;
30983107

@@ -3107,6 +3116,8 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
31073116

31083117
/* at level = 0, we're done, setup the path and exit */
31093118
if (level == 0) {
3119+
if (slot >= nritems)
3120+
goto find_next_key;
31103121
ret = 0;
31113122
path->slots[level] = slot;
31123123
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,
31233134
u64 blockptr;
31243135
u64 gen;
31253136
struct extent_buffer *tmp;
3137+
struct btrfs_disk_key disk_key;
3138+
31263139
blockptr = btrfs_node_blockptr(cur, slot);
31273140
gen = btrfs_node_ptr_generation(cur, slot);
31283141
if (gen < min_trans) {
@@ -3132,6 +3145,14 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
31323145
if (!cache_only)
31333146
break;
31343147

3148+
if (max_key) {
3149+
btrfs_node_key(cur, &disk_key, slot);
3150+
if (comp_keys(&disk_key, max_key) >= 0) {
3151+
ret = 1;
3152+
goto out;
3153+
}
3154+
}
3155+
31353156
tmp = btrfs_find_tree_block(root, blockptr,
31363157
btrfs_level_size(root, level - 1));
31373158

@@ -3143,14 +3164,16 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
31433164
free_extent_buffer(tmp);
31443165
slot++;
31453166
}
3167+
find_next_key:
31463168
/*
31473169
* we didn't find a candidate key in this node, walk forward
31483170
* and find another one
31493171
*/
31503172
if (slot >= nritems) {
3151-
ret = btrfs_find_next_key(root, path, min_key, level,
3173+
path->slots[level] = slot;
3174+
sret = btrfs_find_next_key(root, path, min_key, level,
31523175
cache_only, min_trans);
3153-
if (ret == 0) {
3176+
if (sret == 0) {
31543177
btrfs_release_path(root, path);
31553178
goto again;
31563179
} else {
@@ -3351,6 +3374,7 @@ int btrfs_previous_item(struct btrfs_root *root,
33513374
{
33523375
struct btrfs_key found_key;
33533376
struct extent_buffer *leaf;
3377+
u32 nritems;
33543378
int ret;
33553379

33563380
while(1) {
@@ -3362,9 +3386,20 @@ int btrfs_previous_item(struct btrfs_root *root,
33623386
path->slots[0]--;
33633387
}
33643388
leaf = path->nodes[0];
3389+
nritems = btrfs_header_nritems(leaf);
3390+
if (nritems == 0)
3391+
return 1;
3392+
if (path->slots[0] == nritems)
3393+
path->slots[0]--;
3394+
33653395
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
33663396
if (found_key.type == type)
33673397
return 0;
3398+
if (found_key.objectid < min_objectid)
3399+
break;
3400+
if (found_key.objectid == min_objectid &&
3401+
found_key.type < type)
3402+
break;
33683403
}
33693404
return 1;
33703405
}

0 commit comments

Comments
 (0)