aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-07-01 16:18:19 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 07:57:17 -0400
commitc8cc6341653721b54760480b0d0d9b5f09b46741 (patch)
tree210311dd6ebe33d94955eb7a0a1ad8408ec5023b /fs/btrfs/ctree.c
parentd8dfad3876e4386666b759da3c833d62fb8b2267 (diff)
Btrfs: stop using GFP_ATOMIC for the tree mod log allocations
Previously we held the tree mod lock when adding stuff because we use it to check and see if we truly do want to track tree modifications. This is admirable, but GFP_ATOMIC in a critical area that is going to get hit pretty hard and often is not nice. So instead do our basic checks to see if we don't need to track modifications, and if those pass then do our allocation, and then when we go to insert the new modification check if we still care, and if we don't just free up our mod and return. Otherwise we're good to go and we can carry on. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c161
1 files changed, 56 insertions, 105 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index ed504607d8ec..0d5c686f2b98 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -484,8 +484,27 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
484 struct rb_node **new; 484 struct rb_node **new;
485 struct rb_node *parent = NULL; 485 struct rb_node *parent = NULL;
486 struct tree_mod_elem *cur; 486 struct tree_mod_elem *cur;
487 int ret = 0;
488
489 BUG_ON(!tm);
490
491 tree_mod_log_write_lock(fs_info);
492 if (list_empty(&fs_info->tree_mod_seq_list)) {
493 tree_mod_log_write_unlock(fs_info);
494 /*
495 * Ok we no longer care about logging modifications, free up tm
496 * and return 0. Any callers shouldn't be using tm after
497 * calling tree_mod_log_insert, but if they do we can just
498 * change this to return a special error code to let the callers
499 * do their own thing.
500 */
501 kfree(tm);
502 return 0;
503 }
487 504
488 BUG_ON(!tm || !tm->seq); 505 spin_lock(&fs_info->tree_mod_seq_lock);
506 tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info);
507 spin_unlock(&fs_info->tree_mod_seq_lock);
489 508
490 tm_root = &fs_info->tree_mod_log; 509 tm_root = &fs_info->tree_mod_log;
491 new = &tm_root->rb_node; 510 new = &tm_root->rb_node;
@@ -501,14 +520,17 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
501 else if (cur->seq > tm->seq) 520 else if (cur->seq > tm->seq)
502 new = &((*new)->rb_right); 521 new = &((*new)->rb_right);
503 else { 522 else {
523 ret = -EEXIST;
504 kfree(tm); 524 kfree(tm);
505 return -EEXIST; 525 goto out;
506 } 526 }
507 } 527 }
508 528
509 rb_link_node(&tm->node, parent, new); 529 rb_link_node(&tm->node, parent, new);
510 rb_insert_color(&tm->node, tm_root); 530 rb_insert_color(&tm->node, tm_root);
511 return 0; 531out:
532 tree_mod_log_write_unlock(fs_info);
533 return ret;
512} 534}
513 535
514/* 536/*
@@ -524,57 +546,19 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,
524 return 1; 546 return 1;
525 if (eb && btrfs_header_level(eb) == 0) 547 if (eb && btrfs_header_level(eb) == 0)
526 return 1; 548 return 1;
527
528 tree_mod_log_write_lock(fs_info);
529 if (list_empty(&fs_info->tree_mod_seq_list)) {
530 /*
531 * someone emptied the list while we were waiting for the lock.
532 * we must not add to the list when no blocker exists.
533 */
534 tree_mod_log_write_unlock(fs_info);
535 return 1;
536 }
537
538 return 0; 549 return 0;
539} 550}
540 551
541/*
542 * This allocates memory and gets a tree modification sequence number.
543 *
544 * Returns <0 on error.
545 * Returns >0 (the added sequence number) on success.
546 */
547static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags,
548 struct tree_mod_elem **tm_ret)
549{
550 struct tree_mod_elem *tm;
551
552 /*
553 * once we switch from spin locks to something different, we should
554 * honor the flags parameter here.
555 */
556 tm = *tm_ret = kzalloc(sizeof(*tm), GFP_ATOMIC);
557 if (!tm)
558 return -ENOMEM;
559
560 spin_lock(&fs_info->tree_mod_seq_lock);
561 tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info);
562 spin_unlock(&fs_info->tree_mod_seq_lock);
563
564 return tm->seq;
565}
566
567static inline int 552static inline int
568__tree_mod_log_insert_key(struct btrfs_fs_info *fs_info, 553__tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
569 struct extent_buffer *eb, int slot, 554 struct extent_buffer *eb, int slot,
570 enum mod_log_op op, gfp_t flags) 555 enum mod_log_op op, gfp_t flags)
571{ 556{
572 int ret;
573 struct tree_mod_elem *tm; 557 struct tree_mod_elem *tm;
574 558
575 ret = tree_mod_alloc(fs_info, flags, &tm); 559 tm = kzalloc(sizeof(*tm), flags);
576 if (ret < 0) 560 if (!tm)
577 return ret; 561 return -ENOMEM;
578 562
579 tm->index = eb->start >> PAGE_CACHE_SHIFT; 563 tm->index = eb->start >> PAGE_CACHE_SHIFT;
580 if (op != MOD_LOG_KEY_ADD) { 564 if (op != MOD_LOG_KEY_ADD) {
@@ -589,34 +573,14 @@ __tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
589} 573}
590 574
591static noinline int 575static noinline int
592tree_mod_log_insert_key_mask(struct btrfs_fs_info *fs_info, 576tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
593 struct extent_buffer *eb, int slot, 577 struct extent_buffer *eb, int slot,
594 enum mod_log_op op, gfp_t flags) 578 enum mod_log_op op, gfp_t flags)
595{ 579{
596 int ret;
597
598 if (tree_mod_dont_log(fs_info, eb)) 580 if (tree_mod_dont_log(fs_info, eb))
599 return 0; 581 return 0;
600 582
601 ret = __tree_mod_log_insert_key(fs_info, eb, slot, op, flags); 583 return __tree_mod_log_insert_key(fs_info, eb, slot, op, flags);
602
603 tree_mod_log_write_unlock(fs_info);
604 return ret;
605}
606
607static noinline int
608tree_mod_log_insert_key(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
609 int slot, enum mod_log_op op)
610{
611 return tree_mod_log_insert_key_mask(fs_info, eb, slot, op, GFP_NOFS);
612}
613
614static noinline int
615tree_mod_log_insert_key_locked(struct btrfs_fs_info *fs_info,
616 struct extent_buffer *eb, int slot,
617 enum mod_log_op op)
618{
619 return __tree_mod_log_insert_key(fs_info, eb, slot, op, GFP_NOFS);
620} 584}
621 585
622static noinline int 586static noinline int
@@ -637,14 +601,14 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
637 * buffer, i.e. dst_slot < src_slot. 601 * buffer, i.e. dst_slot < src_slot.
638 */ 602 */
639 for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { 603 for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
640 ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot, 604 ret = __tree_mod_log_insert_key(fs_info, eb, i + dst_slot,
641 MOD_LOG_KEY_REMOVE_WHILE_MOVING); 605 MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS);
642 BUG_ON(ret < 0); 606 BUG_ON(ret < 0);
643 } 607 }
644 608
645 ret = tree_mod_alloc(fs_info, flags, &tm); 609 tm = kzalloc(sizeof(*tm), flags);
646 if (ret < 0) 610 if (!tm)
647 goto out; 611 return -ENOMEM;
648 612
649 tm->index = eb->start >> PAGE_CACHE_SHIFT; 613 tm->index = eb->start >> PAGE_CACHE_SHIFT;
650 tm->slot = src_slot; 614 tm->slot = src_slot;
@@ -652,10 +616,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
652 tm->move.nr_items = nr_items; 616 tm->move.nr_items = nr_items;
653 tm->op = MOD_LOG_MOVE_KEYS; 617 tm->op = MOD_LOG_MOVE_KEYS;
654 618
655 ret = __tree_mod_log_insert(fs_info, tm); 619 return __tree_mod_log_insert(fs_info, tm);
656out:
657 tree_mod_log_write_unlock(fs_info);
658 return ret;
659} 620}
660 621
661static inline void 622static inline void
@@ -670,8 +631,8 @@ __tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
670 631
671 nritems = btrfs_header_nritems(eb); 632 nritems = btrfs_header_nritems(eb);
672 for (i = nritems - 1; i >= 0; i--) { 633 for (i = nritems - 1; i >= 0; i--) {
673 ret = tree_mod_log_insert_key_locked(fs_info, eb, i, 634 ret = __tree_mod_log_insert_key(fs_info, eb, i,
674 MOD_LOG_KEY_REMOVE_WHILE_FREEING); 635 MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS);
675 BUG_ON(ret < 0); 636 BUG_ON(ret < 0);
676 } 637 }
677} 638}
@@ -683,7 +644,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
683 int log_removal) 644 int log_removal)
684{ 645{
685 struct tree_mod_elem *tm; 646 struct tree_mod_elem *tm;
686 int ret;
687 647
688 if (tree_mod_dont_log(fs_info, NULL)) 648 if (tree_mod_dont_log(fs_info, NULL))
689 return 0; 649 return 0;
@@ -691,9 +651,9 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
691 if (log_removal) 651 if (log_removal)
692 __tree_mod_log_free_eb(fs_info, old_root); 652 __tree_mod_log_free_eb(fs_info, old_root);
693 653
694 ret = tree_mod_alloc(fs_info, flags, &tm); 654 tm = kzalloc(sizeof(*tm), flags);
695 if (ret < 0) 655 if (!tm)
696 goto out; 656 return -ENOMEM;
697 657
698 tm->index = new_root->start >> PAGE_CACHE_SHIFT; 658 tm->index = new_root->start >> PAGE_CACHE_SHIFT;
699 tm->old_root.logical = old_root->start; 659 tm->old_root.logical = old_root->start;
@@ -701,10 +661,7 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
701 tm->generation = btrfs_header_generation(old_root); 661 tm->generation = btrfs_header_generation(old_root);
702 tm->op = MOD_LOG_ROOT_REPLACE; 662 tm->op = MOD_LOG_ROOT_REPLACE;
703 663
704 ret = __tree_mod_log_insert(fs_info, tm); 664 return __tree_mod_log_insert(fs_info, tm);
705out:
706 tree_mod_log_write_unlock(fs_info);
707 return ret;
708} 665}
709 666
710static struct tree_mod_elem * 667static struct tree_mod_elem *
@@ -784,23 +741,20 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
784 if (tree_mod_dont_log(fs_info, NULL)) 741 if (tree_mod_dont_log(fs_info, NULL))
785 return; 742 return;
786 743
787 if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0) { 744 if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0)
788 tree_mod_log_write_unlock(fs_info);
789 return; 745 return;
790 }
791 746
792 for (i = 0; i < nr_items; i++) { 747 for (i = 0; i < nr_items; i++) {
793 ret = tree_mod_log_insert_key_locked(fs_info, src, 748 ret = __tree_mod_log_insert_key(fs_info, src,
794 i + src_offset, 749 i + src_offset,
795 MOD_LOG_KEY_REMOVE); 750 MOD_LOG_KEY_REMOVE, GFP_NOFS);
796 BUG_ON(ret < 0); 751 BUG_ON(ret < 0);
797 ret = tree_mod_log_insert_key_locked(fs_info, dst, 752 ret = __tree_mod_log_insert_key(fs_info, dst,
798 i + dst_offset, 753 i + dst_offset,
799 MOD_LOG_KEY_ADD); 754 MOD_LOG_KEY_ADD,
755 GFP_NOFS);
800 BUG_ON(ret < 0); 756 BUG_ON(ret < 0);
801 } 757 }
802
803 tree_mod_log_write_unlock(fs_info);
804} 758}
805 759
806static inline void 760static inline void
@@ -819,9 +773,9 @@ tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info,
819{ 773{
820 int ret; 774 int ret;
821 775
822 ret = tree_mod_log_insert_key_mask(fs_info, eb, slot, 776 ret = __tree_mod_log_insert_key(fs_info, eb, slot,
823 MOD_LOG_KEY_REPLACE, 777 MOD_LOG_KEY_REPLACE,
824 atomic ? GFP_ATOMIC : GFP_NOFS); 778 atomic ? GFP_ATOMIC : GFP_NOFS);
825 BUG_ON(ret < 0); 779 BUG_ON(ret < 0);
826} 780}
827 781
@@ -830,10 +784,7 @@ tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
830{ 784{
831 if (tree_mod_dont_log(fs_info, eb)) 785 if (tree_mod_dont_log(fs_info, eb))
832 return; 786 return;
833
834 __tree_mod_log_free_eb(fs_info, eb); 787 __tree_mod_log_free_eb(fs_info, eb);
835
836 tree_mod_log_write_unlock(fs_info);
837} 788}
838 789
839static noinline void 790static noinline void
@@ -1083,7 +1034,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
1083 1034
1084 WARN_ON(trans->transid != btrfs_header_generation(parent)); 1035 WARN_ON(trans->transid != btrfs_header_generation(parent));
1085 tree_mod_log_insert_key(root->fs_info, parent, parent_slot, 1036 tree_mod_log_insert_key(root->fs_info, parent, parent_slot,
1086 MOD_LOG_KEY_REPLACE); 1037 MOD_LOG_KEY_REPLACE, GFP_NOFS);
1087 btrfs_set_node_blockptr(parent, parent_slot, 1038 btrfs_set_node_blockptr(parent, parent_slot,
1088 cow->start); 1039 cow->start);
1089 btrfs_set_node_ptr_generation(parent, parent_slot, 1040 btrfs_set_node_ptr_generation(parent, parent_slot,
@@ -3208,7 +3159,7 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
3208 } 3159 }
3209 if (level) { 3160 if (level) {
3210 ret = tree_mod_log_insert_key(root->fs_info, lower, slot, 3161 ret = tree_mod_log_insert_key(root->fs_info, lower, slot,
3211 MOD_LOG_KEY_ADD); 3162 MOD_LOG_KEY_ADD, GFP_NOFS);
3212 BUG_ON(ret < 0); 3163 BUG_ON(ret < 0);
3213 } 3164 }
3214 btrfs_set_node_key(lower, key, slot); 3165 btrfs_set_node_key(lower, key, slot);
@@ -4642,7 +4593,7 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
4642 (nritems - slot - 1)); 4593 (nritems - slot - 1));
4643 } else if (level) { 4594 } else if (level) {
4644 ret = tree_mod_log_insert_key(root->fs_info, parent, slot, 4595 ret = tree_mod_log_insert_key(root->fs_info, parent, slot,
4645 MOD_LOG_KEY_REMOVE); 4596 MOD_LOG_KEY_REMOVE, GFP_NOFS);
4646 BUG_ON(ret < 0); 4597 BUG_ON(ret < 0);
4647 } 4598 }
4648 4599