diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-01-29 15:11:36 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:00 -0400 |
commit | 85e21bac165b4ba1f6f90431ad6fc658ffcbaf3a (patch) | |
tree | 6483417c9e5c4f3434fd9f2e7e117a4dc46b94c6 /fs/btrfs/inode.c | |
parent | 70dec8079d78691e476cc6c7cede40656078ad30 (diff) |
Btrfs: During deletes and truncate, remove many items at once from the tree
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 114 |
1 files changed, 65 insertions, 49 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index bac8722e14e1..0a2fe51c4127 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -692,27 +692,6 @@ fail: | |||
692 | return err; | 692 | return err; |
693 | } | 693 | } |
694 | 694 | ||
695 | static int btrfs_free_inode(struct btrfs_trans_handle *trans, | ||
696 | struct btrfs_root *root, | ||
697 | struct inode *inode) | ||
698 | { | ||
699 | struct btrfs_path *path; | ||
700 | int ret; | ||
701 | |||
702 | clear_inode(inode); | ||
703 | |||
704 | path = btrfs_alloc_path(); | ||
705 | BUG_ON(!path); | ||
706 | ret = btrfs_lookup_inode(trans, root, path, | ||
707 | &BTRFS_I(inode)->location, -1); | ||
708 | if (ret > 0) | ||
709 | ret = -ENOENT; | ||
710 | if (!ret) | ||
711 | ret = btrfs_del_item(trans, root, path); | ||
712 | btrfs_free_path(path); | ||
713 | return ret; | ||
714 | } | ||
715 | |||
716 | /* | 695 | /* |
717 | * this can truncate away extent items, csum items and directory items. | 696 | * this can truncate away extent items, csum items and directory items. |
718 | * It starts at a high offset and removes keys until it can't find | 697 | * It starts at a high offset and removes keys until it can't find |
@@ -723,7 +702,8 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans, | |||
723 | */ | 702 | */ |
724 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | 703 | static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, |
725 | struct btrfs_root *root, | 704 | struct btrfs_root *root, |
726 | struct inode *inode) | 705 | struct inode *inode, |
706 | u32 min_type) | ||
727 | { | 707 | { |
728 | int ret; | 708 | int ret; |
729 | struct btrfs_path *path; | 709 | struct btrfs_path *path; |
@@ -739,6 +719,8 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
739 | u64 root_owner = 0; | 719 | u64 root_owner = 0; |
740 | int found_extent; | 720 | int found_extent; |
741 | int del_item; | 721 | int del_item; |
722 | int pending_del_nr = 0; | ||
723 | int pending_del_slot = 0; | ||
742 | int extent_type = -1; | 724 | int extent_type = -1; |
743 | 725 | ||
744 | btrfs_drop_extent_cache(inode, inode->i_size, (u64)-1); | 726 | btrfs_drop_extent_cache(inode, inode->i_size, (u64)-1); |
@@ -751,17 +733,19 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
751 | key.offset = (u64)-1; | 733 | key.offset = (u64)-1; |
752 | key.type = (u8)-1; | 734 | key.type = (u8)-1; |
753 | 735 | ||
736 | btrfs_init_path(path); | ||
737 | search_again: | ||
738 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | ||
739 | if (ret < 0) { | ||
740 | goto error; | ||
741 | } | ||
742 | if (ret > 0) { | ||
743 | BUG_ON(path->slots[0] == 0); | ||
744 | path->slots[0]--; | ||
745 | } | ||
746 | |||
754 | while(1) { | 747 | while(1) { |
755 | btrfs_init_path(path); | ||
756 | fi = NULL; | 748 | fi = NULL; |
757 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | ||
758 | if (ret < 0) { | ||
759 | goto error; | ||
760 | } | ||
761 | if (ret > 0) { | ||
762 | BUG_ON(path->slots[0] == 0); | ||
763 | path->slots[0]--; | ||
764 | } | ||
765 | leaf = path->nodes[0]; | 749 | leaf = path->nodes[0]; |
766 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 750 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
767 | found_type = btrfs_key_type(&found_key); | 751 | found_type = btrfs_key_type(&found_key); |
@@ -769,10 +753,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
769 | if (found_key.objectid != inode->i_ino) | 753 | if (found_key.objectid != inode->i_ino) |
770 | break; | 754 | break; |
771 | 755 | ||
772 | if (found_type != BTRFS_CSUM_ITEM_KEY && | 756 | if (found_type < min_type) |
773 | found_type != BTRFS_DIR_ITEM_KEY && | ||
774 | found_type != BTRFS_DIR_INDEX_KEY && | ||
775 | found_type != BTRFS_EXTENT_DATA_KEY) | ||
776 | break; | 757 | break; |
777 | 758 | ||
778 | item_end = found_key.offset; | 759 | item_end = found_key.offset; |
@@ -801,14 +782,17 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
801 | found_type = BTRFS_INODE_ITEM_KEY; | 782 | found_type = BTRFS_INODE_ITEM_KEY; |
802 | } else if (found_type == BTRFS_EXTENT_ITEM_KEY) { | 783 | } else if (found_type == BTRFS_EXTENT_ITEM_KEY) { |
803 | found_type = BTRFS_CSUM_ITEM_KEY; | 784 | found_type = BTRFS_CSUM_ITEM_KEY; |
785 | } else if (found_type == BTRFS_EXTENT_DATA_KEY) { | ||
786 | found_type = BTRFS_XATTR_ITEM_KEY; | ||
787 | } else if (found_type == BTRFS_XATTR_ITEM_KEY) { | ||
788 | found_type = BTRFS_INODE_REF_KEY; | ||
804 | } else if (found_type) { | 789 | } else if (found_type) { |
805 | found_type--; | 790 | found_type--; |
806 | } else { | 791 | } else { |
807 | break; | 792 | break; |
808 | } | 793 | } |
809 | btrfs_set_key_type(&key, found_type); | 794 | btrfs_set_key_type(&key, found_type); |
810 | btrfs_release_path(root, path); | 795 | goto next; |
811 | continue; | ||
812 | } | 796 | } |
813 | if (found_key.offset >= inode->i_size) | 797 | if (found_key.offset >= inode->i_size) |
814 | del_item = 1; | 798 | del_item = 1; |
@@ -860,13 +844,21 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
860 | } | 844 | } |
861 | delete: | 845 | delete: |
862 | if (del_item) { | 846 | if (del_item) { |
863 | ret = btrfs_del_item(trans, root, path); | 847 | if (!pending_del_nr) { |
864 | if (ret) | 848 | /* no pending yet, add ourselves */ |
865 | goto error; | 849 | pending_del_slot = path->slots[0]; |
850 | pending_del_nr = 1; | ||
851 | } else if (pending_del_nr && | ||
852 | path->slots[0] + 1 == pending_del_slot) { | ||
853 | /* hop on the pending chunk */ | ||
854 | pending_del_nr++; | ||
855 | pending_del_slot = path->slots[0]; | ||
856 | } else { | ||
857 | printk("bad pending slot %d pending_del_nr %d pending_del_slot %d\n", path->slots[0], pending_del_nr, pending_del_slot); | ||
858 | } | ||
866 | } else { | 859 | } else { |
867 | break; | 860 | break; |
868 | } | 861 | } |
869 | btrfs_release_path(root, path); | ||
870 | if (found_extent) { | 862 | if (found_extent) { |
871 | ret = btrfs_free_extent(trans, root, extent_start, | 863 | ret = btrfs_free_extent(trans, root, extent_start, |
872 | extent_num_bytes, | 864 | extent_num_bytes, |
@@ -875,9 +867,36 @@ delete: | |||
875 | found_key.offset, 0); | 867 | found_key.offset, 0); |
876 | BUG_ON(ret); | 868 | BUG_ON(ret); |
877 | } | 869 | } |
870 | next: | ||
871 | if (path->slots[0] == 0) { | ||
872 | if (pending_del_nr) | ||
873 | goto del_pending; | ||
874 | btrfs_release_path(root, path); | ||
875 | goto search_again; | ||
876 | } | ||
877 | |||
878 | path->slots[0]--; | ||
879 | if (pending_del_nr && | ||
880 | path->slots[0] + 1 != pending_del_slot) { | ||
881 | struct btrfs_key debug; | ||
882 | del_pending: | ||
883 | btrfs_item_key_to_cpu(path->nodes[0], &debug, | ||
884 | pending_del_slot); | ||
885 | ret = btrfs_del_items(trans, root, path, | ||
886 | pending_del_slot, | ||
887 | pending_del_nr); | ||
888 | BUG_ON(ret); | ||
889 | pending_del_nr = 0; | ||
890 | btrfs_release_path(root, path); | ||
891 | goto search_again; | ||
892 | } | ||
878 | } | 893 | } |
879 | ret = 0; | 894 | ret = 0; |
880 | error: | 895 | error: |
896 | if (pending_del_nr) { | ||
897 | ret = btrfs_del_items(trans, root, path, pending_del_slot, | ||
898 | pending_del_nr); | ||
899 | } | ||
881 | btrfs_release_path(root, path); | 900 | btrfs_release_path(root, path); |
882 | btrfs_free_path(path); | 901 | btrfs_free_path(path); |
883 | inode->i_sb->s_dirt = 1; | 902 | inode->i_sb->s_dirt = 1; |
@@ -1067,16 +1086,12 @@ void btrfs_delete_inode(struct inode *inode) | |||
1067 | trans = btrfs_start_transaction(root, 1); | 1086 | trans = btrfs_start_transaction(root, 1); |
1068 | 1087 | ||
1069 | btrfs_set_trans_block_group(trans, inode); | 1088 | btrfs_set_trans_block_group(trans, inode); |
1070 | ret = btrfs_truncate_in_trans(trans, root, inode); | 1089 | ret = btrfs_truncate_in_trans(trans, root, inode, 0); |
1071 | if (ret) | ||
1072 | goto no_delete_lock; | ||
1073 | ret = btrfs_delete_xattrs(trans, root, inode); | ||
1074 | if (ret) | ||
1075 | goto no_delete_lock; | ||
1076 | ret = btrfs_free_inode(trans, root, inode); | ||
1077 | if (ret) | 1090 | if (ret) |
1078 | goto no_delete_lock; | 1091 | goto no_delete_lock; |
1092 | |||
1079 | nr = trans->blocks_used; | 1093 | nr = trans->blocks_used; |
1094 | clear_inode(inode); | ||
1080 | 1095 | ||
1081 | btrfs_end_transaction(trans, root); | 1096 | btrfs_end_transaction(trans, root); |
1082 | mutex_unlock(&root->fs_info->fs_mutex); | 1097 | mutex_unlock(&root->fs_info->fs_mutex); |
@@ -2190,7 +2205,8 @@ static void btrfs_truncate(struct inode *inode) | |||
2190 | btrfs_set_trans_block_group(trans, inode); | 2205 | btrfs_set_trans_block_group(trans, inode); |
2191 | 2206 | ||
2192 | /* FIXME, add redo link to tree so we don't leak on crash */ | 2207 | /* FIXME, add redo link to tree so we don't leak on crash */ |
2193 | ret = btrfs_truncate_in_trans(trans, root, inode); | 2208 | ret = btrfs_truncate_in_trans(trans, root, inode, |
2209 | BTRFS_EXTENT_DATA_KEY); | ||
2194 | btrfs_update_inode(trans, root, inode); | 2210 | btrfs_update_inode(trans, root, inode); |
2195 | nr = trans->blocks_used; | 2211 | nr = trans->blocks_used; |
2196 | 2212 | ||