aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-04-20 13:16:02 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-04-20 13:16:02 -0400
commite66f709b157ee8557166c14b67c01bae978ac32e (patch)
tree69a0c17aaffb173095e105a4680bedbefcb13c84 /fs/btrfs
parent8fd17795b2261ecb1bad2a6df09ef14c4957a3fb (diff)
Btrfs: write barriers on commit, balance level before split
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c119
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c12
3 files changed, 131 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 4efcd1bd63e5..744fd728e5d9 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -151,6 +151,11 @@ static int check_node(struct btrfs_root *root, struct btrfs_path *path,
151 for (i = 0; nritems > 1 && i < nritems - 2; i++) { 151 for (i = 0; nritems > 1 && i < nritems - 2; i++) {
152 struct btrfs_key cpukey; 152 struct btrfs_key cpukey;
153 btrfs_disk_key_to_cpu(&cpukey, &node->ptrs[i + 1].key); 153 btrfs_disk_key_to_cpu(&cpukey, &node->ptrs[i + 1].key);
154if (comp_keys(&node->ptrs[i].key, &cpukey) >= 0) {
155 struct btrfs_key bad;
156 btrfs_disk_key_to_cpu(&bad, &node->ptrs[i].key);
157printk("check_node level %d i is %d bad comp %Lu %u %Lu, %Lu %u %Lu\n",level, i, bad.objectid, bad.flags, bad.offset, cpukey.objectid, cpukey.flags, cpukey.offset);
158}
154 BUG_ON(comp_keys(&node->ptrs[i].key, &cpukey) >= 0); 159 BUG_ON(comp_keys(&node->ptrs[i].key, &cpukey) >= 0);
155 } 160 }
156 return 0; 161 return 0;
@@ -448,6 +453,111 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
448 return ret; 453 return ret;
449} 454}
450 455
456/* returns zero if the push worked, non-zero otherwise */
457static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
458 struct btrfs_root *root,
459 struct btrfs_path *path, int level)
460{
461 struct buffer_head *right_buf;
462 struct buffer_head *mid_buf;
463 struct buffer_head *left_buf;
464 struct buffer_head *parent_buf = NULL;
465 struct btrfs_node *right = NULL;
466 struct btrfs_node *mid;
467 struct btrfs_node *left = NULL;
468 struct btrfs_node *parent = NULL;
469 int ret = 0;
470 int wret;
471 int pslot;
472 int orig_slot = path->slots[level];
473 u64 orig_ptr;
474
475 if (level == 0)
476 return 1;
477
478 mid_buf = path->nodes[level];
479 mid = btrfs_buffer_node(mid_buf);
480 orig_ptr = btrfs_node_blockptr(mid, orig_slot);
481
482 if (level < BTRFS_MAX_LEVEL - 1)
483 parent_buf = path->nodes[level + 1];
484 pslot = path->slots[level + 1];
485
486 if (!parent_buf)
487 return 1;
488 parent = btrfs_buffer_node(parent_buf);
489
490 left_buf = read_node_slot(root, parent_buf, pslot - 1);
491
492 /* first, try to make some room in the middle buffer */
493 if (left_buf) {
494 u32 left_nr;
495 btrfs_cow_block(trans, root, left_buf, parent_buf, pslot - 1,
496 &left_buf);
497 left = btrfs_buffer_node(left_buf);
498 left_nr = btrfs_header_nritems(&left->header);
499 wret = push_node_left(trans, root, left_buf, mid_buf);
500 if (wret < 0)
501 ret = wret;
502 if (wret == 0) {
503 orig_slot += left_nr;
504 btrfs_memcpy(root, parent,
505 &parent->ptrs[pslot].key,
506 &mid->ptrs[0].key,
507 sizeof(struct btrfs_disk_key));
508 btrfs_mark_buffer_dirty(parent_buf);
509 if (btrfs_header_nritems(&left->header) > orig_slot) {
510 path->nodes[level] = left_buf;
511 path->slots[level + 1] -= 1;
512 path->slots[level] = orig_slot;
513 btrfs_block_release(root, mid_buf);
514 } else {
515 orig_slot -=
516 btrfs_header_nritems(&left->header);
517 path->slots[level] = orig_slot;
518 btrfs_block_release(root, left_buf);
519 }
520 check_node(root, path, level);
521 return 0;
522 }
523 btrfs_block_release(root, left_buf);
524 }
525 right_buf = read_node_slot(root, parent_buf, pslot + 1);
526
527 /*
528 * then try to empty the right most buffer into the middle
529 */
530 if (right_buf) {
531 btrfs_cow_block(trans, root, right_buf, parent_buf, pslot + 1,
532 &right_buf);
533 right = btrfs_buffer_node(right_buf);
534 wret = balance_node_right(trans, root, right_buf, mid_buf);
535 if (wret < 0)
536 ret = wret;
537 if (wret == 0) {
538 btrfs_memcpy(root, parent,
539 &parent->ptrs[pslot + 1].key,
540 &right->ptrs[0].key,
541 sizeof(struct btrfs_disk_key));
542 btrfs_mark_buffer_dirty(parent_buf);
543 if (btrfs_header_nritems(&mid->header) <= orig_slot) {
544 path->nodes[level] = right_buf;
545 path->slots[level + 1] += 1;
546 path->slots[level] = orig_slot -
547 btrfs_header_nritems(&mid->header);
548 btrfs_block_release(root, mid_buf);
549 } else {
550 btrfs_block_release(root, right_buf);
551 }
552 check_node(root, path, level);
553 return 0;
554 }
555 btrfs_block_release(root, right_buf);
556 }
557 check_node(root, path, level);
558 return 1;
559}
560
451/* 561/*
452 * look for key in the tree. path is filled in with nodes along the way 562 * look for key in the tree. path is filled in with nodes along the way
453 * if key is found, we return zero and you can find the item in the leaf 563 * if key is found, we return zero and you can find the item in the leaf
@@ -774,7 +884,16 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
774 ret = insert_new_root(trans, root, path, level + 1); 884 ret = insert_new_root(trans, root, path, level + 1);
775 if (ret) 885 if (ret)
776 return ret; 886 return ret;
887 } else {
888 ret = push_nodes_for_insert(trans, root, path, level);
889 t = path->nodes[level];
890 c = btrfs_buffer_node(t);
891 if (!ret &&
892 btrfs_header_nritems(&c->header) <
893 BTRFS_NODEPTRS_PER_BLOCK(root) - 1)
894 return 0;
777 } 895 }
896
778 c_nritems = btrfs_header_nritems(&c->header); 897 c_nritems = btrfs_header_nritems(&c->header);
779 split_buffer = btrfs_alloc_free_block(trans, root); 898 split_buffer = btrfs_alloc_free_block(trans, root);
780 split = btrfs_buffer_node(split_buffer); 899 split = btrfs_buffer_node(split_buffer);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 047a84762d93..681b23933d9b 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -259,6 +259,7 @@ struct btrfs_fs_info {
259 struct list_head trans_list; 259 struct list_head trans_list;
260 struct crypto_hash *hash_tfm; 260 struct crypto_hash *hash_tfm;
261 spinlock_t hash_lock; 261 spinlock_t hash_lock;
262 int do_barriers;
262 struct kobject kobj; 263 struct kobject kobj;
263}; 264};
264 265
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index b666c3571aee..13046295bf7a 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -540,6 +540,7 @@ struct btrfs_root *open_ctree(struct super_block *sb)
540 fs_info->btree_inode->i_nlink = 1; 540 fs_info->btree_inode->i_nlink = 1;
541 fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; 541 fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size;
542 fs_info->btree_inode->i_mapping->a_ops = &btree_aops; 542 fs_info->btree_inode->i_mapping->a_ops = &btree_aops;
543 fs_info->do_barriers = 1;
543 BTRFS_I(fs_info->btree_inode)->root = tree_root; 544 BTRFS_I(fs_info->btree_inode)->root = tree_root;
544 memset(&BTRFS_I(fs_info->btree_inode)->location, 0, 545 memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
545 sizeof(struct btrfs_key)); 546 sizeof(struct btrfs_key));
@@ -622,6 +623,7 @@ struct btrfs_root *open_ctree(struct super_block *sb)
622int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root 623int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
623 *root) 624 *root)
624{ 625{
626 int ret;
625 struct buffer_head *bh = root->fs_info->sb_buffer; 627 struct buffer_head *bh = root->fs_info->sb_buffer;
626 628
627 btrfs_set_super_root(root->fs_info->disk_super, 629 btrfs_set_super_root(root->fs_info->disk_super,
@@ -632,7 +634,15 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
632 csum_tree_block(root, bh, 0); 634 csum_tree_block(root, bh, 0);
633 bh->b_end_io = end_buffer_write_sync; 635 bh->b_end_io = end_buffer_write_sync;
634 get_bh(bh); 636 get_bh(bh);
635 submit_bh(WRITE, bh); 637 if (root->fs_info->do_barriers)
638 ret = submit_bh(WRITE_BARRIER, bh);
639 else
640 ret = submit_bh(WRITE, bh);
641 if (ret == -EOPNOTSUPP) {
642 set_buffer_uptodate(bh);
643 root->fs_info->do_barriers = 0;
644 ret = submit_bh(WRITE, bh);
645 }
636 wait_on_buffer(bh); 646 wait_on_buffer(bh);
637 if (!buffer_uptodate(bh)) { 647 if (!buffer_uptodate(bh)) {
638 WARN_ON(1); 648 WARN_ON(1);