diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-05-24 03:06:26 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-05-24 03:06:26 -0400 |
commit | b73077eb03f510a84b102fb97640e595a958403c (patch) | |
tree | 8b639000418e2756bf6baece4e00e07d2534bccc /fs/btrfs/tree-log.c | |
parent | 28350e330cfab46b60a1dbf763b678d859f9f3d9 (diff) | |
parent | 9d2e173644bb5c42ff1b280fbdda3f195a7cf1f7 (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r-- | fs/btrfs/tree-log.c | 92 |
1 files changed, 61 insertions, 31 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 054744ac5719..c50271ad3157 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -338,6 +338,12 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, | |||
338 | } | 338 | } |
339 | dst_copy = kmalloc(item_size, GFP_NOFS); | 339 | dst_copy = kmalloc(item_size, GFP_NOFS); |
340 | src_copy = kmalloc(item_size, GFP_NOFS); | 340 | src_copy = kmalloc(item_size, GFP_NOFS); |
341 | if (!dst_copy || !src_copy) { | ||
342 | btrfs_release_path(root, path); | ||
343 | kfree(dst_copy); | ||
344 | kfree(src_copy); | ||
345 | return -ENOMEM; | ||
346 | } | ||
341 | 347 | ||
342 | read_extent_buffer(eb, src_copy, src_ptr, item_size); | 348 | read_extent_buffer(eb, src_copy, src_ptr, item_size); |
343 | 349 | ||
@@ -665,6 +671,9 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, | |||
665 | btrfs_dir_item_key_to_cpu(leaf, di, &location); | 671 | btrfs_dir_item_key_to_cpu(leaf, di, &location); |
666 | name_len = btrfs_dir_name_len(leaf, di); | 672 | name_len = btrfs_dir_name_len(leaf, di); |
667 | name = kmalloc(name_len, GFP_NOFS); | 673 | name = kmalloc(name_len, GFP_NOFS); |
674 | if (!name) | ||
675 | return -ENOMEM; | ||
676 | |||
668 | read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len); | 677 | read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len); |
669 | btrfs_release_path(root, path); | 678 | btrfs_release_path(root, path); |
670 | 679 | ||
@@ -744,6 +753,9 @@ static noinline int backref_in_log(struct btrfs_root *log, | |||
744 | int match = 0; | 753 | int match = 0; |
745 | 754 | ||
746 | path = btrfs_alloc_path(); | 755 | path = btrfs_alloc_path(); |
756 | if (!path) | ||
757 | return -ENOMEM; | ||
758 | |||
747 | ret = btrfs_search_slot(NULL, log, key, path, 0, 0); | 759 | ret = btrfs_search_slot(NULL, log, key, path, 0, 0); |
748 | if (ret != 0) | 760 | if (ret != 0) |
749 | goto out; | 761 | goto out; |
@@ -787,12 +799,12 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, | |||
787 | struct inode *dir; | 799 | struct inode *dir; |
788 | int ret; | 800 | int ret; |
789 | struct btrfs_inode_ref *ref; | 801 | struct btrfs_inode_ref *ref; |
790 | struct btrfs_dir_item *di; | ||
791 | struct inode *inode; | 802 | struct inode *inode; |
792 | char *name; | 803 | char *name; |
793 | int namelen; | 804 | int namelen; |
794 | unsigned long ref_ptr; | 805 | unsigned long ref_ptr; |
795 | unsigned long ref_end; | 806 | unsigned long ref_end; |
807 | int search_done = 0; | ||
796 | 808 | ||
797 | /* | 809 | /* |
798 | * it is possible that we didn't log all the parent directories | 810 | * it is possible that we didn't log all the parent directories |
@@ -833,7 +845,10 @@ again: | |||
833 | * existing back reference, and we don't want to create | 845 | * existing back reference, and we don't want to create |
834 | * dangling pointers in the directory. | 846 | * dangling pointers in the directory. |
835 | */ | 847 | */ |
836 | conflict_again: | 848 | |
849 | if (search_done) | ||
850 | goto insert; | ||
851 | |||
837 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); | 852 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); |
838 | if (ret == 0) { | 853 | if (ret == 0) { |
839 | char *victim_name; | 854 | char *victim_name; |
@@ -874,37 +889,21 @@ conflict_again: | |||
874 | ret = btrfs_unlink_inode(trans, root, dir, | 889 | ret = btrfs_unlink_inode(trans, root, dir, |
875 | inode, victim_name, | 890 | inode, victim_name, |
876 | victim_name_len); | 891 | victim_name_len); |
877 | kfree(victim_name); | ||
878 | btrfs_release_path(root, path); | ||
879 | goto conflict_again; | ||
880 | } | 892 | } |
881 | kfree(victim_name); | 893 | kfree(victim_name); |
882 | ptr = (unsigned long)(victim_ref + 1) + victim_name_len; | 894 | ptr = (unsigned long)(victim_ref + 1) + victim_name_len; |
883 | } | 895 | } |
884 | BUG_ON(ret); | 896 | BUG_ON(ret); |
885 | } | ||
886 | btrfs_release_path(root, path); | ||
887 | 897 | ||
888 | /* look for a conflicting sequence number */ | 898 | /* |
889 | di = btrfs_lookup_dir_index_item(trans, root, path, dir->i_ino, | 899 | * NOTE: we have searched root tree and checked the |
890 | btrfs_inode_ref_index(eb, ref), | 900 | * coresponding ref, it does not need to check again. |
891 | name, namelen, 0); | 901 | */ |
892 | if (di && !IS_ERR(di)) { | 902 | search_done = 1; |
893 | ret = drop_one_dir_item(trans, root, path, dir, di); | ||
894 | BUG_ON(ret); | ||
895 | } | ||
896 | btrfs_release_path(root, path); | ||
897 | |||
898 | |||
899 | /* look for a conflicting name */ | ||
900 | di = btrfs_lookup_dir_item(trans, root, path, dir->i_ino, | ||
901 | name, namelen, 0); | ||
902 | if (di && !IS_ERR(di)) { | ||
903 | ret = drop_one_dir_item(trans, root, path, dir, di); | ||
904 | BUG_ON(ret); | ||
905 | } | 903 | } |
906 | btrfs_release_path(root, path); | 904 | btrfs_release_path(root, path); |
907 | 905 | ||
906 | insert: | ||
908 | /* insert our name */ | 907 | /* insert our name */ |
909 | ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, | 908 | ret = btrfs_add_link(trans, dir, inode, name, namelen, 0, |
910 | btrfs_inode_ref_index(eb, ref)); | 909 | btrfs_inode_ref_index(eb, ref)); |
@@ -967,6 +966,8 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans, | |||
967 | key.offset = (u64)-1; | 966 | key.offset = (u64)-1; |
968 | 967 | ||
969 | path = btrfs_alloc_path(); | 968 | path = btrfs_alloc_path(); |
969 | if (!path) | ||
970 | return -ENOMEM; | ||
970 | 971 | ||
971 | while (1) { | 972 | while (1) { |
972 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 973 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
@@ -1178,6 +1179,9 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans, | |||
1178 | 1179 | ||
1179 | name_len = btrfs_dir_name_len(eb, di); | 1180 | name_len = btrfs_dir_name_len(eb, di); |
1180 | name = kmalloc(name_len, GFP_NOFS); | 1181 | name = kmalloc(name_len, GFP_NOFS); |
1182 | if (!name) | ||
1183 | return -ENOMEM; | ||
1184 | |||
1181 | log_type = btrfs_dir_type(eb, di); | 1185 | log_type = btrfs_dir_type(eb, di); |
1182 | read_extent_buffer(eb, name, (unsigned long)(di + 1), | 1186 | read_extent_buffer(eb, name, (unsigned long)(di + 1), |
1183 | name_len); | 1187 | name_len); |
@@ -1269,6 +1273,8 @@ static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans, | |||
1269 | ptr_end = ptr + item_size; | 1273 | ptr_end = ptr + item_size; |
1270 | while (ptr < ptr_end) { | 1274 | while (ptr < ptr_end) { |
1271 | di = (struct btrfs_dir_item *)ptr; | 1275 | di = (struct btrfs_dir_item *)ptr; |
1276 | if (verify_dir_item(root, eb, di)) | ||
1277 | return -EIO; | ||
1272 | name_len = btrfs_dir_name_len(eb, di); | 1278 | name_len = btrfs_dir_name_len(eb, di); |
1273 | ret = replay_one_name(trans, root, path, eb, di, key); | 1279 | ret = replay_one_name(trans, root, path, eb, di, key); |
1274 | BUG_ON(ret); | 1280 | BUG_ON(ret); |
@@ -1395,6 +1401,11 @@ again: | |||
1395 | ptr_end = ptr + item_size; | 1401 | ptr_end = ptr + item_size; |
1396 | while (ptr < ptr_end) { | 1402 | while (ptr < ptr_end) { |
1397 | di = (struct btrfs_dir_item *)ptr; | 1403 | di = (struct btrfs_dir_item *)ptr; |
1404 | if (verify_dir_item(root, eb, di)) { | ||
1405 | ret = -EIO; | ||
1406 | goto out; | ||
1407 | } | ||
1408 | |||
1398 | name_len = btrfs_dir_name_len(eb, di); | 1409 | name_len = btrfs_dir_name_len(eb, di); |
1399 | name = kmalloc(name_len, GFP_NOFS); | 1410 | name = kmalloc(name_len, GFP_NOFS); |
1400 | if (!name) { | 1411 | if (!name) { |
@@ -1692,6 +1703,8 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, | |||
1692 | root_owner = btrfs_header_owner(parent); | 1703 | root_owner = btrfs_header_owner(parent); |
1693 | 1704 | ||
1694 | next = btrfs_find_create_tree_block(root, bytenr, blocksize); | 1705 | next = btrfs_find_create_tree_block(root, bytenr, blocksize); |
1706 | if (!next) | ||
1707 | return -ENOMEM; | ||
1695 | 1708 | ||
1696 | if (*level == 1) { | 1709 | if (*level == 1) { |
1697 | wc->process_func(root, next, wc, ptr_gen); | 1710 | wc->process_func(root, next, wc, ptr_gen); |
@@ -1802,7 +1815,8 @@ static int walk_log_tree(struct btrfs_trans_handle *trans, | |||
1802 | int orig_level; | 1815 | int orig_level; |
1803 | 1816 | ||
1804 | path = btrfs_alloc_path(); | 1817 | path = btrfs_alloc_path(); |
1805 | BUG_ON(!path); | 1818 | if (!path) |
1819 | return -ENOMEM; | ||
1806 | 1820 | ||
1807 | level = btrfs_header_level(log->node); | 1821 | level = btrfs_header_level(log->node); |
1808 | orig_level = level; | 1822 | orig_level = level; |
@@ -2032,6 +2046,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2032 | wait_log_commit(trans, log_root_tree, | 2046 | wait_log_commit(trans, log_root_tree, |
2033 | log_root_tree->log_transid); | 2047 | log_root_tree->log_transid); |
2034 | mutex_unlock(&log_root_tree->log_mutex); | 2048 | mutex_unlock(&log_root_tree->log_mutex); |
2049 | ret = 0; | ||
2035 | goto out; | 2050 | goto out; |
2036 | } | 2051 | } |
2037 | atomic_set(&log_root_tree->log_commit[index2], 1); | 2052 | atomic_set(&log_root_tree->log_commit[index2], 1); |
@@ -2096,7 +2111,7 @@ out: | |||
2096 | smp_mb(); | 2111 | smp_mb(); |
2097 | if (waitqueue_active(&root->log_commit_wait[index1])) | 2112 | if (waitqueue_active(&root->log_commit_wait[index1])) |
2098 | wake_up(&root->log_commit_wait[index1]); | 2113 | wake_up(&root->log_commit_wait[index1]); |
2099 | return 0; | 2114 | return ret; |
2100 | } | 2115 | } |
2101 | 2116 | ||
2102 | static void free_log_tree(struct btrfs_trans_handle *trans, | 2117 | static void free_log_tree(struct btrfs_trans_handle *trans, |
@@ -2194,6 +2209,9 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, | |||
2194 | 2209 | ||
2195 | log = root->log_root; | 2210 | log = root->log_root; |
2196 | path = btrfs_alloc_path(); | 2211 | path = btrfs_alloc_path(); |
2212 | if (!path) | ||
2213 | return -ENOMEM; | ||
2214 | |||
2197 | di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino, | 2215 | di = btrfs_lookup_dir_item(trans, log, path, dir->i_ino, |
2198 | name, name_len, -1); | 2216 | name, name_len, -1); |
2199 | if (IS_ERR(di)) { | 2217 | if (IS_ERR(di)) { |
@@ -2594,6 +2612,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
2594 | 2612 | ||
2595 | ins_data = kmalloc(nr * sizeof(struct btrfs_key) + | 2613 | ins_data = kmalloc(nr * sizeof(struct btrfs_key) + |
2596 | nr * sizeof(u32), GFP_NOFS); | 2614 | nr * sizeof(u32), GFP_NOFS); |
2615 | if (!ins_data) | ||
2616 | return -ENOMEM; | ||
2617 | |||
2597 | ins_sizes = (u32 *)ins_data; | 2618 | ins_sizes = (u32 *)ins_data; |
2598 | ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); | 2619 | ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); |
2599 | 2620 | ||
@@ -2725,7 +2746,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
2725 | log = root->log_root; | 2746 | log = root->log_root; |
2726 | 2747 | ||
2727 | path = btrfs_alloc_path(); | 2748 | path = btrfs_alloc_path(); |
2749 | if (!path) | ||
2750 | return -ENOMEM; | ||
2728 | dst_path = btrfs_alloc_path(); | 2751 | dst_path = btrfs_alloc_path(); |
2752 | if (!dst_path) { | ||
2753 | btrfs_free_path(path); | ||
2754 | return -ENOMEM; | ||
2755 | } | ||
2729 | 2756 | ||
2730 | min_key.objectid = inode->i_ino; | 2757 | min_key.objectid = inode->i_ino; |
2731 | min_key.type = BTRFS_INODE_ITEM_KEY; | 2758 | min_key.type = BTRFS_INODE_ITEM_KEY; |
@@ -3075,16 +3102,20 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) | |||
3075 | .stage = 0, | 3102 | .stage = 0, |
3076 | }; | 3103 | }; |
3077 | 3104 | ||
3078 | fs_info->log_root_recovering = 1; | ||
3079 | path = btrfs_alloc_path(); | 3105 | path = btrfs_alloc_path(); |
3080 | BUG_ON(!path); | 3106 | if (!path) |
3107 | return -ENOMEM; | ||
3108 | |||
3109 | fs_info->log_root_recovering = 1; | ||
3081 | 3110 | ||
3082 | trans = btrfs_start_transaction(fs_info->tree_root, 0); | 3111 | trans = btrfs_start_transaction(fs_info->tree_root, 0); |
3112 | BUG_ON(IS_ERR(trans)); | ||
3083 | 3113 | ||
3084 | wc.trans = trans; | 3114 | wc.trans = trans; |
3085 | wc.pin = 1; | 3115 | wc.pin = 1; |
3086 | 3116 | ||
3087 | walk_log_tree(trans, log_root_tree, &wc); | 3117 | ret = walk_log_tree(trans, log_root_tree, &wc); |
3118 | BUG_ON(ret); | ||
3088 | 3119 | ||
3089 | again: | 3120 | again: |
3090 | key.objectid = BTRFS_TREE_LOG_OBJECTID; | 3121 | key.objectid = BTRFS_TREE_LOG_OBJECTID; |
@@ -3108,8 +3139,7 @@ again: | |||
3108 | 3139 | ||
3109 | log = btrfs_read_fs_root_no_radix(log_root_tree, | 3140 | log = btrfs_read_fs_root_no_radix(log_root_tree, |
3110 | &found_key); | 3141 | &found_key); |
3111 | BUG_ON(!log); | 3142 | BUG_ON(IS_ERR(log)); |
3112 | |||
3113 | 3143 | ||
3114 | tmp_key.objectid = found_key.offset; | 3144 | tmp_key.objectid = found_key.offset; |
3115 | tmp_key.type = BTRFS_ROOT_ITEM_KEY; | 3145 | tmp_key.type = BTRFS_ROOT_ITEM_KEY; |